From 29a5fa6d46b48e1cf6b5d7db30ba7ee1db91fce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Thu, 28 Aug 2025 06:50:17 +0200 Subject: [PATCH 01/31] skip discard flows if not required by process --- dist/activity/Activity.js | 3 + src/activity/Activity.js | 5 + test/feature/skip-discard-feature.js | 297 ++++++++++++++++++ .../event-based-gateway-with-same-target.bpmn | 56 ++-- ...me-target-sequence-flows-with-excl-gw.bpmn | 247 +++++++++++++++ test/resources/loop.bpmn | 112 +++---- 6 files changed, 636 insertions(+), 84 deletions(-) create mode 100644 test/feature/skip-discard-feature.js create mode 100644 test/resources/issue-42-same-target-sequence-flows-with-excl-gw.bpmn diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 8284808a..49df2bbe 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -910,6 +910,9 @@ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlo action, result } = outboundFlow; + if (action === 'discard' && this.environment.settings.skipDiscard) { + return; + } this.broker.publish('run', 'run.outbound.' + action, (0, _messageHelper.cloneContent)(content, { flow: { ...(result && typeof result === 'object' && result), diff --git a/src/activity/Activity.js b/src/activity/Activity.js index 040e113f..f40a5af9 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -885,6 +885,11 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content, discardSequence) { const { id: flowId, action, result } = outboundFlow; + + if (action === 'discard' && this.environment.settings.skipDiscard) { + return; + } + this.broker.publish( 'run', 'run.outbound.' + action, diff --git a/test/feature/skip-discard-feature.js b/test/feature/skip-discard-feature.js new file mode 100644 index 00000000..e7934ae5 --- /dev/null +++ b/test/feature/skip-discard-feature.js @@ -0,0 +1,297 @@ +import * as ck from 'chronokinesis'; +import { Definition } from 'bpmn-elements'; +import JsExtension from '../resources/extensions/JsExtension.js'; +import testHelpers from '../helpers/testHelpers.js'; +import factory from '../helpers/factory.js'; +import CamundaExtension from '../resources/extensions/CamundaExtension.js'; + +Feature('Skip discarding flows if parallel gateway is not used', () => { + after(ck.reset); + + Scenario('A process with task splits', () => { + /** @type {Definition} */ + let definition; + Given('a process matching scenario', async () => { + const source = factory.resource('conditional-flows.bpmn'); + const context = await testHelpers.context(source, { + extensions: { + js: JsExtension, + }, + }); + definition = new Definition(context, { settings: { skipDiscard: true } }); + }); + + const discardedFlows = []; + And('a listener counting discarded flows', () => { + definition.broker.subscribeTmp( + 'event', + 'flow.discard', + (_, msg) => { + discardedFlows.push(msg.content.id); + }, + { noAck: true } + ); + }); + + let end; + When('ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('no flows were discarded', () => { + expect(discardedFlows).to.have.length(0); + }); + + And('only some tasks were taken', () => { + expect(definition.getActivityById('start').counters, 'start').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('task1').counters, 'task1').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('task2').counters, 'task2').to.deep.equal({ taken: 0, discarded: 0 }); + expect(definition.getActivityById('task3').counters, 'task3').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('task4').counters, 'task4').to.deep.equal({ taken: 0, discarded: 0 }); + expect(definition.getActivityById('end').counters, 'end').to.deep.equal({ taken: 1, discarded: 0 }); + }); + }); + + Scenario('A process with loop back', () => { + /** @type {Definition} */ + let definition; + Given('a process matching scenario', async () => { + const source = factory.resource('loop.bpmn'); + const context = await testHelpers.context(source, { + extensions: { + js: JsExtension, + }, + }); + definition = new Definition(context, { settings: { skipDiscard: true }, variables: { input: 0 } }); + }); + + const discardedFlows = []; + And('a listener counting discarded flows', () => { + definition.broker.subscribeTmp( + 'event', + 'flow.discard', + (_, msg) => { + discardedFlows.push(msg.content.id); + }, + { noAck: true } + ); + }); + + let end; + When('ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('no flows were discarded', () => { + expect(discardedFlows).to.have.length(0); + }); + + And('only some tasks were taken', () => { + expect(definition.getActivityById('start').counters, 'start').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('task1').counters, 'task1').to.deep.equal({ taken: 3, discarded: 0 }); + expect(definition.getActivityById('decision').counters, 'decision').to.deep.equal({ taken: 3, discarded: 0 }); + expect(definition.getActivityById('task2').counters, 'task2').to.deep.equal({ taken: 2, discarded: 0 }); + expect(definition.getActivityById('end').counters, 'end').to.deep.equal({ taken: 1, discarded: 0 }); + }); + }); + + Scenario('A process with event based gateway succeeded by signal and timer', () => { + /** @type {Definition} */ + let definition; + Given('a process matching scenario', async () => { + const source = factory.resource('event-based-gateway-with-same-target.bpmn'); + const context = await testHelpers.context(source, { + extensions: { + js: JsExtension, + }, + }); + definition = new Definition(context, { settings: { skipDiscard: true }, variables: { input: 0 } }); + }); + + const discardedFlows = []; + And('a listener counting discarded flows', () => { + definition.broker.subscribeTmp( + 'event', + 'flow.discard', + (_, msg) => { + discardedFlows.push(msg.content.id); + }, + { noAck: true } + ); + }); + + let end; + let wait; + When('ran', () => { + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + definition.run(); + }); + + let signalEvent; + Then('run is awaiting signal', async () => { + signalEvent = await wait; + }); + + When('run is signalled', () => { + definition.signal(signalEvent.content.signal); + }); + + Then('run completes', () => { + return end; + }); + + And('no flows were discarded', () => { + expect(discardedFlows).to.have.length(0); + }); + + And('only some tasks were taken', () => { + expect(definition.getActivityById('start').counters, 'start').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('gateway').counters, 'gateway').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('signalEvent').counters, 'signalEvent').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('task1').counters, 'task1').to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('timerEvent').counters, 'end').to.deep.equal({ taken: 0, discarded: 1 }); + expect(definition.getActivityById('end').counters, 'end').to.deep.equal({ taken: 1, discarded: 0 }); + }); + }); + + ['engine-issue-73.bpmn', 'engine-issue-73_2.bpmn', 'issue-42-same-target-sequence-flows-with-excl-gw.bpmn'].forEach((source) => { + Scenario(`${source} should complete as expected`, () => { + /** @type {Definition} */ + let definition; + Given('a process matching scenario', async () => { + const context = await testHelpers.context(factory.resource(source), { + extensions: { + camunda: CamundaExtension, + }, + }); + definition = new Definition(context, { + settings: { skipDiscard: true }, + variables: { input: 0 }, + services: { + takeFlow() { + return true; + }, + }, + }); + }); + + And('a listener for wait immediately signalling or discarding if touched more than trice', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.wait', + (_, msg) => { + const elm = definition.getActivityById(msg.content.id); + if (elm.counters.taken > 2) { + elm.discard(); + } else { + definition.signal(msg.content.reference ?? { id: msg.content.id, executionId: msg.content.executionId }); + } + }, + { noAck: true } + ); + }); + + const discardedFlows = []; + And('a listener counting discarded flows', () => { + definition.broker.subscribeTmp( + 'event', + 'flow.discard', + (_, msg) => { + discardedFlows.push(msg.content.id); + }, + { noAck: true } + ); + }); + + let end; + When('ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('with no discarded flows', () => { + expect(discardedFlows).to.have.length(0); + }); + }); + }); + + ['issue-42-same-target-sequence-flows.bpmn'].forEach((source) => { + Scenario(`${source} with parallel join gateways should complete as expected`, () => { + /** @type {Definition} */ + let definition; + Given('a process matching scenario', async () => { + const context = await testHelpers.context(factory.resource(source), { + extensions: { + camunda: CamundaExtension, + }, + }); + definition = new Definition(context, { + settings: { skipDiscard: true }, + variables: { input: 0 }, + services: { + takeFlow() { + return true; + }, + }, + }); + }); + + And('a listener for wait immediately signalling or discarding if touched more than trice', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.wait', + (_, msg) => { + const elm = definition.getActivityById(msg.content.id); + if (elm.counters.taken > 2) { + elm.discard(); + } else { + definition.signal(msg.content.reference ?? { id: msg.content.id, executionId: msg.content.executionId }); + } + }, + { noAck: true } + ); + }); + + const discardedFlows = []; + And('a listener counting discarded flows', () => { + definition.broker.subscribeTmp( + 'event', + 'flow.discard', + (_, msg) => { + discardedFlows.push(msg.content.id); + }, + { noAck: true } + ); + }); + + let end; + When('ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('with no discarded flows', () => { + expect(discardedFlows).to.have.length(0); + }); + }); + }); +}); diff --git a/test/resources/event-based-gateway-with-same-target.bpmn b/test/resources/event-based-gateway-with-same-target.bpmn index 05817cd8..e32b1855 100644 --- a/test/resources/event-based-gateway-with-same-target.bpmn +++ b/test/resources/event-based-gateway-with-same-target.bpmn @@ -1,12 +1,12 @@ - + - toGateway + to-gateway - + - toGateway + to-gateway from-gateway-2 from-gateway-1 to-timerEvent @@ -14,52 +14,56 @@ from-gateway-2 from-gateway-1 - SequenceFlow_0mgq2p1 + from-signalEvent - - SequenceFlow_0mgq2p1 - Flow_1ufc3pc - SequenceFlow_1b15xe6 + + from-signalEvent + from-timerEvent + to-end - - + + - SequenceFlow_1b15xe6 + to-end to-timerEvent - Flow_1ufc3pc + from-timerEvent PT1H - + + + + + + + - + - - - - - - + + + + @@ -70,24 +74,20 @@ - + - + - - - - - + diff --git a/test/resources/issue-42-same-target-sequence-flows-with-excl-gw.bpmn b/test/resources/issue-42-same-target-sequence-flows-with-excl-gw.bpmn new file mode 100644 index 00000000..4610ef32 --- /dev/null +++ b/test/resources/issue-42-same-target-sequence-flows-with-excl-gw.bpmn @@ -0,0 +1,247 @@ + + + + + to-task1 + + + to-task1 + backto-task1 + to-task2-2 + to-task2-1 + to-task2-3 + to-task3 + + + + ${environment.services.takeFlow(2,environment.variables)} + + + to-task2-2 + to-task2-1 + to-task2-3 + from-task2 + + + + ${environment.services.takeFlow(1,environment.variables)} + + + ${environment.services.takeFlow(2,environment.variables)} + + + to-task3 + from-task3 + + + ${environment.services.takeFlow(0,environment.variables)} + + + + + Flow_069q2f5 + + + to-task4 + to-fork + backto-task1 + + + + ${false} + + + + + + + + to-end + from-task5-1 + from-task5-0 + from-task5-2 + + + + ${false} + + + ${true} + + + from-task5-0 + from-task7 + + + + from-fork-0 + from-task6 + + + + from-task2 + from-task3 + to-task4 + + + to-fork + from-fork-1 + from-fork-2 + from-fork-0 + + + from-fork-1 + from-fork-2 + from-task6 + to-end + + + from-task5-1 + from-task5-2 + from-task7 + Flow_069q2f5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/loop.bpmn b/test/resources/loop.bpmn index 50e92f09..385fb58b 100644 --- a/test/resources/loop.bpmn +++ b/test/resources/loop.bpmn @@ -1,96 +1,96 @@ - + - - flow1 + + to-task1 - - - flow2 - flow5 - flow3 + + + to-decision + to-end + to-task2 - - - flow5 + + + to-end - - - + + + next(null, environment.variables.input < 2); - - - flow3 - flow4 - + + + to-task2 + from-task2 + environment.variables.input += 1; +next(); - - flow1 - flow4 - flow2 + + to-task1 + from-task2 + to-decision next(); - + - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - + + + - - - - - - From bd9160efc79867e11218d683489e942c55f652ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Tue, 9 Sep 2025 06:28:30 +0200 Subject: [PATCH 02/31] mv feature test --- ...tiple-startEvent-feature.js => multiple-startevent-feature.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/feature/{multiple-startEvent-feature.js => multiple-startevent-feature.js} (100%) diff --git a/test/feature/multiple-startEvent-feature.js b/test/feature/multiple-startevent-feature.js similarity index 100% rename from test/feature/multiple-startEvent-feature.js rename to test/feature/multiple-startevent-feature.js From 3c95907f33175379a32a08eb315ba494a315cc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Wed, 10 Sep 2025 07:42:00 +0200 Subject: [PATCH 03/31] closing in fixing shake functionality --- CHANGELOG.md | 2 + docs/Activity.md | 1 + package.json | 2 +- src/Environment.js | 2 +- src/activity/Activity.js | 68 ++- src/flows/SequenceFlow.js | 13 +- src/process/ProcessExecution.js | 196 ++++++--- test/Environment-test.js | 2 +- test/feature/BoundaryEvent-feature.js | 4 +- test/feature/environment-feature.js | 2 +- .../issues/exclusive-gateway-join-feature.js | 50 ++- test/feature/multiple-startevent-feature.js | 396 +++++++++--------- test/feature/performance-feature.js | 181 ++++---- test/feature/skip-discard-feature.js | 6 +- test/resources/join-inbound.bpmn | 51 ++- test/resources/join-paradox-1.bpmn | 222 ++++++++++ .../multiple-signal-startevents.bpmn | 98 +++++ types/types.d.ts | 6 + 18 files changed, 893 insertions(+), 409 deletions(-) create mode 100644 test/resources/join-paradox-1.bpmn create mode 100644 test/resources/multiple-signal-startevents.bpmn diff --git a/CHANGELOG.md b/CHANGELOG.md index f4953cd7..b990752a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- new activity readonly property `isParallelJoin` indicating a parallel joun gateway + ## v17.3.0 - 2025-12-03 - major upgrade of [smqp@11](https://github.com/paed01/smqp/blob/default/CHANGELOG.md) diff --git a/docs/Activity.md b/docs/Activity.md index fd562d6a..443f758f 100644 --- a/docs/Activity.md +++ b/docs/Activity.md @@ -34,6 +34,7 @@ Activity properties: - `isRunning`: boolean indicating if the activity is running - `isStart`: boolean indicating if the activity a start activity - `isSubProcess`: boolean indicating if the activity is a sub process +- `isParallelJoin`: boolean indicating if the activity is a parallel join gateway - `logger`: activity [logger](/docs/Environment.md#logger) instance - `outbound`: list of outbound sequence flows - `parent`: activity parent diff --git a/package.json b/package.json index 8b1272db..718c915d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bpmn-elements", - "version": "17.3.0", + "version": "18.0.0", "description": "Executable workflow elements based on BPMN 2.0", "type": "module", "main": "./dist/index.js", diff --git a/src/Environment.js b/src/Environment.js index 9fb8f6a3..80372cb1 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -15,7 +15,7 @@ export default function Environment(options = {}) { this.output = options.output || {}; this.scripts = options.scripts || new Scripts(); this.timers = options.timers || new Timers(); - this.settings = { ...options.settings }; + this.settings = { skipDiscard: true, ...options.settings }; this.Logger = options.Logger || DummyLogger; this[kServices] = options.services || {}; this[kVariables] = options.variables || {}; diff --git a/src/activity/Activity.js b/src/activity/Activity.js index f40a5af9..b713e546 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -80,7 +80,7 @@ function Activity(Behaviour, activityDef, context) { outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows), ...(isParallelJoin && { inboundJoinFlows: new Set(), - inboundSourceIds: new Set(inboundSequenceFlows.map(({ sourceId }) => sourceId)), + inboundSourceIds: new Map(inboundSequenceFlows.map(({ sourceId }) => [sourceId, 0])), }), }; @@ -198,6 +198,11 @@ Object.defineProperties(Activity.prototype, { return this[kFlags].isForCompensation; }, }, + isParallelJoin: { + get() { + return this[kFlags].isParallelJoin; + }, + }, triggeredByEvent: { get() { return this[kActivityDef].triggeredByEvent; @@ -228,6 +233,11 @@ Object.defineProperties(Activity.prototype, { return this.context.getActivityParentById(this.id); }, }, + expectedInboundSources: { + get() { + return new Map(this[kFlows].inboundSourceIds); + }, + }, }); Activity.prototype.activate = function activate() { @@ -242,6 +252,7 @@ Activity.prototype.deactivate = function deactivate() { this.removeInboundListeners(); broker.cancel('_run-on-inbound'); broker.cancel('_format-consumer'); + if (this.isParallelJoin) this[kFlows].inboundSourceIds = new Map(this[kFlows].inboundSequenceFlows.map(({ sourceId }) => [sourceId, 0])); }; Activity.prototype.init = function init(initContent) { @@ -451,19 +462,40 @@ Activity.prototype._discardRun = function discardRun() { this._consumeRunQ(); }; +Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { + if (this.isParallelJoin) { + const message = cloneMessage(sourceMessage, { join: this.id }); + message.content.sequence.push({ id: this.id, type: this.type }); + return this.broker.publish('event', 'activity.shake.join', message.content, { + persistent: false, + type: 'shake', + }); + } + + this._shakeOutbound(sourceMessage); +}; + Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { const message = cloneMessage(sourceMessage); message.content.sequence = message.content.sequence || []; message.content.sequence.push({ id: this.id, type: this.type }); - const broker = this.broker; - this.broker.publish('api', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); + this.broker.publish('event', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); if (this[kFlags].isEnd) { - return broker.publish('event', 'activity.shake.end', message.content, { persistent: false, type: 'shake' }); + return this.broker.publish('event', 'activity.shake.end', cloneContent(message.content), { persistent: false, type: 'shake' }); + } + + const targets = new Map(); + + for (const outboundFlow of this[kFlows].outboundSequenceFlows) { + const prevTarget = targets.get(outboundFlow.targetId); + if (!prevTarget) { + targets.set(outboundFlow.targetId, outboundFlow); + } } - for (const flow of this[kFlows].outboundSequenceFlows) flow.shake(message); + for (const t of targets.values()) t.shake(message); }; Activity.prototype._consumeInbound = function consumeInbound() { @@ -508,31 +540,20 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { }; Activity.prototype._onJoinInbound = function onJoinInbound(routingKey, message) { - const { content } = message; const { inboundJoinFlows, inboundSourceIds } = this[kFlows]; - let alreadyTouched = false; - const touched = new Set(); - - let taken; - for (const msg of inboundJoinFlows) { - const sourceId = msg.content.sourceId; - touched.add(sourceId); - if (sourceId === content.sourceId) { - alreadyTouched = true; - } - } + const expectedInboundCount = [...inboundSourceIds.values()].reduce((s, a) => s + (a || 1)); inboundJoinFlows.add(message); - if (alreadyTouched) return; - - const remaining = inboundSourceIds.size - touched.size - 1; + const remaining = expectedInboundCount - inboundJoinFlows.size; if (remaining) { return this.logger.debug(`<${this.id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`); } const inbound = []; + + let taken; for (const im of inboundJoinFlows) { if (im.fields.routingKey === 'flow.take') taken = true; im.ack(); @@ -569,8 +590,13 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message break; } case 'flow.shake': { - return this._shakeOutbound(message); + if (this.isParallelJoin) { + let count = this[kFlows].inboundSourceIds.get(content.sourceId); + this[kFlows].inboundSourceIds.set(content.sourceId, ++count); + } } + case 'activity.shake.start': + return this._onShakeMessage(message); case 'association.take': case 'flow.take': case 'flow.discard': diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index 6d61ba9e..ce6513cc 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -100,14 +100,19 @@ SequenceFlow.prototype.stop = function stop() { }; SequenceFlow.prototype.shake = function shake(message) { - const content = cloneContent(message.content); + const content = cloneContent(message.content, { sourceId: this.sourceId, targetId: this.targetId }); content.sequence = content.sequence || []; - content.sequence.push({ id: this.id, type: this.type, isSequenceFlow: true, targetId: this.targetId }); + const hasCondition = !!this.behaviour.conditionExpression; + content.sequence.push({ id: this.id, type: this.type, isSequenceFlow: true, hasCondition, targetId: this.targetId }); - if (content.id === this.targetId) return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); + if (content.id === this.targetId) { + return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); + } for (const s of message.content.sequence || []) { - if (s.id === this.id) return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); + if (s.id === this.id) { + return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); + } } this.broker.publish('event', 'flow.shake', content, { persistent: false, type: 'shake' }); diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 1ece1965..924a0df6 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -37,7 +37,8 @@ function ProcessExecution(parentActivity, context) { startActivities: new Set(), triggeredByEvent: new Set(), detachedActivities: new Set(), - startSequences: {}, + parallelJoins: new Set(), + startSequences: new Map(), }; const exchangeName = (this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution'); @@ -124,9 +125,9 @@ ProcessExecution.prototype.resume = function resume() { this._activate(); - const { startActivities, detachedActivities, postponed } = this[kElements]; + const { startActivities, detachedActivities, postponed, parallelJoins } = this[kElements]; - if (startActivities.size > 1) { + if (startActivities.size > 1 || parallelJoins.size) { for (const a of startActivities) a.shake(); } @@ -238,43 +239,55 @@ ProcessExecution.prototype.recover = function recover(state) { }; ProcessExecution.prototype.shake = function shake(fromId) { - let executing = true; - const id = this.id; - if (!this.isRunning) { - executing = false; - this.executionId = getUniqueId(id); - this._activate(); - } - const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; - - const result = {}; - this.broker.subscribeTmp( - 'event', - '*.shake.*', - (routingKey, { content }) => { - let isLooped = false; - switch (routingKey) { - case 'flow.shake.loop': - isLooped = true; - case 'activity.shake.end': { - const { id: shakeId, parent: shakeParent } = content; - if (shakeParent.id !== id) return; - - result[shakeId] = result[shakeId] || []; - result[shakeId].push({ ...content, isLooped }); - break; - } - } - }, - { noAck: true, consumerTag: `_shaker-${this.executionId}` } - ); - - for (const a of toShake) a.shake(); - - if (!executing) this._deactivate(); - this.broker.cancel(`_shaker-${this.executionId}`); - - return result; + return Object.fromEntries(this._shakeElements(fromId).sequences); + // let executing = true; + // const id = this.id; + // if (!this.isRunning) { + // executing = false; + // this.executionId = getUniqueId(id); + // this._activate(); + // } + // const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; + + // const result = { + // settings: { + // skipDiscard: this.environment.settings.skipDiscard, + // }, + // }; + // const joins = new Set(); + // const consumerTag = `_shaker-${this.executionId}`; + + // this.broker.subscribeTmp( + // 'event', + // '*.shake.*', + // (routingKey, { content }) => { + // switch (routingKey) { + // case 'activity.shake.join': + // joins.add(content.join); + // result.settings.skipDiscard = false; + // case 'flow.shake.loop': + // case 'activity.shake.end': { + // const { id: shakeId, parent: shakeParent } = content; + // if (shakeParent.id !== id) return; + + // result[shakeId] = result[shakeId] || []; + // result[shakeId].push({ ...content, isLooped: routingKey === 'flow.shake.loop' }); + // break; + // } + // } + // }, + // { noAck: true, consumerTag } + // ); + + // for (const a of toShake) a.shake(); + // for (const joinId of joins) this.getActivityById(joinId).shake(); + + // console.log('---------------------------', result); + + // if (!executing) this._deactivate(); + // this.broker.cancel(consumerTag); + + // return result; }; ProcessExecution.prototype.stop = function stop() { @@ -369,9 +382,15 @@ ProcessExecution.prototype._start = function start() { this.broker.publish(this._exchangeName, 'execute.start', cloneContent(executeContent)); - const { startActivities, postponed, detachedActivities } = this[kElements]; - if (startActivities.size > 1) { - for (const a of startActivities) a.shake(); + const { startActivities, postponed, detachedActivities, parallelJoins } = this[kElements]; + if (startActivities.size > 1 || parallelJoins.size) { + const result = this._shakeElements(); + this.environment.settings.skipDiscard = result.settings.skipDiscard; + this._debug( + !result.settings.skipDiscard + ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` + : 'forced shake' + ); } for (const a of startActivities) a.init(); @@ -403,7 +422,7 @@ ProcessExecution.prototype._activate = function activate() { }); } - const { outboundMessageFlows, flows, associations, startActivities, triggeredByEvent, children } = this[kElements]; + const { outboundMessageFlows, flows, associations, startActivities, triggeredByEvent, parallelJoins, children } = this[kElements]; for (const flow of outboundMessageFlows) { flow.activate(); @@ -443,6 +462,7 @@ ProcessExecution.prototype._activate = function activate() { }); if (activity.isStart) startActivities.add(activity); if (activity.triggeredByEvent) triggeredByEvent.add(activity); + if (activity.isParallelJoin) parallelJoins.add(activity); } this[kActivated] = true; @@ -478,6 +498,60 @@ ProcessExecution.prototype._deactivate = function deactivate() { this[kActivated] = false; }; +ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { + let executing = true; + const id = this.id; + if (!this.isRunning) { + executing = false; + this.executionId = getUniqueId(id); + this._activate(); + } + const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; + + const result = { + settings: { + skipDiscard: this.environment.settings.skipDiscard, + }, + sequences: new Map(), + }; + const joins = new Set(); + const consumerTag = `_shaker-${this.executionId}`; + + this.broker.subscribeTmp( + 'event', + '*.shake.*', + (routingKey, { content }) => { + switch (routingKey) { + case 'activity.shake.join': + joins.add(content.join); + result.settings.skipDiscard = false; + case 'flow.shake.loop': + case 'activity.shake.end': { + const { id: shakeId, parent: shakeParent } = content; + if (shakeParent.id !== id) return; + + let seqnce; + if (!(seqnce = result.sequences.get(shakeId))) { + seqnce = []; + result.sequences.set(shakeId, seqnce); + } + seqnce.push({ ...content, isLooped: routingKey === 'flow.shake.loop' }); + break; + } + } + }, + { noAck: true, consumerTag } + ); + + for (const a of toShake) a.shake(); + for (const joinId of joins) this.getActivityById(joinId).shake(); + + if (!executing) this._deactivate(); + this.broker.cancel(consumerTag); + + return result; +}; + ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) { const eventType = message.properties.type; let delegate = true; @@ -506,12 +580,13 @@ ProcessExecution.prototype._onMessageFlowEvent = function onMessageFlowEvent(rou }; ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { - if (message.fields.redelivered && message.properties.persistent === false) return; + const { fields, content, properties } = message; + + if (fields.redelivered && properties.persistent === false) return; - const content = message.content; const parent = (content.parent = content.parent || {}); - let delegate = message.properties.delegate; - const shaking = message.properties.type === 'shake'; + let delegate = properties.delegate; + const shaking = properties.type === 'shake'; const isDirectChild = content.parent.id === this.id; if (isDirectChild) { @@ -523,7 +598,7 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe if (delegate) delegate = this._onDelegateEvent(message); this[kTracker].track(routingKey, message); - this.broker.publish('event', routingKey, content, { ...message.properties, delegate, mandatory: false }); + this.broker.publish('event', routingKey, content, { ...properties, delegate, mandatory: false }); if (shaking) return this._onShookEnd(message); if (!isDirectChild) return; @@ -697,11 +772,11 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message const startSequences = this[kElements].startSequences; for (const msg of postponed) { const postponedId = msg.content.id; - const startSequence = startSequences[postponedId]; - if (startSequence) { - if (startSequence.content.sequence.some(({ id: sid }) => sid === id)) { - this._getChildApi(msg).discard(); - } + const startSequence = startSequences.get(postponedId); + if (!startSequence) continue; + + if (startSequence.has(id)) { + this._getChildApi(msg).discard(); } } } @@ -920,9 +995,16 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { }; ProcessExecution.prototype._onShookEnd = function onShookEnd(message) { - const routingKey = message.fields.routingKey; - if (routingKey !== 'activity.shake.end') return; - this[kElements].startSequences[message.content.id] = cloneMessage(message); + const { id, targetId } = message.content; + + let seq = this[kElements].startSequences.get(id); + if (!seq) { + seq = new Set([id]); + this[kElements].startSequences.set(id, seq); + } + if (targetId) { + seq.add(targetId); + } }; ProcessExecution.prototype._debug = function debugMessage(logMessage) { diff --git a/test/Environment-test.js b/test/Environment-test.js index 8a6f9f91..9da9a825 100644 --- a/test/Environment-test.js +++ b/test/Environment-test.js @@ -4,7 +4,7 @@ import { Timers } from '../src/Timers.js'; describe('Environment', () => { describe('ctor', () => { it('sets settings', () => { - expect(new Environment()).to.have.property('settings').that.eql({}); + expect(new Environment()).to.have.property('settings').that.deep.equal({}); expect( new Environment({ settings: { diff --git a/test/feature/BoundaryEvent-feature.js b/test/feature/BoundaryEvent-feature.js index 105ee86a..f985c47b 100644 --- a/test/feature/BoundaryEvent-feature.js +++ b/test/feature/BoundaryEvent-feature.js @@ -47,8 +47,8 @@ Feature('BoundaryEvent', () => { - - + + diff --git a/test/feature/environment-feature.js b/test/feature/environment-feature.js index f481c38c..5695ba7f 100644 --- a/test/feature/environment-feature.js +++ b/test/feature/environment-feature.js @@ -1,7 +1,7 @@ import testHelpers from '../helpers/testHelpers.js'; import Definition from '../../src/definition/Definition.js'; -Feature('Definition', () => { +Feature('Environment', () => { Scenario('A definition with one process and a user task', () => { const source = ` diff --git a/test/feature/issues/exclusive-gateway-join-feature.js b/test/feature/issues/exclusive-gateway-join-feature.js index 4faa9a12..00f6cd4c 100644 --- a/test/feature/issues/exclusive-gateway-join-feature.js +++ b/test/feature/issues/exclusive-gateway-join-feature.js @@ -1,22 +1,48 @@ -import { Definition } from '../../../src/index.js'; +import { Definition } from 'bpmn-elements'; + import testHelpers from '../../helpers/testHelpers.js'; import factory from '../../helpers/factory.js'; const source = factory.resource('exclusive-gateway-as-join.bpmn'); Feature('Exclusive gateway used for joining', () => { - Scenario('a number of exclusive gateway join and split', () => { - let context, definition, end; - When('running a definition matching the scenario', async () => { - context = await testHelpers.context(source); - - definition = new Definition(context); - end = definition.waitFor('end'); - definition.run(); - }); + [false, true].forEach((skipDiscard) => { + describe(`run ${skipDiscard ? 'with' : 'without'} skipDiscard setting`, () => { + Scenario('a number of exclusive gateway join and split', () => { + let context; + /** @type {Definition} */ + let definition; + let end; + When('running a definition matching the scenario', async () => { + context = await testHelpers.context(source); + + definition = new Definition(context, { settings: { skipDiscard } }); + end = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + When('same instance is ran again', () => { + end = definition.waitFor('leave'); + definition.run(); + }); + + Then('second run completes', () => { + return end; + }); + + When('same instance is ran yet again', () => { + end = definition.waitFor('leave'); + definition.run(); + }); - Then('run completes', () => { - return end; + Then('third run completes', () => { + return end; + }); + }); }); }); }); diff --git a/test/feature/multiple-startevent-feature.js b/test/feature/multiple-startevent-feature.js index 325ce7cb..015e80d9 100644 --- a/test/feature/multiple-startevent-feature.js +++ b/test/feature/multiple-startevent-feature.js @@ -1,209 +1,209 @@ import Definition from '../../src/definition/Definition.js'; import testHelpers from '../helpers/testHelpers.js'; +import factory from '../helpers/factory.js'; Feature('Multiple start events', () => { - Scenario('Two start events waiting to be signaled ending up in a task', () => { - const source = ` - - - - - - - - - - - - - - - next(null, environment.output.start2) - - - - - - - `; - - let definition; - Given('a process with multiple start events, a joining task and an end event', async () => { - const context = await testHelpers.context(source); - definition = new Definition(context, { - extensions: { - output(element) { - if (element.type !== 'bpmn:Process') return; - - const { broker, environment } = element; - broker.subscribeTmp( - 'event', - 'activity.end', - (_, { content }) => { - environment.output[content.id] = 1; + [false, true].forEach((skipDiscard) => { + describe(`run ${skipDiscard ? 'with' : 'without'} skipDiscard setting`, () => { + Scenario('Two start events waiting to be signaled ending up in a task', () => { + const source = factory.resource('multiple-signal-startevents.bpmn'); + + let definition; + Given('a process with multiple start events, a joining task and an end event', async () => { + const context = await testHelpers.context(source); + definition = new Definition(context, { + settings: { + skipDiscard, + }, + extensions: { + output(element) { + if (element.type !== 'bpmn:Process') return; + + const { broker, environment } = element; + broker.subscribeTmp( + 'event', + 'activity.end', + (_, { content }) => { + environment.output[content.id] = 1; + }, + { noAck: true } + ); }, - { noAck: true } - ); - }, - }, + }, + }); + }); + + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + And('first start event is signaled', () => { + definition.signal(); + }); + + Then('first end event is taken', () => { + const endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: skipDiscard ? 0 : 1 }); + }); + + And('second end event is not taken', () => { + const endEvent = definition.getActivityById('named-end'); + expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: skipDiscard ? 0 : 2 }); + }); + + And('process is completed', async () => { + await leave; + expect(definition.counters).to.deep.equal({ + completed: 1, + discarded: 0, + }); + }); + + When('process is ran again', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + And('second start event is signaled', () => { + const start2 = definition.getPostponed().find(({ id }) => id === 'start2'); + definition.signal(start2.content.signal); + }); + + Then('second end event is taken', () => { + const endEvent = definition.getActivityById('named-end'); + expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: skipDiscard ? 0 : 3 }); + }); + + And('first end event is discarded', () => { + const endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: skipDiscard ? 0 : 3 }); + }); + + And('process is completed', async () => { + await leave; + + const pending = definition.getPostponed().map(({ id }) => id); + + expect(definition.counters, `pending <${pending}>`).to.deep.equal({ + completed: 2, + discarded: 0, + }); + }); }); - }); - - When('process is ran', () => { - definition.run(); - }); - - And('first start event is signaled', () => { - definition.signal(); - }); - - Then('first end event is taken', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 1 }); - }); - - And('second end event is discarded', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 2 }); - }); - - And('process is completed', () => { - expect(definition.counters).to.deep.equal({ - completed: 1, - discarded: 0, - }); - }); - - When('process is ran again', () => { - definition.run(); - }); - - And('second start event is signaled', () => { - definition.signal({ id: 'Message_1' }); - }); - - Then('second end event is taken', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 3 }); - }); - - And('first end event is discarded', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 3 }); - }); - And('process is completed', () => { - expect(definition.counters).to.deep.equal({ - completed: 2, - discarded: 0, - }); - }); - }); - - Scenario('Two start events waiting to be signaled ending up in a parallel join', () => { - const source = ` - - - - - - - - - - - - - - - next(null, environment.output.start2) - - - - - - - `; - - let definition; - Given('a process with multiple start events, a joining task and an end event', async () => { - const context = await testHelpers.context(source); - definition = new Definition(context, { - extensions: { - output(element) { - if (element.type !== 'bpmn:Process') return; - - const { broker, environment } = element; - broker.subscribeTmp( - 'event', - 'activity.end', - (_, { content }) => { - environment.output[content.id] = 1; + Scenario('Two start events waiting to be signaled ending up in a parallel join', () => { + const source = ` + + + + + + + + + + + + + + + next(null, environment.output.start2) + + + + + + + `; + + let definition; + Given('a process with multiple start events, a joining task and an end event', async () => { + const context = await testHelpers.context(source); + definition = new Definition(context, { + environment: { + settings: { + skipDiscard, }, - { noAck: true } - ); - }, - }, - }); - }); - - When('process is ran', () => { - definition.run(); - }); - - And('first start event is signaled', () => { - definition.signal(); - }); - - Then('parallel join is pending', () => { - const join = definition.getActivityById('join'); - expect(join.counters).to.deep.equal({ taken: 0, discarded: 0 }); - }); - - When('second start event is signaled', () => { - definition.signal({ id: 'Message_1' }); - }); - - Then('process is completed', () => { - expect(definition.counters).to.deep.equal({ - completed: 1, - discarded: 0, - }); - }); - - Then('first end event is discarded', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 1 }); - }); - - And('second end event is taken', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 0 }); - }); - - When('process is ran again', () => { - definition.run(); - }); - - And('start events are signaled', () => { - definition.signal(); - definition.signal({ id: 'Message_1' }); - }); - - Then('first end event is discarded', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 2 }); - }); - - And('second end event is taken', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 2, discarded: 0 }); - }); - - And('process is completed', () => { - expect(definition.counters).to.deep.equal({ - completed: 2, - discarded: 0, + }, + extensions: { + output(element) { + if (element.type !== 'bpmn:Process') return; + + const { broker, environment } = element; + broker.subscribeTmp( + 'event', + 'activity.end', + (_, { content }) => { + environment.output[content.id] = 1; + }, + { noAck: true } + ); + }, + }, + }); + }); + + When('process is ran', () => { + definition.run(); + }); + + And('first start event is signaled', () => { + definition.signal(); + }); + + Then('parallel join is pending', () => { + const join = definition.getActivityById('join'); + expect(join.counters).to.deep.equal({ taken: 0, discarded: 0 }); + }); + + When('second start event is signaled', () => { + definition.signal({ id: 'Message_1' }); + }); + + Then('process is completed', () => { + expect(definition.counters).to.deep.equal({ + completed: 1, + discarded: 0, + }); + }); + + Then('first end event is discarded', () => { + const endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 1 }); + }); + + And('second end event is taken', () => { + const endEvent = definition.getActivityById('named-end'); + expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + When('process is ran again', () => { + definition.run(); + }); + + And('start events are signaled', () => { + definition.signal(); + definition.signal({ id: 'Message_1' }); + }); + + Then('first end event is discarded', () => { + const endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 2 }); + }); + + And('second end event is taken', () => { + const endEvent = definition.getActivityById('named-end'); + expect(endEvent.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('process is completed', () => { + expect(definition.counters).to.deep.equal({ + completed: 2, + discarded: 0, + }); + }); }); }); }); diff --git a/test/feature/performance-feature.js b/test/feature/performance-feature.js index 484775a6..12fd2a70 100644 --- a/test/feature/performance-feature.js +++ b/test/feature/performance-feature.js @@ -9,111 +9,122 @@ const extensions = { }; Feature('Performance', () => { - describe('lots of script conditions', () => { - let context; - Given('a diagram with lots of script conditions and nested joins', async () => { - const source = factory.resource('nested-joins.bpmn'); - context = await testHelpers.context(source, { extensions }); - }); + [true, false].forEach((skipDiscard) => { + describe(`${skipDiscard ? 'with' : 'without'} skipDiscard and lots of script conditions`, () => { + let context; + Given('a diagram with lots of script conditions and nested joins', async () => { + const source = factory.resource('nested-joins.bpmn'); + context = await testHelpers.context(source, { extensions }); + }); - let definition, ended; - When('run with default JavaScript', async () => { - definition = new Definition(await context.clone()); - ended = definition.waitFor('end'); - await definition.run(); - }); + let definition, ended; + When('run with default JavaScript', async () => { + definition = new Definition(await context.clone(), { settings: { skipDiscard } }); + ended = definition.waitFor('end'); + await definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - When('run again with default JavaScript', () => { - definition = new Definition(context.clone()); - ended = definition.waitFor('end'); - definition.run(); - }); + When('run again with default JavaScript', () => { + definition = new Definition(context.clone(), { settings: { skipDiscard } }); + ended = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - let endEvent; - And('end event was taken', () => { - endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.have.property('taken', 1); - }); + let endEvent; + And('end event was taken', () => { + endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.have.property('taken', 1); + }); - When('same definition is ran again', () => { - ended = definition.waitFor('end'); - definition.run(); - }); + When('same definition is ran again', () => { + ended = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - And('end event was taken again', () => { - endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.have.property('taken', 2); - }); + And('end event was taken again', () => { + endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.have.property('taken', 2); + }); - When('run with non-op JavaScript', () => { - definition = new Definition(context.clone(), { - scripts: { - register() {}, - getScript() { - return { - execute(...args) { - return args.pop()(); - }, - }; + When('run with non-op JavaScript', () => { + definition = new Definition(context.clone(), { + settings: { + skipDiscard, }, - }, + scripts: { + register() {}, + getScript() { + return { + execute(...args) { + return args.pop()(); + }, + }; + }, + }, + }); + ended = definition.waitFor('end'); + definition.run(); }); - ended = definition.waitFor('end'); - definition.run(); - }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - When('run without logger', () => { - definition = new Definition(context.clone(), { - Logger: null, + When('run without logger', () => { + definition = new Definition(context.clone(), { + settings: { + skipDiscard, + }, + Logger: null, + }); + ended = definition.waitFor('end'); + definition.run(); }); - ended = definition.waitFor('end'); - definition.run(); - }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - When('run with non-op JavaScript and no logger', () => { - definition = new Definition(context.clone(), { - Logger: null, - scripts: { - register() {}, - getScript() { - return { - execute(...args) { - return args.pop()(); - }, - }; + When('run with non-op JavaScript and no logger', () => { + definition = new Definition(context.clone(), { + settings: { + skipDiscard, }, - }, + Logger: null, + scripts: { + register() {}, + getScript() { + return { + execute(...args) { + return args.pop()(); + }, + }; + }, + }, + }); + ended = definition.waitFor('end'); + definition.run(); }); - ended = definition.waitFor('end'); - definition.run(); - }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - And('end event was taken', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + And('end event was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); }); }); }); diff --git a/test/feature/skip-discard-feature.js b/test/feature/skip-discard-feature.js index e7934ae5..15392d40 100644 --- a/test/feature/skip-discard-feature.js +++ b/test/feature/skip-discard-feature.js @@ -230,7 +230,7 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { }); }); - ['issue-42-same-target-sequence-flows.bpmn'].forEach((source) => { + ['join-inbound.bpmn', 'join-paradox-1.bpmn', 'issue-42-same-target-sequence-flows.bpmn'].forEach((source) => { Scenario(`${source} with parallel join gateways should complete as expected`, () => { /** @type {Definition} */ let definition; @@ -289,8 +289,8 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { return end; }); - And('with no discarded flows', () => { - expect(discardedFlows).to.have.length(0); + And('with discarded flows', () => { + expect(discardedFlows.length).to.be.above(0); }); }); }); diff --git a/test/resources/join-inbound.bpmn b/test/resources/join-inbound.bpmn index 4ebe7694..7e8bab78 100644 --- a/test/resources/join-inbound.bpmn +++ b/test/resources/join-inbound.bpmn @@ -1,5 +1,5 @@ - + Flow_0jzmhc7 @@ -17,19 +17,19 @@ to-task2 - + to-task3 to-gw-collect ${false} - + to-task1 from-task1 - + to-task2 from-task2 @@ -50,7 +50,7 @@ to-end - + to-task4 from-task5 from-task4 @@ -81,13 +81,16 @@ - + to-task5 from-task5 + + + @@ -96,12 +99,15 @@ + + + @@ -109,20 +115,19 @@ - - - + - - + + + @@ -140,10 +145,6 @@ - - - - @@ -166,28 +167,32 @@ + + + + + + + + - - - - - - - - + + + + diff --git a/test/resources/join-paradox-1.bpmn b/test/resources/join-paradox-1.bpmn new file mode 100644 index 00000000..cc13c9af --- /dev/null +++ b/test/resources/join-paradox-1.bpmn @@ -0,0 +1,222 @@ + + + + + to-sub + + + to-sub + to-end + + to-task1 + + + to-task1 + from-task3 + to-task2 + to-task4 + + + + + to-task2 + from-task2 + to-task3 + + + + to-task3 + from-task3 + + + ${false} + + + + to-task4 + from-task4 + to-task + + + + + to-sub-end + + + from-task2 + from-task4 + from-task5 + to-fork + + + to-fork + from-fork-1 + from-fork-2 + to-task5 + + + from-fork-1 + from-fork-2 + from-fork-task + to-sub-end + + + to-task5 + from-fork-task + + + + + + + + + to-task + from-task5 + + + + + + + to-end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/multiple-signal-startevents.bpmn b/test/resources/multiple-signal-startevents.bpmn new file mode 100644 index 00000000..cba3389f --- /dev/null +++ b/test/resources/multiple-signal-startevents.bpmn @@ -0,0 +1,98 @@ + + + + + from-task1 + + + + from-task2 + + + + from-task1 + from-task2 + to-decision + + + + + to-decision + to-end + to-named-end + + + + to-end + + + + to-named-end + + + next(null, environment.output.start2); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/types/types.d.ts b/types/types.d.ts index c4b7bd11..e797f315 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -159,6 +159,11 @@ declare interface EnvironmentSettings { * Defaults to falsy */ disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; [x: string]: any; } @@ -725,6 +730,7 @@ declare class Activity extends Element { get isMultiInstance(): boolean; get isThrowing(): boolean; get isForCompensation(): boolean; + get isParallelJoin(): boolean; get triggeredByEvent(): boolean; get attachedTo(): Activity; get eventDefinitions(): EventDefinition[]; From 7ea891de62d42cd9679c55a66dfd6806a6dedbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 14 Sep 2025 08:26:44 +0200 Subject: [PATCH 04/31] shake link event definition --- CHANGELOG.md | 6 + dist/Environment.js | 1 + dist/activity/Activity.js | 78 ++- dist/definition/DefinitionExecution.js | 4 +- dist/eventDefinitions/LinkEventDefinition.js | 43 +- dist/events/IntermediateCatchEvent.js | 5 +- dist/flows/SequenceFlow.js | 23 +- dist/process/ProcessExecution.js | 236 ++++++--- src/activity/Activity.js | 6 + src/definition/DefinitionExecution.js | 3 +- src/eventDefinitions/LinkEventDefinition.js | 35 +- src/events/IntermediateCatchEvent.js | 2 +- src/process/ProcessExecution.js | 44 +- test/feature/ad-hoc-subprocess-feature.js | 2 +- test/feature/linking-feature.js | 468 +++++++++--------- ...-feature.js => stop-and-resume-feature.js} | 0 test/feature/sub-process-feature.js | 13 +- test/helpers/testHelpers.js | 3 +- test/resources/misp-loopback.bpmn | 27 +- 19 files changed, 628 insertions(+), 371 deletions(-) rename test/feature/{stopAndResume-feature.js => stop-and-resume-feature.js} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index b990752a..bf1ab13f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +### Breaking + +- IntermediateCatchEvent cannot be used as a starting element, or it can, but will not be started by default + +### Additions + - new activity readonly property `isParallelJoin` indicating a parallel joun gateway ## v17.3.0 - 2025-12-03 diff --git a/dist/Environment.js b/dist/Environment.js index 5653f900..7f21606f 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -19,6 +19,7 @@ function Environment(options = {}) { this.scripts = options.scripts || new _Scripts.Scripts(); this.timers = options.timers || new _Timers.Timers(); this.settings = { + skipDiscard: true, ...options.settings }; this.Logger = options.Logger || DummyLogger; diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 49df2bbe..ddf139c9 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -94,9 +94,9 @@ function Activity(Behaviour, activityDef, context) { outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows), ...(isParallelJoin && { inboundJoinFlows: new Set(), - inboundSourceIds: new Set(inboundSequenceFlows.map(({ + inboundSourceIds: new Map(inboundSequenceFlows.map(({ sourceId - }) => sourceId)) + }) => [sourceId, 0])) }) }; this[kFlags] = { @@ -109,6 +109,7 @@ function Activity(Behaviour, activityDef, context) { isTransaction: activityDef.isTransaction, isParallelJoin, isThrowing: activityDef.isThrowing, + isCatching: activityDef.isCatching, lane: activityDef.lane?.id }; this[kExec] = new Map(); @@ -206,11 +207,21 @@ Object.defineProperties(Activity.prototype, { return this[kFlags].isThrowing; } }, + isCatching: { + get() { + return this[kFlags].isCatching; + } + }, isForCompensation: { get() { return this[kFlags].isForCompensation; } }, + isParallelJoin: { + get() { + return this[kFlags].isParallelJoin; + } + }, triggeredByEvent: { get() { return this[kActivityDef].triggeredByEvent; @@ -240,6 +251,11 @@ Object.defineProperties(Activity.prototype, { get() { return this.context.getActivityParentById(this.id); } + }, + expectedInboundSources: { + get() { + return new Map(this[kFlows].inboundSourceIds); + } } }); Activity.prototype.activate = function activate() { @@ -253,6 +269,9 @@ Activity.prototype.deactivate = function deactivate() { this.removeInboundListeners(); broker.cancel('_run-on-inbound'); broker.cancel('_format-consumer'); + if (this.isParallelJoin) this[kFlows].inboundSourceIds = new Map(this[kFlows].inboundSequenceFlows.map(({ + sourceId + }) => [sourceId, 0])); }; Activity.prototype.init = function init(initContent) { const id = this.id; @@ -452,6 +471,22 @@ Activity.prototype._discardRun = function discardRun() { this[kConsuming] = true; this._consumeRunQ(); }; +Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { + if (this.isParallelJoin) { + const message = (0, _messageHelper.cloneMessage)(sourceMessage, { + join: this.id + }); + message.content.sequence.push({ + id: this.id, + type: this.type + }); + return this.broker.publish('event', 'activity.shake.join', message.content, { + persistent: false, + type: 'shake' + }); + } + this._shakeOutbound(sourceMessage); +}; Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { const message = (0, _messageHelper.cloneMessage)(sourceMessage); message.content.sequence = message.content.sequence || []; @@ -459,18 +494,24 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { id: this.id, type: this.type }); - const broker = this.broker; - this.broker.publish('api', 'activity.shake.start', message.content, { + this.broker.publish('event', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); if (this[kFlags].isEnd) { - return broker.publish('event', 'activity.shake.end', message.content, { + return this.broker.publish('event', 'activity.shake.end', (0, _messageHelper.cloneContent)(message.content), { persistent: false, type: 'shake' }); } - for (const flow of this[kFlows].outboundSequenceFlows) flow.shake(message); + const targets = new Map(); + for (const outboundFlow of this[kFlows].outboundSequenceFlows) { + const prevTarget = targets.get(outboundFlow.targetId); + if (!prevTarget) { + targets.set(outboundFlow.targetId, outboundFlow); + } + } + for (const t of targets.values()) t.shake(message); }; Activity.prototype._consumeInbound = function consumeInbound() { if (!this[kActivated]) return; @@ -515,30 +556,18 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { } }; Activity.prototype._onJoinInbound = function onJoinInbound(routingKey, message) { - const { - content - } = message; const { inboundJoinFlows, inboundSourceIds } = this[kFlows]; - let alreadyTouched = false; - const touched = new Set(); - let taken; - for (const msg of inboundJoinFlows) { - const sourceId = msg.content.sourceId; - touched.add(sourceId); - if (sourceId === content.sourceId) { - alreadyTouched = true; - } - } + const expectedInboundCount = [...inboundSourceIds.values()].reduce((s, a) => s + (a || 1)); inboundJoinFlows.add(message); - if (alreadyTouched) return; - const remaining = inboundSourceIds.size - touched.size - 1; + const remaining = expectedInboundCount - inboundJoinFlows.size; if (remaining) { return this.logger.debug(`<${this.id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`); } const inbound = []; + let taken; for (const im of inboundJoinFlows) { if (im.fields.routingKey === 'flow.take') taken = true; im.ack(); @@ -581,8 +610,13 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message } case 'flow.shake': { - return this._shakeOutbound(message); + if (this.isParallelJoin) { + let count = this[kFlows].inboundSourceIds.get(content.sourceId); + this[kFlows].inboundSourceIds.set(content.sourceId, ++count); + } } + case 'activity.shake.start': + return this._onShakeMessage(message); case 'association.take': case 'flow.take': case 'flow.discard': diff --git a/dist/definition/DefinitionExecution.js b/dist/definition/DefinitionExecution.js index 1dcb0e02..c09da13a 100644 --- a/dist/definition/DefinitionExecution.js +++ b/dist/definition/DefinitionExecution.js @@ -4,11 +4,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = DefinitionExecution; -var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); var _Api = require("../Api.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const kActivated = Symbol.for('activated'); const kProcessesQ = Symbol.for('processesQ'); const kCompleted = Symbol.for('completed'); @@ -493,7 +491,7 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, const messageType = message.properties.type; const delegate = message.properties.delegate; if (delegate && this.id === message.content.id) { - const referenceId = (0, _getPropertyValue.default)(message, 'content.message.id'); + const referenceId = message.content.message?.id; this._startProcessesByMessage({ referenceId, referenceType: messageType diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index 543e1ee5..2daea74f 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -4,10 +4,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = LinkEventDefinition; -var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const kCompleted = Symbol.for('completed'); const kMessageQ = Symbol.for('messageQ'); const kExecuteMessage = Symbol.for('executeMessage'); @@ -42,7 +40,26 @@ function LinkEventDefinition(activity, eventDefinition) { broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); + broker.subscribeTmp('api', `activity.shake.${reference.referenceType}`, this._onApiMessage.bind(this), { + noAck: true + }); } else { + broker.subscribeTmp('event', 'activity.shake.start', (_, msg) => { + broker.publish('event', `activity.shake.${reference.referenceType}`, (0, _messageHelper.cloneContent)(msg.content, { + sourceId: this.id, + targetId: undefined, + message: { + ...this.reference + } + }), { + type: 'shake', + delegate: true + }); + }, { + noAck: true, + consumerTag: '_link-parent-shake', + priority: 1000 + }); broker.subscribeTmp('event', 'activity.discard', this._onDiscard.bind(this), { noAck: true, consumerTag: '_link-parent-discard' @@ -115,13 +132,12 @@ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessag return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); }; LinkEventDefinition.prototype._onCatchLink = function onCatchLink(routingKey, message) { - if ((0, _getPropertyValue.default)(message, 'content.message.linkName') !== this.reference.linkName) return; + if (message.content.message?.linkName !== this.reference.linkName) return; if (message.content.state === 'discard') return this._discard(); return this._complete('caught', message.content.message); }; LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { - const messageType = message.properties.type; - switch (messageType) { + switch (message.properties.type) { case 'discard': { return this._discard(); @@ -131,6 +147,23 @@ LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, this._stop(); break; } + case 'shake': + { + if (message.content.message?.linkName !== this.reference.linkName) return; + const content = (0, _messageHelper.cloneContent)(message.content, { + targetId: this.id, + isLinked: true + }); + content.sequence = content.sequence || []; + content.sequence.push({ + id: this.id, + type: this.type + }); + return this.broker.publish('event', 'activity.shake.linked', content, { + persistent: false, + type: 'shake' + }); + } } }; LinkEventDefinition.prototype._complete = function complete(verb, output) { diff --git a/dist/events/IntermediateCatchEvent.js b/dist/events/IntermediateCatchEvent.js index 182b6546..5cce1b38 100644 --- a/dist/events/IntermediateCatchEvent.js +++ b/dist/events/IntermediateCatchEvent.js @@ -11,7 +11,10 @@ var _messageHelper = require("../messageHelper.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const kExecution = Symbol.for('execution'); function IntermediateCatchEvent(activityDef, context) { - return new _Activity.default(IntermediateCatchEventBehaviour, activityDef, context); + return new _Activity.default(IntermediateCatchEventBehaviour, { + ...activityDef, + isCatching: true + }, context); } function IntermediateCatchEventBehaviour(activity) { this.id = activity.id; diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index 791930ef..eec72fd3 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -109,24 +109,33 @@ SequenceFlow.prototype.stop = function stop() { this.broker.stop(); }; SequenceFlow.prototype.shake = function shake(message) { - const content = (0, _messageHelper.cloneContent)(message.content); + const content = (0, _messageHelper.cloneContent)(message.content, { + sourceId: this.sourceId, + targetId: this.targetId + }); content.sequence = content.sequence || []; + const hasCondition = !!this.behaviour.conditionExpression; content.sequence.push({ id: this.id, type: this.type, isSequenceFlow: true, + hasCondition, targetId: this.targetId }); - if (content.id === this.targetId) return this.broker.publish('event', 'flow.shake.loop', content, { - persistent: false, - type: 'shake' - }); - for (const s of message.content.sequence || []) { - if (s.id === this.id) return this.broker.publish('event', 'flow.shake.loop', content, { + if (content.id === this.targetId) { + return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); } + for (const s of message.content.sequence || []) { + if (s.id === this.id) { + return this.broker.publish('event', 'flow.shake.loop', content, { + persistent: false, + type: 'shake' + }); + } + } this.broker.publish('event', 'flow.shake', content, { persistent: false, type: 'shake' diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 7bcbaebc..001023b4 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -44,7 +44,8 @@ function ProcessExecution(parentActivity, context) { startActivities: new Set(), triggeredByEvent: new Set(), detachedActivities: new Set(), - startSequences: {} + parallelJoins: new Set(), + startSequences: new Map() }; const exchangeName = this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution'; broker.assertExchange(exchangeName, 'topic', { @@ -125,10 +126,15 @@ ProcessExecution.prototype.resume = function resume() { const { startActivities, detachedActivities, - postponed + postponed, + parallelJoins } = this[kElements]; - if (startActivities.size > 1) { - for (const a of startActivities) a.shake(); + if (startActivities.size > 1 || parallelJoins.size) { + const result = this._shakeElements(); + if (this.environment.settings.skipDiscard !== result.settings.skipDiscard) { + this.environment.settings.skipDiscard = result.settings.skipDiscard; + this._debug(!result.settings.skipDiscard ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` : 'forced shake'); + } } postponed.clear(); detachedActivities.clear(); @@ -227,45 +233,55 @@ ProcessExecution.prototype.recover = function recover(state) { return this; }; ProcessExecution.prototype.shake = function shake(fromId) { - let executing = true; - const id = this.id; - if (!this.isRunning) { - executing = false; - this.executionId = (0, _shared.getUniqueId)(id); - this._activate(); - } - const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; - const result = {}; - this.broker.subscribeTmp('event', '*.shake.*', (routingKey, { - content - }) => { - let isLooped = false; - switch (routingKey) { - case 'flow.shake.loop': - isLooped = true; - case 'activity.shake.end': - { - const { - id: shakeId, - parent: shakeParent - } = content; - if (shakeParent.id !== id) return; - result[shakeId] = result[shakeId] || []; - result[shakeId].push({ - ...content, - isLooped - }); - break; - } - } - }, { - noAck: true, - consumerTag: `_shaker-${this.executionId}` - }); - for (const a of toShake) a.shake(); - if (!executing) this._deactivate(); - this.broker.cancel(`_shaker-${this.executionId}`); - return result; + return Object.fromEntries(this._shakeElements(fromId).sequences); + // let executing = true; + // const id = this.id; + // if (!this.isRunning) { + // executing = false; + // this.executionId = getUniqueId(id); + // this._activate(); + // } + // const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; + + // const result = { + // settings: { + // skipDiscard: this.environment.settings.skipDiscard, + // }, + // }; + // const joins = new Set(); + // const consumerTag = `_shaker-${this.executionId}`; + + // this.broker.subscribeTmp( + // 'event', + // '*.shake.*', + // (routingKey, { content }) => { + // switch (routingKey) { + // case 'activity.shake.join': + // joins.add(content.join); + // result.settings.skipDiscard = false; + // case 'flow.shake.loop': + // case 'activity.shake.end': { + // const { id: shakeId, parent: shakeParent } = content; + // if (shakeParent.id !== id) return; + + // result[shakeId] = result[shakeId] || []; + // result[shakeId].push({ ...content, isLooped: routingKey === 'flow.shake.loop' }); + // break; + // } + // } + // }, + // { noAck: true, consumerTag } + // ); + + // for (const a of toShake) a.shake(); + // for (const joinId of joins) this.getActivityById(joinId).shake(); + + // console.log('---------------------------', result); + + // if (!executing) this._deactivate(); + // this.broker.cancel(consumerTag); + + // return result; }; ProcessExecution.prototype.stop = function stop() { this.getApi().stop(); @@ -347,10 +363,13 @@ ProcessExecution.prototype._start = function start() { const { startActivities, postponed, - detachedActivities + detachedActivities, + parallelJoins } = this[kElements]; - if (startActivities.size > 1) { - for (const a of startActivities) a.shake(); + if (startActivities.size > 1 || parallelJoins.size) { + const result = this._shakeElements(); + this.environment.settings.skipDiscard = result.settings.skipDiscard; + this._debug(!result.settings.skipDiscard ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` : 'forced shake'); } for (const a of startActivities) a.init(); this[kStatus] = 'executing'; @@ -387,6 +406,7 @@ ProcessExecution.prototype._activate = function activate() { associations, startActivities, triggeredByEvent, + parallelJoins, children } = this[kElements]; for (const flow of outboundMessageFlows) { @@ -422,7 +442,8 @@ ProcessExecution.prototype._activate = function activate() { priority: 200 }); if (activity.isStart) startActivities.add(activity); - if (activity.triggeredByEvent) triggeredByEvent.add(activity); + if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); + if (activity.isParallelJoin) parallelJoins.add(activity); } this[kActivated] = true; }; @@ -454,6 +475,71 @@ ProcessExecution.prototype._deactivate = function deactivate() { } this[kActivated] = false; }; +ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { + let executing = true; + const id = this.id; + if (!this.isRunning) { + executing = false; + this.executionId = (0, _shared.getUniqueId)(id); + this._activate(); + } + const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; + const result = { + settings: { + skipDiscard: this.environment.settings.skipDiscard + }, + sequences: new Map() + }; + const manualShakes = new Set(); + const consumerTag = `_shaker-${this.executionId}`; + this.broker.subscribeTmp('event', '*.shake.*', (routingKey, { + content + }) => { + switch (routingKey) { + case 'activity.shake.link': + { + for (const a of this[kElements].triggeredByEvent) { + if (!a.isCatching) continue; + a.broker.publish('api', routingKey, (0, _messageHelper.cloneContent)(content), { + type: 'shake' + }); + } + break; + } + case 'activity.shake.join': + manualShakes.add(content.join); + result.settings.skipDiscard = false; + case 'flow.shake.loop': + case 'activity.shake.linked': + case 'activity.shake.end': + { + const { + id: shakeId, + parent: shakeParent + } = content; + if (shakeParent.id !== id) return; + let seqnce; + if (!(seqnce = result.sequences.get(shakeId))) { + seqnce = []; + result.sequences.set(shakeId, seqnce); + } + seqnce.push({ + ...content, + isLooped: routingKey === 'flow.shake.loop' + }); + break; + } + } + }, { + noAck: true, + consumerTag + }); + for (const a of toShake) a.shake(); + for (const aid of manualShakes) this.getActivityById(aid).shake(); + if (!executing) this._deactivate(); + this.broker.cancel(consumerTag); + return result; +}; ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) { const eventType = message.properties.type; let delegate = true; @@ -464,7 +550,7 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) this._debug(`delegate ${eventType} anonymous event`); } for (const activity of this[kElements].triggeredByEvent) { - if (activity.getStartActivities({ + if (activity.isSubProcess && activity.getStartActivities({ referenceId: content.message?.id, referenceType: eventType }).length) { @@ -481,11 +567,15 @@ ProcessExecution.prototype._onMessageFlowEvent = function onMessageFlowEvent(rou this.broker.publish('message', routingKey, (0, _messageHelper.cloneContent)(message.content), message.properties); }; ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { - if (message.fields.redelivered && message.properties.persistent === false) return; - const content = message.content; + const { + fields, + content, + properties + } = message; + if (fields.redelivered && properties.persistent === false) return; const parent = content.parent = content.parent || {}; - let delegate = message.properties.delegate; - const shaking = message.properties.type === 'shake'; + let delegate = properties.delegate; + const shaking = properties.type === 'shake'; const isDirectChild = content.parent.id === this.id; if (isDirectChild) { parent.executionId = this.executionId; @@ -499,11 +589,11 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe if (delegate) delegate = this._onDelegateEvent(message); this[kTracker].track(routingKey, message); this.broker.publish('event', routingKey, content, { - ...message.properties, + ...properties, delegate, mandatory: false }); - if (shaking) return this._onShookEnd(message); + if (shaking) return this._onShakeMessage(message); if (!isDirectChild) return; switch (routingKey) { case 'process.terminate': @@ -680,13 +770,10 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message const startSequences = this[kElements].startSequences; for (const msg of postponed) { const postponedId = msg.content.id; - const startSequence = startSequences[postponedId]; - if (startSequence) { - if (startSequence.content.sequence.some(({ - id: sid - }) => sid === id)) { - this._getChildApi(msg).discard(); - } + const startSequence = startSequences.get(postponedId); + if (!startSequence) continue; + if (startSequence.has(id)) { + this._getChildApi(msg).discard(); } } } @@ -867,10 +954,29 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { if (child) return child.getApi(message); } }; -ProcessExecution.prototype._onShookEnd = function onShookEnd(message) { - const routingKey = message.fields.routingKey; - if (routingKey !== 'activity.shake.end') return; - this[kElements].startSequences[message.content.id] = (0, _messageHelper.cloneMessage)(message); +ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { + const { + id, + targetId, + isLinked + } = message.content; + let seq = this[kElements].startSequences.get(id); + if (!seq) { + seq = new Set([id]); + this[kElements].startSequences.set(id, seq); + } + if (targetId) { + seq.add(targetId); + } + if (isLinked) { + let linkedSeq = this[kElements].startSequences.get(targetId); + if (!linkedSeq) { + linkedSeq = new Set(seq); + this[kElements].startSequences.set(targetId, linkedSeq); + } else { + linkedSeq.add(targetId); + } + } }; ProcessExecution.prototype._debug = function debugMessage(logMessage) { this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); diff --git a/src/activity/Activity.js b/src/activity/Activity.js index b713e546..eb61ff26 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -94,6 +94,7 @@ function Activity(Behaviour, activityDef, context) { isTransaction: activityDef.isTransaction, isParallelJoin, isThrowing: activityDef.isThrowing, + isCatching: activityDef.isCatching, lane: activityDef.lane?.id, }; this[kExec] = new Map(); @@ -193,6 +194,11 @@ Object.defineProperties(Activity.prototype, { return this[kFlags].isThrowing; }, }, + isCatching: { + get() { + return this[kFlags].isCatching; + }, + }, isForCompensation: { get() { return this[kFlags].isForCompensation; diff --git a/src/definition/DefinitionExecution.js b/src/definition/DefinitionExecution.js index 858f780a..ed6cc178 100644 --- a/src/definition/DefinitionExecution.js +++ b/src/definition/DefinitionExecution.js @@ -1,4 +1,3 @@ -import getPropertyValue from '../getPropertyValue.js'; import { DefinitionApi } from '../Api.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, cloneMessage, pushParent, cloneParent } from '../messageHelper.js'; @@ -511,7 +510,7 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, const delegate = message.properties.delegate; if (delegate && this.id === message.content.id) { - const referenceId = getPropertyValue(message, 'content.message.id'); + const referenceId = message.content.message?.id; this._startProcessesByMessage({ referenceId, referenceType: messageType }); } diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 2bab8d06..e0e0c176 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -1,4 +1,3 @@ -import getPropertyValue from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; @@ -28,7 +27,26 @@ export default function LinkEventDefinition(activity, eventDefinition) { const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(reference.linkName)}-q`; this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); + broker.subscribeTmp('api', `activity.shake.${reference.referenceType}`, this._onApiMessage.bind(this), { noAck: true }); } else { + broker.subscribeTmp( + 'event', + 'activity.shake.start', + (_, msg) => { + broker.publish( + 'event', + `activity.shake.${reference.referenceType}`, + cloneContent(msg.content, { sourceId: this.id, targetId: undefined, message: { ...this.reference } }), + { type: 'shake', delegate: true } + ); + }, + { + noAck: true, + consumerTag: '_link-parent-shake', + priority: 1000, + } + ); + broker.subscribeTmp('event', 'activity.discard', this._onDiscard.bind(this), { noAck: true, consumerTag: '_link-parent-discard', @@ -104,15 +122,13 @@ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessag }; LinkEventDefinition.prototype._onCatchLink = function onCatchLink(routingKey, message) { - if (getPropertyValue(message, 'content.message.linkName') !== this.reference.linkName) return; + if (message.content.message?.linkName !== this.reference.linkName) return; if (message.content.state === 'discard') return this._discard(); return this._complete('caught', message.content.message); }; LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { - const messageType = message.properties.type; - - switch (messageType) { + switch (message.properties.type) { case 'discard': { return this._discard(); } @@ -120,6 +136,15 @@ LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, this._stop(); break; } + case 'shake': { + if (message.content.message?.linkName !== this.reference.linkName) return; + + const content = cloneContent(message.content, { targetId: this.id, isLinked: true }); + content.sequence = content.sequence || []; + content.sequence.push({ id: this.id, type: this.type }); + + return this.broker.publish('event', 'activity.shake.linked', content, { persistent: false, type: 'shake' }); + } } }; diff --git a/src/events/IntermediateCatchEvent.js b/src/events/IntermediateCatchEvent.js index 40b0e674..a8b1d012 100644 --- a/src/events/IntermediateCatchEvent.js +++ b/src/events/IntermediateCatchEvent.js @@ -5,7 +5,7 @@ import { cloneContent } from '../messageHelper.js'; const kExecution = Symbol.for('execution'); export default function IntermediateCatchEvent(activityDef, context) { - return new Activity(IntermediateCatchEventBehaviour, activityDef, context); + return new Activity(IntermediateCatchEventBehaviour, { ...activityDef, isCatching: true }, context); } export function IntermediateCatchEventBehaviour(activity) { diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 924a0df6..0dc8026a 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -128,7 +128,15 @@ ProcessExecution.prototype.resume = function resume() { const { startActivities, detachedActivities, postponed, parallelJoins } = this[kElements]; if (startActivities.size > 1 || parallelJoins.size) { - for (const a of startActivities) a.shake(); + const result = this._shakeElements(); + if (this.environment.settings.skipDiscard !== result.settings.skipDiscard) { + this.environment.settings.skipDiscard = result.settings.skipDiscard; + this._debug( + !result.settings.skipDiscard + ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` + : 'forced shake' + ); + } } postponed.clear(); @@ -461,7 +469,7 @@ ProcessExecution.prototype._activate = function activate() { priority: 200, }); if (activity.isStart) startActivities.add(activity); - if (activity.triggeredByEvent) triggeredByEvent.add(activity); + if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); if (activity.isParallelJoin) parallelJoins.add(activity); } @@ -514,7 +522,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { }, sequences: new Map(), }; - const joins = new Set(); + const manualShakes = new Set(); const consumerTag = `_shaker-${this.executionId}`; this.broker.subscribeTmp( @@ -522,10 +530,18 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { '*.shake.*', (routingKey, { content }) => { switch (routingKey) { + case 'activity.shake.link': { + for (const a of this[kElements].triggeredByEvent) { + if (!a.isCatching) continue; + a.broker.publish('api', routingKey, cloneContent(content), { type: 'shake' }); + } + break; + } case 'activity.shake.join': - joins.add(content.join); + manualShakes.add(content.join); result.settings.skipDiscard = false; case 'flow.shake.loop': + case 'activity.shake.linked': case 'activity.shake.end': { const { id: shakeId, parent: shakeParent } = content; if (shakeParent.id !== id) return; @@ -544,7 +560,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { ); for (const a of toShake) a.shake(); - for (const joinId of joins) this.getActivityById(joinId).shake(); + for (const aid of manualShakes) this.getActivityById(aid).shake(); if (!executing) this._deactivate(); this.broker.cancel(consumerTag); @@ -564,7 +580,7 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) } for (const activity of this[kElements].triggeredByEvent) { - if (activity.getStartActivities({ referenceId: content.message?.id, referenceType: eventType }).length) { + if (activity.isSubProcess && activity.getStartActivities({ referenceId: content.message?.id, referenceType: eventType }).length) { delegate = false; activity.run(content.message); } @@ -599,7 +615,7 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe this[kTracker].track(routingKey, message); this.broker.publish('event', routingKey, content, { ...properties, delegate, mandatory: false }); - if (shaking) return this._onShookEnd(message); + if (shaking) return this._onShakeMessage(message); if (!isDirectChild) return; switch (routingKey) { @@ -994,8 +1010,8 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { } }; -ProcessExecution.prototype._onShookEnd = function onShookEnd(message) { - const { id, targetId } = message.content; +ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { + const { id, targetId, isLinked } = message.content; let seq = this[kElements].startSequences.get(id); if (!seq) { @@ -1005,6 +1021,16 @@ ProcessExecution.prototype._onShookEnd = function onShookEnd(message) { if (targetId) { seq.add(targetId); } + + if (isLinked) { + let linkedSeq = this[kElements].startSequences.get(targetId); + if (!linkedSeq) { + linkedSeq = new Set(seq); + this[kElements].startSequences.set(targetId, linkedSeq); + } else { + linkedSeq.add(targetId); + } + } }; ProcessExecution.prototype._debug = function debugMessage(logMessage) { diff --git a/test/feature/ad-hoc-subprocess-feature.js b/test/feature/ad-hoc-subprocess-feature.js index 8032acec..c42f65e0 100644 --- a/test/feature/ad-hoc-subprocess-feature.js +++ b/test/feature/ad-hoc-subprocess-feature.js @@ -5,7 +5,7 @@ import factory from '../helpers/factory.js'; Feature('Ad-hoc subprocess', () => { Scenario('Running ad-hoc subprocess', () => { let context, definition; - Given('a process mathching feature', async () => { + Given('a process matching feature', async () => { const source = factory.resource('ad-hoc-subprocess.bpmn'); context = await testHelpers.context(source); }); diff --git a/test/feature/linking-feature.js b/test/feature/linking-feature.js index 30a3904c..5011dfc6 100644 --- a/test/feature/linking-feature.js +++ b/test/feature/linking-feature.js @@ -39,238 +39,248 @@ Feature('Linking', () => { }); }); - Scenario('Link in discard flow', () => { - let definition; - const logBook = []; - Given('a decision desides if an intermediate catch event is discarded', async () => { - const source = ` - - - - - - - - - \${environment.variables.condition} - - - - - - - - - - - - - - - - - - - - `; - const context = await testHelpers.context(source); - - definition = new Definition(context, { - services: { - log(...args) { - logBook.push(...args); - }, - }, - }); - }); - - let end; - When('definition is ran with the decision to discard', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was discarded', () => { - expect(definition.getActivityById('throw').counters).to.have.property('discarded', 1); - expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); - }); - - And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); - expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); - }); - - Given('decision changes to take', () => { - definition.environment.variables.condition = true; - }); - - When('definition is ran again', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was taken', () => { - expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); - expect(definition.getActivityById('throw').counters).to.have.property('discarded', 1); - }); - - And('catch event was taken', () => { - expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); - }); - }); - - Scenario('Stop and resume', () => { - let context, definition; - Given('a user is asked to take decision if an intermediate catch event is discarded or not', async () => { - const source = ` - - - - - - - - - \${environment.output.condition} - - - - - - - - - - - - - - - - `; - - context = await testHelpers.context(source, { - extensions: { js: JsExtension }, + [false, true].forEach((skipDiscard) => { + describe(`run with skipDiscard=${skipDiscard}`, () => { + Scenario('Link in discard flow', () => { + let definition; + const logBook = []; + Given('a decision decides if an intermediate catch event is discarded', async () => { + const source = ` + + + + + + + + + \${environment.variables.condition} + + + + + + + + + + + + + + + + + + + + `; + const context = await testHelpers.context(source); + + definition = new Definition(context, { + settings: { + skipDiscard, + }, + services: { + log(...args) { + logBook.push(...args); + }, + }, + }); + }); + + let end; + When('definition is ran with the decision to discard', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was discarded', () => { + expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); + expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); + }); + + And('catch event was discarded', () => { + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); + }); + + Given('decision changes to take', () => { + definition.environment.variables.condition = true; + }); + + When('definition is ran again', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + }); }); - definition = new Definition(context, { - extensions: { - js: JsExtension.extension, - }, + Scenario('Stop and resume', () => { + let context, definition; + Given('a user is asked to take decision if an intermediate catch event is discarded or not', async () => { + const source = ` + + + + + + + + + \${environment.output.condition} + + + + + + + + + + + + + + + + `; + + context = await testHelpers.context(source, { + extensions: { js: JsExtension }, + }); + + definition = new Definition(context, { + settings: { + skipDiscard, + }, + extensions: { + js: JsExtension.extension, + }, + }); + }); + + let wait, end; + When('definition is ran', () => { + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + definition.run(); + }); + + let user; + Then('definition waits for user to decide', async () => { + user = await wait; + expect(user).to.have.property('id', 'start'); + }); + + And('throw event is waiting as well', () => { + expect(definition.getActivityById('catch')).to.have.property('isRunning', true); + }); + + Given('execution is stopped', () => { + definition.stop(); + }); + + When('resumed', () => { + definition.resume(); + }); + + And('user takes decision to discard', () => { + user.signal(false); + }); + + Then('definition completes', () => { + return end; + }); + + And('throw event was discarded', () => { + expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); + expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); + }); + + And('catch event was discarded', () => { + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); + }); + + When('definition is ran again', () => { + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition waits for user to decide', async () => { + user = await wait; + expect(user).to.have.property('id', 'start'); + }); + + And('throw event is waiting as well', () => { + expect(definition.getActivityById('catch')).to.have.property('isRunning', true); + }); + + Given('execution is stopped', () => { + definition.stop(); + }); + + let state; + And('state is saved', () => { + state = definition.getState(); + }); + + When('definition is recovered and resumed', () => { + definition = new Definition(context, { + extensions: { + js: JsExtension.extension, + }, + }).recover(JSON.parse(JSON.stringify(state))); + + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + + definition.resume(); + }); + + Then('definition waits for user to decide', async () => { + user = await wait; + expect(user).to.have.property('id', 'start'); + }); + + When('user takes decision to proceed', () => { + user.signal(true); + }); + + Then('definition completes', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + }); }); }); - - let wait, end; - When('definition is ran', () => { - wait = definition.waitFor('wait'); - end = definition.waitFor('end'); - definition.run(); - }); - - let user; - Then('definition waits for user to decide', async () => { - user = await wait; - expect(user).to.have.property('id', 'start'); - }); - - And('throw event is waiting as well', () => { - expect(definition.getActivityById('catch')).to.have.property('isRunning', true); - }); - - Given('execution is stopped', () => { - definition.stop(); - }); - - When('resumed', () => { - definition.resume(); - }); - - And('user takes decision to discard', () => { - user.signal(false); - }); - - Then('definition completes', () => { - return end; - }); - - And('throw event was discarded', () => { - expect(definition.getActivityById('throw').counters).to.have.property('discarded', 1); - expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); - }); - - And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); - expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); - }); - - When('definition is ran again', () => { - wait = definition.waitFor('wait'); - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition waits for user to decide', async () => { - user = await wait; - expect(user).to.have.property('id', 'start'); - }); - - And('throw event is waiting as well', () => { - expect(definition.getActivityById('catch')).to.have.property('isRunning', true); - }); - - Given('execution is stopped', () => { - definition.stop(); - }); - - let state; - And('state is saved', () => { - state = definition.getState(); - }); - - When('definition is recovered and resumed', () => { - definition = new Definition(context, { - extensions: { - js: JsExtension.extension, - }, - }).recover(JSON.parse(JSON.stringify(state))); - - wait = definition.waitFor('wait'); - end = definition.waitFor('end'); - - definition.resume(); - }); - - Then('definition waits for user to decide', async () => { - user = await wait; - expect(user).to.have.property('id', 'start'); - }); - - When('user takes decision to proceed', () => { - user.signal(true); - }); - - Then('definition completes', () => { - return end; - }); - - And('throw event was taken', () => { - expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); - expect(definition.getActivityById('throw').counters).to.have.property('discarded', 1); - }); - - And('catch event was taken', () => { - expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); - }); }); }); diff --git a/test/feature/stopAndResume-feature.js b/test/feature/stop-and-resume-feature.js similarity index 100% rename from test/feature/stopAndResume-feature.js rename to test/feature/stop-and-resume-feature.js diff --git a/test/feature/sub-process-feature.js b/test/feature/sub-process-feature.js index faba66e0..e28b79cc 100644 --- a/test/feature/sub-process-feature.js +++ b/test/feature/sub-process-feature.js @@ -147,7 +147,7 @@ Feature('Sub-process', () => { Scenario('SubProcess with sequential loop characteristics with loopback so that it runs again', () => { let context, definition; - Given('a process mathching feature', async () => { + Given('a process matching feature', async () => { const source = factory.resource('misp-loopback.bpmn'); context = await testHelpers.context(source); }); @@ -155,6 +155,9 @@ Feature('Sub-process', () => { let leave; When('running definition with instruction to loop back', () => { definition = new Definition(context, { + settings: { + skipDiscard: true, + }, variables: { cardinality: 10, loopback: true, @@ -172,7 +175,6 @@ Feature('Sub-process', () => { const sub = definition.getActivityById('sub'); expect(sub.counters).to.have.property('taken', 2); - expect(sub.execution).to.not.be.ok; expect(sub.broker.consumerCount, 'broker.consumerCount').to.equal(3); }); @@ -189,14 +191,13 @@ Feature('Sub-process', () => { const sub = definition.getActivityById('sub'); expect(sub.counters).to.have.property('taken', 4); - expect(sub.execution).to.not.be.ok; expect(sub.broker.consumerCount, 'broker.consumerCount').to.equal(3); }); }); Scenario('SubProcess with parallel loop characteristics with loopback', () => { let context, definition; - Given('a process mathching feature', async () => { + Given('a process matching feature', async () => { const source = factory.resource('misp-parallel-loopback.bpmn'); context = await testHelpers.context(source); }); @@ -281,8 +282,8 @@ Feature('Sub-process', () => { And('sub process is taken twice', () => { sub = definition.getActivityById('sub'); - expect(sub.counters).to.have.property('discarded', 1); expect(sub.counters).to.have.property('taken', 2); + expect(sub.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); }); And('leaves no lingering references', () => { @@ -376,7 +377,7 @@ Feature('Sub-process', () => { And('sub process was taken twice and discarded once by gateway', () => { sub = definition.getActivityById('sub'); expect(sub.counters).to.have.property('taken', 2); - expect(sub.counters).to.have.property('discarded', 1); + expect(sub.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); }); And('leaves no lingering references', () => { diff --git a/test/helpers/testHelpers.js b/test/helpers/testHelpers.js index d20935b9..113ee4e0 100644 --- a/test/helpers/testHelpers.js +++ b/test/helpers/testHelpers.js @@ -51,9 +51,10 @@ async function context(source, ...args) { return result; }, {}); + const { settings, ...otherOptions } = options; const ctx = Context( serializer, - new Environment({ Logger, scripts: new Scripts(), settings: { enableDummyService: true }, ...options, extensions }) + new Environment({ Logger, scripts: new Scripts(), settings: { enableDummyService: true, ...settings }, ...otherOptions, extensions }) ); logger.debug('context complete'); if (callback) { diff --git a/test/resources/misp-loopback.bpmn b/test/resources/misp-loopback.bpmn index cc40cb16..fca57192 100644 --- a/test/resources/misp-loopback.bpmn +++ b/test/resources/misp-loopback.bpmn @@ -1,5 +1,5 @@ - + @@ -28,8 +28,7 @@ to-subscript to-subend - -next(null, environment.variables.content.index) + next(null, environment.variables.content.index) to-subend @@ -60,6 +59,10 @@ next(null, loopback); + + + + @@ -69,28 +72,24 @@ next(null, loopback); - - - - - - - + + + + + + + - - - - From 9ee69e0bfbb2994335f5aea25e31302649c18cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Fri, 14 Nov 2025 05:53:44 +0100 Subject: [PATCH 05/31] refactor converging parallel gateway --- .github/workflows/build.yaml | 2 +- .github/workflows/release.yaml | 2 +- CHANGELOG.md | 12 +- docs/ParallelGateway.md | 4 + package.json | 2 +- src/Environment.js | 4 +- src/Tracker.js | 1 + src/activity/Activity.js | 52 +- src/activity/ActivityExecution.js | 5 +- src/definition/Definition.js | 2 +- src/eventDefinitions/LinkEventDefinition.js | 1 + src/flows/SequenceFlow.js | 29 +- src/gateways/ParallelGateway.js | 259 +++++++- src/process/ProcessExecution.js | 154 ++--- test/feature/BoundaryEvent-feature.js | 13 +- test/feature/Process-feature.js | 75 +-- test/feature/activity-status-feature.js | 8 +- test/feature/environment-feature.js | 8 +- test/feature/gateway-feature.js | 8 +- test/feature/issues/issue-39-feature.js | 10 +- test/feature/issues/issues-feature.js | 49 +- test/feature/linking-feature.js | 324 +++++++++- test/feature/messaging-feature.js | 4 +- test/feature/outbound-flows-feature.js | 2 +- test/feature/parallel-gateway-feature.js | 195 +++++- test/feature/parallel-gateway-fork-feature.js | 567 ++++++++++++++++++ test/feature/shake-feature.js | 49 +- test/feature/skip-discard-feature.js | 43 +- test/helpers/setup.js | 2 +- test/helpers/testHelpers.js | 5 + .../resources/fork-inbound-with-loopback.bpmn | 211 +++++++ .../fork-inbound-with-pre-inbound.bpmn | 209 +++++++ test/resources/fork-inbound.bpmn | 200 ++++++ .../issue-42-same-target-sequence-flows.bpmn | 32 +- test/resources/join-inbound.bpmn | 44 +- test/resources/join-paradox-1.bpmn | 119 ++-- test/resources/join-paradox-2.bpmn | 262 ++++++++ .../join-paradox-3-with-loopback.bpmn | 196 ++++++ test/resources/join-paradox-3.bpmn | 156 +++++ test/resources/join-paradox-4.bpmn | 157 +++++ test/resources/join-paradox-5.bpmn | 180 ++++++ test/resources/link-to-bypass-logic.bpmn | 169 ++++++ .../link-to-bypass-parallel-join.bpmn | 169 ++++++ test/resources/link-to-parallel-join.bpmn | 165 +++++ .../multiple-links-to-bypass-logic.bpmn | 215 +++++++ .../parallel-converging-execution.bpmn | 286 +++++++++ test/resources/parallel-join-edgecase.bpmn | 90 +-- test/resources/wait-activities.bpmn | 40 +- test/tasks/ServiceTask-test.js | 8 +- types/types.d.ts | 2 +- 50 files changed, 4390 insertions(+), 411 deletions(-) create mode 100644 test/feature/parallel-gateway-fork-feature.js create mode 100644 test/resources/fork-inbound-with-loopback.bpmn create mode 100644 test/resources/fork-inbound-with-pre-inbound.bpmn create mode 100644 test/resources/fork-inbound.bpmn create mode 100644 test/resources/join-paradox-2.bpmn create mode 100644 test/resources/join-paradox-3-with-loopback.bpmn create mode 100644 test/resources/join-paradox-3.bpmn create mode 100644 test/resources/join-paradox-4.bpmn create mode 100644 test/resources/join-paradox-5.bpmn create mode 100644 test/resources/link-to-bypass-logic.bpmn create mode 100644 test/resources/link-to-bypass-parallel-join.bpmn create mode 100644 test/resources/link-to-parallel-join.bpmn create mode 100644 test/resources/multiple-links-to-bypass-logic.bpmn create mode 100644 test/resources/parallel-converging-execution.bpmn diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 04dc54cb..9e089bd6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -14,7 +14,7 @@ jobs: node-version: [18, 20, 22, 24, latest] steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a9dc6c52..f42f20bc 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,7 +13,7 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index bf1ab13f..71e695b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,21 @@ ## Unreleased +## v18.0.0 - 2026-01-14 + +Refactor parallel converging and forking gateways. + ### Breaking -- IntermediateCatchEvent cannot be used as a starting element, or it can, but will not be started by default +- parallel gateways now enters execution as soon as first nbound sequence flow is touched +- shake sequence has changed +- IntermediateCatchEvent cannot be used as a starting element, or it can but will not be started by default ### Additions -- new activity readonly property `isParallelJoin` indicating a parallel joun gateway +- fix link event definition shaking +- activity readonly property `isParallelJoin` indicating a parallel converging gateway +- new activity event published when parallel gateway is executed, namely `activity.converge` ## v17.3.0 - 2025-12-03 diff --git a/docs/ParallelGateway.md b/docs/ParallelGateway.md index 2845a549..65d18684 100644 --- a/docs/ParallelGateway.md +++ b/docs/ParallelGateway.md @@ -24,3 +24,7 @@ Both behaviour comes with the same caveat. The success of the above example is depending on how the sequence flows are ordered in the source (XML). If the flow `default` comes before `take` or `discard` the process will stall. The default flow will publish a discard initializing the join gateway. As soon as either `take` or `discard` is touched the join gateway will consider the join fulfilled and continue. Thus, the second `task` outbound flow will initiate a new join. But in vain since no more flow actions will come from `decision` gateway. The process has stalled. But, if the `default` is placed at after `take` or `discard` in the source, both of them will manage to touch the `toJoin` flow before the `default` flow is touched. + +## Events + +- `activity.converge`: The converging parallel gateway is collecting inbound and monitoring peers diff --git a/package.json b/package.json index 718c915d..24f2ca55 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "chronokinesis": "^7.0.0", "debug": "^4.3.4", "eslint": "^9.0.0", - "globals": "^16.0.0", + "globals": "^17.0.0", "mocha": "^11.0.1", "mocha-cakes-2": "^3.3.0", "moddle-context-serializer": "^4.2.1", diff --git a/src/Environment.js b/src/Environment.js index 80372cb1..b8656a56 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -89,12 +89,14 @@ Environment.prototype.assignVariables = function assignVariables(newVars) { }; Environment.prototype.assignSettings = function assignSettings(newSettings) { - if (!newSettings || typeof newSettings !== 'object') return; + if (!newSettings || typeof newSettings !== 'object') return this; this.settings = { ...this.settings, ...newSettings, }; + + return this; }; Environment.prototype.getScript = function getScript(...args) { diff --git a/src/Tracker.js b/src/Tracker.js index f1608e2e..74aab53c 100644 --- a/src/Tracker.js +++ b/src/Tracker.js @@ -29,6 +29,7 @@ ActivityTracker.prototype.track = function track(routingKey, message) { this._executing(executionId); break; case 'activity.execution.outbound.take': + case 'activity.converge': case 'activity.detach': case 'activity.call': case 'activity.wait': { diff --git a/src/activity/Activity.js b/src/activity/Activity.js index eb61ff26..2e592443 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -70,7 +70,8 @@ function Activity(Behaviour, activityDef, context) { } const outboundSequenceFlows = context.getOutboundSequenceFlows(id); - const isParallelJoin = activityDef.isParallelGateway && inboundSequenceFlows.length > 1; + const inboundSourceIds = new Set(inboundSequenceFlows.map(({ sourceId }) => sourceId)); + const isParallelJoin = activityDef.isParallelGateway && inboundSourceIds.size > 1; this[kFlows] = { inboundSequenceFlows, @@ -93,6 +94,7 @@ function Activity(Behaviour, activityDef, context) { attachedTo, isTransaction: activityDef.isTransaction, isParallelJoin, + isParallelGateway: activityDef.isParallelGateway, isThrowing: activityDef.isThrowing, isCatching: activityDef.isCatching, lane: activityDef.lane?.id, @@ -100,7 +102,8 @@ function Activity(Behaviour, activityDef, context) { this[kExec] = new Map(); this[kMessageHandlers] = { - onInbound: isParallelJoin ? this._onJoinInbound.bind(this) : this._onInbound.bind(this), + // onInbound: isParallelJoin ? this._onJoinInbound.bind(this) : this._onInbound.bind(this), + onInbound: this._onInbound.bind(this), onRunMessage: this._onRunMessage.bind(this), onApiMessage: this._onApiMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this), @@ -244,6 +247,11 @@ Object.defineProperties(Activity.prototype, { return new Map(this[kFlows].inboundSourceIds); }, }, + initialized: { + get() { + return !!this[kExec]?.get('initExecutionId'); + }, + }, }); Activity.prototype.activate = function activate() { @@ -258,7 +266,7 @@ Activity.prototype.deactivate = function deactivate() { this.removeInboundListeners(); broker.cancel('_run-on-inbound'); broker.cancel('_format-consumer'); - if (this.isParallelJoin) this[kFlows].inboundSourceIds = new Map(this[kFlows].inboundSequenceFlows.map(({ sourceId }) => [sourceId, 0])); + // if (this.isParallelJoin) this[kFlows].inboundSourceIds = new Map(this[kFlows].inboundSequenceFlows.map(({ sourceId }) => [sourceId, 0])); }; Activity.prototype.init = function init(initContent) { @@ -313,7 +321,7 @@ Activity.prototype.getState = function getState() { Activity.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running activity <${this.id}>`); - if (!state) return; + if (!state) return; // TODO: return this this.stopped = state.stopped; this.status = state.status; @@ -469,7 +477,8 @@ Activity.prototype._discardRun = function discardRun() { }; Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { - if (this.isParallelJoin) { + // if (this.isParallelJoin) { + if (this[kFlags].isParallelGateway) { const message = cloneMessage(sourceMessage, { join: this.id }); message.content.sequence.push({ id: this.id, type: this.type }); return this.broker.publish('event', 'activity.shake.join', message.content, { @@ -483,10 +492,13 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { const message = cloneMessage(sourceMessage); - message.content.sequence = message.content.sequence || []; - message.content.sequence.push({ id: this.id, type: this.type }); + const sequence = (message.content.sequence = message.content.sequence || []); + const count = 1; + const looped = sequence?.find((f) => f.id === this.id); - this.broker.publish('event', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); + sequence.push({ id: this.id, type: this.type, count: looped ? looped.count + 1 : count }); + + this.broker.publish('api', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); if (this[kFlags].isEnd) { return this.broker.publish('event', 'activity.shake.end', cloneContent(message.content), { persistent: false, type: 'shake' }); @@ -512,10 +524,6 @@ Activity.prototype._consumeInbound = function consumeInbound() { const inboundQ = this.broker.getQueue('inbound-q'); const onInbound = this[kMessageHandlers].onInbound; - if (this[kFlags].isParallelJoin) { - return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound', prefetch: 1000 }); - } - return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); }; @@ -540,7 +548,9 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { case 'activity.discard': { let discardSequence; if (content.discardSequence) discardSequence = content.discardSequence.slice(); - return this._runDiscard({ inbound, discardSequence }); + const context = { inbound, discardSequence }; + // return this.isParallelJoin ? this.run(context) : this._runDiscard(context); + return this[kFlags].isParallelGateway ? this.run(context) : this._runDiscard(context); } } }; @@ -548,11 +558,17 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { Activity.prototype._onJoinInbound = function onJoinInbound(routingKey, message) { const { inboundJoinFlows, inboundSourceIds } = this[kFlows]; - const expectedInboundCount = [...inboundSourceIds.values()].reduce((s, a) => s + (a || 1)); + let expectedInboundCount = 0; + for (const [, a] of inboundSourceIds) { + expectedInboundCount += a || 0; + } + + // const expectedInboundCount = [...inboundSourceIds.values()].reduce((s, a) => s + (a || 1), 0); inboundJoinFlows.add(message); const remaining = expectedInboundCount - inboundJoinFlows.size; + if (remaining) { return this.logger.debug(`<${this.id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`); } @@ -624,6 +640,7 @@ Activity.prototype._pauseRunQ = function pauseRunQ() { Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, messageProperties) { switch (routingKey) { + case 'run.execute.passthrough': case 'run.outbound.discard': case 'run.outbound.take': case 'run.next': @@ -809,6 +826,10 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, return this._ackRunExecuteMessage(); }); } + case 'execution.inbound.cancel': { + message.ack(); + return this.broker.cancel('_run-on-inbound'); + } case 'execution.error': { this.status = 'error'; broker.publish('run', 'run.error', content, { correlationId }); @@ -816,10 +837,11 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, break; } case 'execution.cancel': - case 'execution.discard': + case 'execution.discard': { this.status = 'discarded'; broker.publish('run', 'run.discarded', content, { correlationId }); break; + } default: { this.status = 'executed'; broker.publish('run', 'run.end', content, { correlationId }); diff --git a/src/activity/ActivityExecution.js b/src/activity/ActivityExecution.js index 4efb47f4..451b9adf 100644 --- a/src/activity/ActivityExecution.js +++ b/src/activity/ActivityExecution.js @@ -249,7 +249,7 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete const { executionId, keep, isRootScope } = message.content; if (!isRootScope) { - this._debug('completed sub execution'); + this._debug('completed sub execution', executionId); if (!keep) message.ack(); if (postponed.size === 1) { const onlyMessage = postponed.values().next().value; @@ -365,9 +365,8 @@ ActivityExecution.prototype._debug = function debug(logMessage, executionId) { }; function getExecuteMessage(message) { - const result = cloneMessage(message, { + return cloneMessage(message, { ...(message.fields.redelivered && { isRecovered: true }), ignoreIfExecuting: undefined, }); - return result; } diff --git a/src/definition/Definition.js b/src/definition/Definition.js index c9163123..64553c04 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -28,7 +28,7 @@ export function Definition(context, options) { let environment; if (options) { - environment = this.environment = context.environment.clone(options); + environment = this.environment = context.environment.clone(options).assignSettings(options.settings); this.context = context.clone(environment); } else { environment = this.environment = context.environment; diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index e0e0c176..546cae8e 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -13,6 +13,7 @@ export default function LinkEventDefinition(activity, eventDefinition) { this.type = type; const reference = (this.reference = { + id: behaviour.name, linkName: behaviour.name, referenceType: 'link', }); diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index ce6513cc..1539bf99 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -60,7 +60,7 @@ SequenceFlow.prototype.take = function take(content) { SequenceFlow.prototype.discard = function discard(content = {}) { const sequenceId = content?.sequenceId ?? getUniqueId(this.id); - const discardSequence = (content.discardSequence = (content.discardSequence || []).slice()); + const discardSequence = (content.discardSequence = content.discardSequence?.slice() || []); if (discardSequence.indexOf(this.targetId) > -1) { ++this[kCounters].looped; this.logger.debug(`<${this.id}> discard loop detected <${this.sourceId}> -> <${this.targetId}>. Stop.`); @@ -100,22 +100,27 @@ SequenceFlow.prototype.stop = function stop() { }; SequenceFlow.prototype.shake = function shake(message) { - const content = cloneContent(message.content, { sourceId: this.sourceId, targetId: this.targetId }); + const content = cloneContent(message.content); + content.sequence = content.sequence || []; - const hasCondition = !!this.behaviour.conditionExpression; - content.sequence.push({ id: this.id, type: this.type, isSequenceFlow: true, hasCondition, targetId: this.targetId }); + + const info = { + id: this.id, + type: this.type, + isSequenceFlow: true, + sourceId: this.sourceId, + targetId: this.targetId, + }; if (content.id === this.targetId) { + content.sequence.push(info); return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); + } else if (content.sequence?.find((f) => f.id === this.id)) { + return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); + } else { + content.sequence.push(info); + this.broker.publish('event', 'flow.shake', content, { persistent: false, type: 'shake' }); } - - for (const s of message.content.sequence || []) { - if (s.id === this.id) { - return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); - } - } - - this.broker.publish('event', 'flow.shake', content, { persistent: false, type: 'shake' }); }; SequenceFlow.prototype.getCondition = function getCondition() { diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index 50271756..1126429f 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -1,17 +1,260 @@ import Activity from '../activity/Activity.js'; -import { cloneContent } from '../messageHelper.js'; +import { cloneContent, cloneMessage } from '../messageHelper.js'; + +const STATE_MONTITORING = 'monitoring'; +const STATE_SETUP = 'setup'; + +const kPeers = Symbol.for('peers'); +const kInboundSourceIds = Symbol.for('inbound peers'); +const kTargets = Symbol.for('targets'); +const kExecuteMessage = Symbol.for('executeMessage'); export default function ParallelGateway(activityDef, context) { - return new Activity(ParallelGatewayBehaviour, { ...activityDef, isParallelGateway: true }, context); + const activity = new Activity(ParallelGatewayBehaviour, { ...activityDef, isParallelGateway: true }, context); + + const id = (this.id = activity.id); + + activity.broker.cancel('_api-shake'); + activity.broker.subscribeTmp('api', 'activity.shake.continue', onApiShake, { noAck: true, consumerTag: '_api-shake', priority: 1000 }); + + const peers = (activity[kPeers] = new Map(activity.inbound.map(({ id: flowId, sourceId }) => [flowId, new Set([sourceId])]))); + + return activity; + + function onApiShake(_, message) { + const collect = new Set(); + + let sequenceFlow; + for (const s of message.content.sequence) { + if (s.isSequenceFlow) { + sequenceFlow = s; + } else if (s.id === id) { + const peer = peers.get(sequenceFlow.id); + for (const c of collect) { + peer.add(c); + } + collect.clear(); + } else { + collect.add(s.id); + } + } + + activity.logger.debug(`<${activity.id}> collected parallel gateway peers`); + + activity.shake(message); + } } export function ParallelGatewayBehaviour(activity) { - const { id, type, broker } = activity; - this.id = id; - this.type = type; - this.broker = broker; + this.id = activity.id; + this.type = activity.type; + this.activity = activity; + this.broker = activity.broker; + this.inbound = new Set(); + + this.isConverging = new Set(activity.inbound.map(({ sourceId }) => sourceId)).size > 1; + this[kExecuteMessage] = undefined; } -ParallelGatewayBehaviour.prototype.execute = function execute({ content }) { - this.broker.publish('execution', 'execute.completed', cloneContent(content)); +Object.defineProperties(ParallelGatewayBehaviour.prototype, { + executionId: { + get() { + return this[kExecuteMessage]?.content.executionId; + }, + }, +}); + +ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { + const routingKey = executeMessage.fields.routingKey; + const isRedelivered = executeMessage.fields.redelivered; + const executeContent = executeMessage.content; + + if (executeContent.isRootScope) { + this[kExecuteMessage] = executeMessage; + + switch (routingKey) { + case 'execute.start': { + if (!isRedelivered && executeContent.state === STATE_SETUP && !this.peerMonitor.isRunning) { + return this._complete(); + } + if (executeContent.state !== 'start' && !isRedelivered) { + return; + } + return this.setup(executeMessage); + } + } + } +}; + +ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { + const peerIds = new Set([...this.activity[kPeers].values()].map((v) => [...v]).flat()); + this[kTargets] = new Map([...peerIds].map((pid) => [pid, this.activity.getActivityById(pid)])); + + this.peerMonitor = new PeerMonitor(this.activity, this.activity[kInboundSourceIds], this[kTargets]); + + const message = (this[kExecuteMessage] = cloneMessage(executeMessage)); + const executeContent = message.content; + const { executionId } = executeContent; + + this.inbound.add(cloneContent(executeMessage.content.inbound[0])); + + this.broker.subscribeOnce('api', `activity.stop.${executionId}`, () => this._stop(), { + consumerTag: '_api-stop-execution', + }); + + this.broker.subscribeTmp('execution', 'execute.completed', this._onExecuteMessage.bind(this), { + noAck: true, + consumerTag: '_parallel-execution-execute-tag', + }); + + this.peerMonitor.execute(message); + + const inboundQ = this.broker.getQueue('inbound-q'); + inboundQ.consume( + (_, inboundMessage) => { + this.inbound.add(inboundMessage); + + message.content.inbound.push(cloneContent(inboundMessage.content)); + + this.peerMonitor.execute(message); + }, + { consumerTag: '_converging-inbound', exclusive: true, prefetch: 10000 } + ); + + this.broker.publish('event', 'activity.converge', cloneContent(executeContent)); + + return this.broker.publish( + 'execution', + 'execute.start', + cloneContent(executeMessage.content, { preventComplete: true, state: STATE_SETUP }) + ); +}; + +ParallelGatewayBehaviour.prototype._onExecuteMessage = function onExecuteMessage(routingKey, message) { + this.activity.logger.debug(`<${this.executionId} (${this.id})> received completed from <${message.content.id}>`); + if (this.peerMonitor._onCompleteMessage(routingKey, message)) { + return this._complete(); + } +}; + +ParallelGatewayBehaviour.prototype._complete = function complete() { + const take = this.peerMonitor.inbound.some(({ action }) => action === 'take'); + + this.broker.cancel('_converging-inbound', false); + + this._stop(); + + const state = take ? 'completed' : 'discard'; + + this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring with state: ${state}`); + + const content = cloneContent(this[kExecuteMessage].content, { isRootScope: true, state }); + content.inbound = this.peerMonitor.inbound; + + return this.broker.publish('execution', `execute.${state}`, content); +}; + +ParallelGatewayBehaviour.prototype._stop = function stop() { + this.broker.cancel('_converging-inbound'); + this.broker.cancel('_api-stop-execution'); + this.broker.cancel('_parallel-execution-execute-tag'); + this.peerMonitor.stop(); +}; + +function PeerMonitor(activity, peers, targets) { + this.activity = activity; + this.id = activity.id; + this.broker = activity.broker; + this.running = 0; + this.index = 0; + this.discarded = 0; + this.running = new Map(); + this.watching = new Map(); + this.peers = peers; + this.targets = targets; + this.touched = new Set(); + this.inbound = []; +} + +Object.defineProperty(PeerMonitor.prototype, 'isRunning', { + get() { + return this.running.size > 0; + }, +}); + +PeerMonitor.prototype.execute = function execute(executeMessage) { + const message = cloneMessage(executeMessage); + const inbound = message.content.inbound.pop(); + this.inbound.push(cloneContent(inbound)); + + this.activity.logger.debug(`<${executeMessage.content.executionId} (${this.id})> start monitoring inbound <${inbound.id}> peers`); + + this.activity.broker.publish('execution', 'execute.start', { + ...cloneContent(executeMessage.content), + inbound: this.inbound.slice(), + state: STATE_MONTITORING, + preventComplete: true, + }); + + this.touched.add(inbound.sourceId); + + for (const target of this.targets.values()) { + if (target.status || target.initialized) this.monitor(target); + } + + return this.running.size; +}; + +PeerMonitor.prototype.monitor = function monitor(peerActivity) { + if (this.running.has(peerActivity.id)) return; + + this.activity.logger.debug(`<${this.id}> monitor <${peerActivity.id}> with status: ${peerActivity.status}`); + + this.running.set(peerActivity.id, peerActivity); + + this.broker.publish('execution', 'execute.start', { + id: this.id, + peerId: peerActivity.id, + executionId: peerActivity.executionId, + isRootScope: false, + }); + + peerActivity.broker.createShovel( + `_on-leave-${this.id}`, + { + exchange: 'event', + pattern: 'activity.leave', + }, + { + broker: this.broker, + exchange: 'execution', + exchangeKey: 'execute.completed', + publishProperties: { + monitor: true, + }, + }, + { + cloneMessage(sourceMessage) { + return cloneMessage(sourceMessage, { isRootScope: false, preventComplete: true }); + }, + } + ); +}; + +PeerMonitor.prototype._onCompleteMessage = function onCompleteMessage(_routingKey, message) { + const peerActivity = this.running.get(message.content.id); + peerActivity.broker.closeShovel(`_on-leave-${this.id}`); + this.running.delete(message.content.id); + + for (const target of this.targets.values()) { + if (target.status || target.initialized) this.monitor(target); + } + + return !this.running.size; +}; + +PeerMonitor.prototype.stop = function stop() { + for (const peerActivity of this.running.values()) { + peerActivity.broker.closeShovel(`_on-leave-${this.id}`); + } }; diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 0dc8026a..e35bfa39 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -37,7 +37,7 @@ function ProcessExecution(parentActivity, context) { startActivities: new Set(), triggeredByEvent: new Set(), detachedActivities: new Set(), - parallelJoins: new Set(), + convergingGateways: new Set(), startSequences: new Map(), }; @@ -125,18 +125,13 @@ ProcessExecution.prototype.resume = function resume() { this._activate(); - const { startActivities, detachedActivities, postponed, parallelJoins } = this[kElements]; - - if (startActivities.size > 1 || parallelJoins.size) { + const { startActivities, postponed, detachedActivities, convergingGateways } = this[kElements]; + if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); - if (this.environment.settings.skipDiscard !== result.settings.skipDiscard) { - this.environment.settings.skipDiscard = result.settings.skipDiscard; - this._debug( - !result.settings.skipDiscard - ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` - : 'forced shake' - ); - } + const skipDiscard = (this.environment.settings.skipDiscard = result.settings.skipDiscard); + this._debug( + !skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake' + ); } postponed.clear(); @@ -248,54 +243,6 @@ ProcessExecution.prototype.recover = function recover(state) { ProcessExecution.prototype.shake = function shake(fromId) { return Object.fromEntries(this._shakeElements(fromId).sequences); - // let executing = true; - // const id = this.id; - // if (!this.isRunning) { - // executing = false; - // this.executionId = getUniqueId(id); - // this._activate(); - // } - // const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; - - // const result = { - // settings: { - // skipDiscard: this.environment.settings.skipDiscard, - // }, - // }; - // const joins = new Set(); - // const consumerTag = `_shaker-${this.executionId}`; - - // this.broker.subscribeTmp( - // 'event', - // '*.shake.*', - // (routingKey, { content }) => { - // switch (routingKey) { - // case 'activity.shake.join': - // joins.add(content.join); - // result.settings.skipDiscard = false; - // case 'flow.shake.loop': - // case 'activity.shake.end': { - // const { id: shakeId, parent: shakeParent } = content; - // if (shakeParent.id !== id) return; - - // result[shakeId] = result[shakeId] || []; - // result[shakeId].push({ ...content, isLooped: routingKey === 'flow.shake.loop' }); - // break; - // } - // } - // }, - // { noAck: true, consumerTag } - // ); - - // for (const a of toShake) a.shake(); - // for (const joinId of joins) this.getActivityById(joinId).shake(); - - // console.log('---------------------------', result); - - // if (!executing) this._deactivate(); - // this.broker.cancel(consumerTag); - - // return result; }; ProcessExecution.prototype.stop = function stop() { @@ -390,14 +337,12 @@ ProcessExecution.prototype._start = function start() { this.broker.publish(this._exchangeName, 'execute.start', cloneContent(executeContent)); - const { startActivities, postponed, detachedActivities, parallelJoins } = this[kElements]; - if (startActivities.size > 1 || parallelJoins.size) { + const { startActivities, postponed, detachedActivities, convergingGateways } = this[kElements]; + if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); - this.environment.settings.skipDiscard = result.settings.skipDiscard; + const skipDiscard = (this.environment.settings.skipDiscard = result.settings.skipDiscard); this._debug( - !result.settings.skipDiscard - ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` - : 'forced shake' + !skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake' ); } @@ -430,7 +375,8 @@ ProcessExecution.prototype._activate = function activate() { }); } - const { outboundMessageFlows, flows, associations, startActivities, triggeredByEvent, parallelJoins, children } = this[kElements]; + const { outboundMessageFlows, flows, associations, startActivities, startSequences, triggeredByEvent, convergingGateways, children } = + this[kElements]; for (const flow of outboundMessageFlows) { flow.activate(); @@ -468,9 +414,17 @@ ProcessExecution.prototype._activate = function activate() { consumerTag: '_process-activity-consumer', priority: 200, }); - if (activity.isStart) startActivities.add(activity); + if (activity.isStart) { + startActivities.add(activity); + } if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); - if (activity.isParallelJoin) parallelJoins.add(activity); + if (activity.isParallelJoin) convergingGateways.add(activity); + } + + if (startActivities.size > 1) { + for (const activity of startActivities) { + startSequences.set(activity.id, new Set()); + } } this[kActivated] = true; @@ -522,13 +476,16 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { }, sequences: new Map(), }; - const manualShakes = new Set(); + + const convergingGateways = new Map(); const consumerTag = `_shaker-${this.executionId}`; this.broker.subscribeTmp( 'event', '*.shake.*', (routingKey, { content }) => { + if (content.parent.id !== this.id) return; + switch (routingKey) { case 'activity.shake.link': { for (const a of this[kElements].triggeredByEvent) { @@ -537,9 +494,15 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { } break; } - case 'activity.shake.join': - manualShakes.add(content.join); - result.settings.skipDiscard = false; + case 'activity.shake.join': { + const join = convergingGateways.get(content.join); + if (!join) { + convergingGateways.set(content.join, content); + } else { + join.sequence = join.sequence.concat(content.sequence); + } + break; + } case 'flow.shake.loop': case 'activity.shake.linked': case 'activity.shake.end': { @@ -560,9 +523,18 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { ); for (const a of toShake) a.shake(); - for (const aid of manualShakes) this.getActivityById(aid).shake(); + + for (const [aid, c] of convergingGateways.entries()) { + this._debug(`manual shake of converging gateway <${aid}>`); + this.getActivityById(aid).broker.publish('api', 'activity.shake.continue', c, { type: 'shake' }); + } + + if (result.settings.skipDiscard && convergingGateways.size) { + result.settings.skipDiscard = false; + } if (!executing) this._deactivate(); + this.broker.cancel(consumerTag); return result; @@ -758,7 +730,13 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message this._stateChangeMessage(message, false); if (message.fields.redelivered) return message.ack(); - const { id, type, isEnd } = message.content; + const { id, type, isEnd, isParallelGateway } = message.content; + + if (isParallelGateway) { + for (const inb of message.content.inbound) { + this._popPostponed(inb)?.ack(); + } + } const { postponed, detachedActivities, startActivities } = this[kElements]; const postponedCount = postponed.size; @@ -770,7 +748,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message } message.ack(); - this._debug(`left <${id}> (${type}), pending activities ${postponedCount}`); + this._debug(`left <${id}> (${type}), pending activities ${postponedCount} ${[...postponed].map((m) => m.content.id)}`); if (postponedCount && postponedCount === detachedActivities.size) { return this[kActivityQ].queueMessage( @@ -1011,25 +989,13 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { }; ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { - const { id, targetId, isLinked } = message.content; - - let seq = this[kElements].startSequences.get(id); - if (!seq) { - seq = new Set([id]); - this[kElements].startSequences.set(id, seq); - } - if (targetId) { - seq.add(targetId); - } + if (message.fields.routingKey !== 'activity.shake.end') return; + let seq; + if (!(seq = this[kElements].startSequences.get(message.content.id))) return; - if (isLinked) { - let linkedSeq = this[kElements].startSequences.get(targetId); - if (!linkedSeq) { - linkedSeq = new Set(seq); - this[kElements].startSequences.set(targetId, linkedSeq); - } else { - linkedSeq.add(targetId); - } + for (const s of message.content.sequence) { + if (s.isSequenceFlow) continue; + seq.add(s.id); } }; diff --git a/test/feature/BoundaryEvent-feature.js b/test/feature/BoundaryEvent-feature.js index f985c47b..5b5235c3 100644 --- a/test/feature/BoundaryEvent-feature.js +++ b/test/feature/BoundaryEvent-feature.js @@ -1,5 +1,5 @@ import testHelpers from '../helpers/testHelpers.js'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; Feature('BoundaryEvent', () => { Scenario('task with boundary event followed by a join', () => { @@ -36,6 +36,7 @@ Feature('BoundaryEvent', () => { }); Scenario('user task with interrupting boundary event followed by a join', () => { + /** @type {import('bpmn-elements').Process} */ let bp; Given('a process', async () => { const source = ` @@ -48,7 +49,7 @@ Feature('BoundaryEvent', () => { - + @@ -108,7 +109,7 @@ Feature('BoundaryEvent', () => { }); And('user task was taken', () => { - expect(bp.getActivityById('task').counters).to.have.property('discarded', 1); + expect(bp.getActivityById('task').counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); expect(bp.getActivityById('task').counters).to.have.property('taken', 1); }); @@ -278,7 +279,7 @@ Feature('BoundaryEvent', () => { }); And('end was discarded', () => { - expect(bp.getActivityById('end').counters).to.have.property('discarded', 1); + expect(bp.getActivityById('end').counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); expect(bp.getActivityById('end').counters).to.have.property('taken', 0); }); @@ -300,7 +301,7 @@ Feature('BoundaryEvent', () => { }); And('init task is discarded', () => { - expect(initTask.counters).to.have.property('discarded', 1); + expect(initTask.counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); expect(initTask.counters).to.have.property('taken', 2); }); @@ -311,7 +312,7 @@ Feature('BoundaryEvent', () => { And('end was taken', () => { expect(bp.getActivityById('end').counters).to.have.property('taken', 1); - expect(bp.getActivityById('end').counters).to.have.property('discarded', 1); + expect(bp.getActivityById('end').counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); }); And('process completes', () => { diff --git a/test/feature/Process-feature.js b/test/feature/Process-feature.js index 08cc42ba..717d4b35 100644 --- a/test/feature/Process-feature.js +++ b/test/feature/Process-feature.js @@ -240,7 +240,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -249,7 +249,7 @@ Feature('Process', () => { processInstance.broker.subscribeTmp( 'event', 'process.#', - (routingKey, message) => { + (_routingKey, message) => { messages.push(message); }, { noAck: true } @@ -258,7 +258,7 @@ Feature('Process', () => { processInstance.broker.subscribeTmp( 'event', 'activity.*', - (routingKey, message) => { + (_routingKey, message) => { messages.push(message); }, { noAck: true } @@ -478,15 +478,15 @@ Feature('Process', () => { }); }); - Scenario('A process with a join', () => { + Scenario('A process with double start and a join', () => { const source = ` - - + + @@ -496,7 +496,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -539,19 +539,20 @@ Feature('Process', () => { assertMessage('activity.enter', 'start1'); assertMessage('activity.start', 'start1'); assertMessage('activity.end', 'start1'); + assertMessage('activity.enter', 'join'); + assertMessage('activity.start', 'join'); + assertMessage('activity.converge', 'join'); assertMessage('activity.leave', 'start1'); assertMessage('activity.enter', 'start2'); assertMessage('activity.start', 'start2'); assertMessage('activity.end', 'start2'); - assertMessage('activity.enter', 'join'); - assertMessage('activity.start', 'join'); + assertMessage('activity.leave', 'start2'); assertMessage('activity.end', 'join'); assertMessage('activity.enter', 'end'); assertMessage('activity.start', 'end'); assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); assertMessage('activity.leave', 'join'); - assertMessage('activity.leave', 'start2'); assertMessage('process.end', 'theProcess'); assertMessage('process.leave', 'theProcess'); }); @@ -587,7 +588,7 @@ Feature('Process', () => { processInstance.broker.subscribeTmp( 'event', 'process.#', - (routingKey, message) => { + (_routingKey, message) => { messages.push(message); }, { noAck: true } @@ -596,7 +597,7 @@ Feature('Process', () => { processInstance.broker.subscribeTmp( 'event', 'activity.*', - (routingKey, message) => { + (_routingKey, message) => { messages.push(message); }, { noAck: true } @@ -625,13 +626,14 @@ Feature('Process', () => { assertMessage('activity.end', 'decision'); assertMessage('activity.enter', 'join'); assertMessage('activity.start', 'join'); + assertMessage('activity.converge', 'join'); + assertMessage('activity.leave', 'decision'); assertMessage('activity.end', 'join'); assertMessage('activity.enter', 'end'); assertMessage('activity.start', 'end'); assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); assertMessage('activity.leave', 'join'); - assertMessage('activity.leave', 'decision'); assertMessage('activity.leave', 'start'); assertMessage('process.end', 'theProcess'); assertMessage('process.leave', 'theProcess'); @@ -645,7 +647,7 @@ Feature('Process', () => { - + PT0.01S @@ -665,7 +667,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -838,6 +840,8 @@ Feature('Process', () => { assertMessage('activity.end', 'start'); assertMessage('activity.enter', 'fork'); assertMessage('activity.start', 'fork'); + assertMessage('activity.converge', 'fork'); + assertMessage('activity.leave', 'start'); assertMessage('activity.end', 'fork'); assertMessage('activity.enter', 'timer'); @@ -852,8 +856,6 @@ Feature('Process', () => { assertMessage('activity.leave', 'fork'); - assertMessage('activity.leave', 'start'); - assertMessage('activity.stop', 'start'); assertMessage('activity.stop', 'fork'); assertMessage('activity.stop', 'timer'); @@ -933,20 +935,22 @@ Feature('Process', () => { }); And('before the timeout event completes', () => { + assertMessage('activity.enter', 'join'); + assertMessage('activity.start', 'join'); + + assertMessage('activity.converge', 'join'); assertMessage('activity.leave', 'immediate'); assertMessage('activity.leave', 'start'); assertMessage('activity.timeout', 'postponed'); assertMessage('activity.end', 'postponed'); - assertMessage('activity.enter', 'join'); - assertMessage('activity.start', 'join'); + assertMessage('activity.leave', 'postponed'); assertMessage('activity.end', 'join'); assertMessage('activity.enter', 'end'); assertMessage('activity.start', 'end'); assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); assertMessage('activity.leave', 'join'); - assertMessage('activity.leave', 'postponed'); }); }); @@ -968,7 +972,7 @@ Feature('Process', () => { const messages = []; let bp, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); bp = context.getProcessById('theProcess'); bp.environment.variables.condition1 = true; assertMessage = AssertMessage(context, messages, true); @@ -1108,20 +1112,22 @@ Feature('Process', () => { }); And('before the timeout event completes', () => { + assertMessage('activity.enter', 'join'); + assertMessage('activity.start', 'join'); + assertMessage('activity.converge', 'join'); + assertMessage('activity.leave', 'immediate'); assertMessage('activity.leave', 'start'); assertMessage('activity.timeout', 'postponed'); assertMessage('activity.end', 'postponed'); - assertMessage('activity.enter', 'join'); - assertMessage('activity.start', 'join'); + assertMessage('activity.leave', 'postponed'); assertMessage('activity.end', 'join'); assertMessage('activity.enter', 'end'); assertMessage('activity.start', 'end'); assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); assertMessage('activity.leave', 'join'); - assertMessage('activity.leave', 'postponed'); expect(messages.length).to.equal(0); }); @@ -1147,6 +1153,9 @@ Feature('Process', () => { assertMessage('activity.enter', 'immediate'); assertMessage('activity.start', 'immediate'); assertMessage('activity.end', 'immediate'); + assertMessage('activity.enter', 'join'); + assertMessage('activity.start', 'join'); + assertMessage('activity.converge', 'join'); api.signal(); }); @@ -1157,19 +1166,17 @@ Feature('Process', () => { assertMessage('activity.catch', 'postponed'); assertMessage('activity.end', 'postponed'); + assertMessage('activity.leave', 'postponed'); }); And('the timeout is discarded and process completes', async () => { await completed; - assertMessage('activity.enter', 'join'); - assertMessage('activity.start', 'join'); assertMessage('activity.end', 'join'); assertMessage('activity.enter', 'end'); assertMessage('activity.start', 'end'); assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); assertMessage('activity.leave', 'join'); - assertMessage('activity.leave', 'postponed'); }); }); @@ -1255,7 +1262,7 @@ Feature('Process', () => { const messages = []; let bp, assertMessage, serviceComplete; Given('a process', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); bp = context.getProcessById('theProcess'); bp.environment.addService('get', get); assertMessage = AssertMessage(context, messages, false); @@ -1389,7 +1396,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage, serviceComplete; Given('a process', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); processInstance.environment.variables.timeout = 'PT1S'; processInstance.environment.addService('get', get); @@ -1540,7 +1547,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage, serviceComplete; Given('a process', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); processInstance.environment.variables.timeout = 'PT1S'; processInstance.environment.addService('get', get); @@ -1669,7 +1676,7 @@ Feature('Process', () => { const messages = []; let context, processInstance, assertMessage; Given('a process with a user task', async () => { - context = await testHelpers.context(source); + context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, false); }); @@ -1753,7 +1760,7 @@ Feature('Process', () => { const messages = []; let context, processInstance, assertMessage; Given('a process', async () => { - context = await testHelpers.context(source); + context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); processInstance.environment.variables.timeout = 'PT1S'; assertMessage = AssertMessage(context, messages, false); @@ -1870,7 +1877,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process with user task and timer', async () => { - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -2126,7 +2133,7 @@ Feature('Process', () => { const messages = []; let context, processInstance, assertMessage; Given('a process with a task and bound timer event both leading to end event', async () => { - context = await testHelpers.context(source); + context = await testHelpers.context(source, { settings: { skipDiscard: false } }); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); diff --git a/test/feature/activity-status-feature.js b/test/feature/activity-status-feature.js index 7591b3be..0422ff2d 100644 --- a/test/feature/activity-status-feature.js +++ b/test/feature/activity-status-feature.js @@ -1,5 +1,5 @@ import * as ck from 'chronokinesis'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; import camunda from '../resources/extensions/CamundaExtension.js'; @@ -189,6 +189,7 @@ Feature('Activity status', () => { postponed, postponed.map(({ id }) => id) ).to.have.length(3); + expect(postponed[0].content).to.have.property('id', 'eventgateway'); expect(postponed[1].content).to.have.property('id', 'tevent'); expect(postponed[2].content).to.have.property('id', 'sevent'); @@ -209,13 +210,14 @@ Feature('Activity status', () => { postponed.length, postponed.map(({ id }) => id) ).to.be.above(1); + expect(postponed[0].content).to.have.property('id', 'utask4'); expect(postponed[1].content).to.have.property('id', 'utask5'); }); And('definition and process activity status is idle', () => { - expect(definition.activityStatus).to.equal('wait'); - expect(definition.execution.processes[0].activityStatus).to.equal('wait'); + expect(definition.execution.processes[0].activityStatus, 'process status').to.equal('wait'); + expect(definition.activityStatus, 'definition status').to.equal('wait'); }); When('first user task is signaled', () => { diff --git a/test/feature/environment-feature.js b/test/feature/environment-feature.js index 5695ba7f..c7ddba33 100644 --- a/test/feature/environment-feature.js +++ b/test/feature/environment-feature.js @@ -54,7 +54,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(task.environment.settings).to.deep.equal({ strict: true }); + expect(task.environment.settings).to.deep.equal({ strict: true, skipDiscard: true }); }); And('differs from definition', () => { @@ -71,7 +71,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(runningBp.environment.settings).to.deep.equal({ strict: true }); + expect(runningBp.environment.settings).to.deep.equal({ strict: true, skipDiscard: true }); }); When('definition completes', () => { @@ -103,7 +103,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(runningBp.environment.settings).to.deep.equal({ strict: false }); + expect(runningBp.environment.settings).to.deep.equal({ strict: false, skipDiscard: true }); }); But('differs from definition', () => { @@ -121,7 +121,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(runningBp.environment.settings).to.deep.equal({ strict: false }); + expect(runningBp.environment.settings).to.deep.equal({ strict: false, skipDiscard: true }); }); When('definition completes', () => { diff --git a/test/feature/gateway-feature.js b/test/feature/gateway-feature.js index fb2274c4..99f14615 100644 --- a/test/feature/gateway-feature.js +++ b/test/feature/gateway-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import nock from 'nock'; @@ -36,7 +36,7 @@ Feature('Gateway', () => { `; - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); definition = new Definition(context); }); @@ -132,7 +132,7 @@ Feature('Gateway', () => { `; - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); definition = new Definition(context); }); @@ -386,7 +386,7 @@ Feature('Gateway', () => { `; - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); definition = new Definition(context); }); diff --git a/test/feature/issues/issue-39-feature.js b/test/feature/issues/issue-39-feature.js index cf3fabf3..490b2a9e 100644 --- a/test/feature/issues/issue-39-feature.js +++ b/test/feature/issues/issue-39-feature.js @@ -74,8 +74,14 @@ Feature('Issue 39 - resolve SequenceFlow expression promise', () => { }); And('discarded default and the other one', () => { - expect(definition.getActivityById('defaultend').counters, 'default').to.deep.equal({ taken: 0, discarded: 1 }); - expect(definition.getActivityById('theotherone').counters, 'the other one').to.deep.equal({ taken: 0, discarded: 1 }); + expect(definition.getActivityById('defaultend').counters, 'default').to.deep.equal({ + taken: 0, + discarded: definition.environment.settings.skipDiscard ? 0 : 1, + }); + expect(definition.getActivityById('theotherone').counters, 'the other one').to.deep.equal({ + taken: 0, + discarded: definition.environment.settings.skipDiscard ? 0 : 1, + }); }); }); }); diff --git a/test/feature/issues/issues-feature.js b/test/feature/issues/issues-feature.js index 86420af4..a6f8a6ec 100644 --- a/test/feature/issues/issues-feature.js +++ b/test/feature/issues/issues-feature.js @@ -57,30 +57,30 @@ Feature('Issues', () => { And('first user task is taken once and discarded twice', () => { expect(task1.counters).to.have.property('taken', 1); - expect(task1.counters).to.have.property('discarded', 2); + expect(task1.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 1 : 2); }); And('second user task is taken once and discarded twice', () => { expect(task2.counters).to.have.property('taken', 1); - expect(task2.counters).to.have.property('discarded', 2); + expect(task2.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); }); And('first decision is taken once and discarded once since discard loop prevents more', () => { const decision = definition.getActivityById('decision1'); expect(decision.counters).to.have.property('taken', 1); - expect(decision.counters).to.have.property('discarded', 1); + expect(decision.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); }); And('second decision is discarded twice', () => { const decision = definition.getActivityById('decision2'); expect(decision.counters).to.have.property('taken', 0); - expect(decision.counters).to.have.property('discarded', 2); + expect(decision.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); }); And('end event is discarded four times', () => { const decision = definition.getActivityById('end'); expect(decision.counters).to.have.property('taken', 0); - expect(decision.counters).to.have.property('discarded', 4); + expect(decision.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 4); }); }); @@ -150,13 +150,13 @@ Feature('Issues', () => { }); And('discarded 4 times', () => { - expect(usertask.counters).to.have.property('discarded', 4); + expect(usertask.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 4); }); And('end event is taken once and discarded twice', () => { const endEvent = recovered.getActivityById('end'); expect(endEvent.counters).to.have.property('taken', 1); - expect(endEvent.counters).to.have.property('discarded', 2); + expect(endEvent.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); }); }); @@ -280,13 +280,13 @@ Feature('Issues', () => { And('user task was discarded once', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 1); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); }); And('end was discarded thrice', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 3); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); }); Given('variables are reset', () => { @@ -328,13 +328,13 @@ Feature('Issues', () => { And('user task was discarded twice', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', 2); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); }); And('end was discarded six times', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', 6); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 6); }); When('definition is recovered with state from first run user task wait', () => { @@ -378,13 +378,13 @@ Feature('Issues', () => { And('user task was discarded once', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 1); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); }); And('end was discarded thrice', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 3); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); }); }); @@ -453,7 +453,7 @@ Feature('Issues', () => { And('user task was discarded twice', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 2); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); }); When('definition is recovered with state from wait', () => { @@ -497,7 +497,7 @@ Feature('Issues', () => { And('user task was discarded twice', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 2); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); }); }); @@ -568,13 +568,13 @@ Feature('Issues', () => { And('user task was discarded once', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 1); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); }); And('end was discarded thrice', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 3); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); }); Given('variables are reset', () => { @@ -616,13 +616,13 @@ Feature('Issues', () => { And('user task was discarded twice', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', 2); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); }); And('end was discarded six times', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', 6); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 6); }); When('definition is recovered with state from first run user task wait', () => { @@ -666,13 +666,13 @@ Feature('Issues', () => { And('user task was discarded once', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 1); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); }); And('end was discarded thrice', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', 3); + expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); }); Given('definition is ran again', () => { @@ -713,7 +713,10 @@ Feature('Issues', () => { }); Then('end event is discarded once', () => { - expect(definition.getActivityById('End').counters).to.deep.equal({ taken: 0, discarded: 1 }); + expect(definition.getActivityById('End').counters).to.deep.equal({ + taken: 0, + discarded: definition.environment.settings.skipDiscard ? 0 : 1, + }); }); }); }); @@ -723,7 +726,7 @@ Feature('Issues', () => { Given('fork two user tasks and then join', async () => { const source = ` - + diff --git a/test/feature/linking-feature.js b/test/feature/linking-feature.js index 5011dfc6..3f2de32d 100644 --- a/test/feature/linking-feature.js +++ b/test/feature/linking-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; import JsExtension from '../resources/extensions/JsExtension.js'; @@ -41,7 +41,8 @@ Feature('Linking', () => { [false, true].forEach((skipDiscard) => { describe(`run with skipDiscard=${skipDiscard}`, () => { - Scenario('Link in discard flow', () => { + Scenario('Link within discard flow', () => { + /** @type {Definition} */ let definition; const logBook = []; Given('a decision decides if an intermediate catch event is discarded', async () => { @@ -133,6 +134,98 @@ Feature('Linking', () => { }); }); + Scenario('Link within discard flow reversed order', () => { + let definition; + const logBook = []; + Given('a decision decides if an intermediate catch event is discarded', async () => { + const source = ` + + + + + + + + + + + + + + + + + + \${environment.variables.condition} + + + + + + + + + + + `; + const context = await testHelpers.context(source); + + definition = new Definition(context, { + settings: { + skipDiscard, + }, + services: { + log(...args) { + logBook.push(...args); + }, + }, + }); + }); + + let end; + When('definition is ran with the decision to discard', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was discarded', () => { + expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); + expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); + }); + + And('catch event was discarded', () => { + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); + }); + + Given('decision changes to take', () => { + definition.environment.variables.condition = true; + }); + + When('definition is ran again', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + }); + }); + Scenario('Stop and resume', () => { let context, definition; Given('a user is asked to take decision if an intermediate catch event is discarded or not', async () => { @@ -281,6 +374,233 @@ Feature('Linking', () => { expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); }); }); + + Scenario('a flow with link event to bypass parallel join', () => { + let context, definition; + Given('a flow with link event definitions and a bypassed parallel gateway', async () => { + const source = factory.resource('link-to-bypass-parallel-join.bpmn'); + + context = await testHelpers.context(source); + + definition = new Definition(context, { + variables: { + condition: true, + }, + settings: { + skipDiscard, + }, + }); + }); + + let end; + When('definition is ran with condition to take link', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + + When('definition is ran with condition to discard link', () => { + end = definition.waitFor('end'); + + definition.environment.variables.condition = false; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); + }); + + Scenario('a flow with link event to complete parallel join', () => { + let context, definition; + Given('a flow matching scenario', async () => { + const source = factory.resource('link-to-parallel-join.bpmn'); + + context = await testHelpers.context(source); + + definition = new Definition(context, { + variables: { + condition: true, + }, + settings: { + skipDiscard, + }, + }); + }); + + let end; + When('definition is ran with condition to take link', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + + When('definition is ran with condition to discard link', () => { + end = definition.waitFor('end'); + + definition.environment.variables.condition = false; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); + }); + + Scenario('a flow with link event to bypass logic', () => { + let context, definition; + Given('a flow with link event definition to bypass major part of logic', async () => { + const source = factory.resource('link-to-bypass-logic.bpmn'); + + context = await testHelpers.context(source); + + definition = new Definition(context, { + variables: { + condition: true, + }, + settings: { + skipDiscard, + }, + }); + }); + + let end; + When('definition is ran with condition to take link', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken once', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + + When('definition is ran with condition to discard link', () => { + end = definition.waitFor('end'); + + definition.environment.variables.condition = false; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken again', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 3); + }); + }); + + Scenario('a flow with multiple link events to bypass logic', () => { + let context, definition; + Given('a flow matching scenario', async () => { + const source = factory.resource('multiple-links-to-bypass-logic.bpmn'); + + context = await testHelpers.context(source); + + definition = new Definition(context, { + variables: { + condition1: true, + }, + settings: { + skipDiscard, + }, + }); + }); + + let end; + When('definition is ran with condition to take link 1', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken once', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + + When('definition is ran with condition to take link 2', () => { + end = definition.waitFor('end'); + + definition.environment.variables.condition1 = false; + definition.environment.variables.condition2 = true; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken again', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); + + When('definition is ran with condition to take both links', () => { + end = definition.waitFor('end'); + + definition.environment.variables.condition1 = true; + definition.environment.variables.condition2 = true; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken twice', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 4); + }); + + When('definition is ran with condition to discard both links', () => { + end = definition.waitFor('end'); + + definition.environment.variables.condition1 = false; + definition.environment.variables.condition2 = false; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken twice', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 6); + }); + }); }); }); }); diff --git a/test/feature/messaging-feature.js b/test/feature/messaging-feature.js index 830d286d..f6fbd782 100644 --- a/test/feature/messaging-feature.js +++ b/test/feature/messaging-feature.js @@ -23,7 +23,7 @@ Feature('Messaging', () => { `; - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); definition = new Definition(context); }); @@ -549,7 +549,7 @@ Feature('Messaging', () => { `; - context = await testHelpers.context(source); + context = await testHelpers.context(source, { settings: { skipDiscard: false } }); definition = new Definition(context); }); diff --git a/test/feature/outbound-flows-feature.js b/test/feature/outbound-flows-feature.js index 332e14bb..34dc659d 100644 --- a/test/feature/outbound-flows-feature.js +++ b/test/feature/outbound-flows-feature.js @@ -8,7 +8,7 @@ Feature('Outbound flows', () => { let definition; Given('a task with one default flow, flow with script condition, and a third with expression', async () => { const source = factory.resource('conditional-flows.bpmn'); - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); definition = new Definition(context); }); diff --git a/test/feature/parallel-gateway-feature.js b/test/feature/parallel-gateway-feature.js index e570deb5..712cc404 100644 --- a/test/feature/parallel-gateway-feature.js +++ b/test/feature/parallel-gateway-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; @@ -6,24 +6,26 @@ const joinSource = factory.resource('join-inbound.bpmn'); Feature('Parallel gateway', () => { Scenario('A process with a parallel join with multiple inbound with some touched more than once', () => { - let context, definition; + let context; + /** @type {Definition} */ + let definition; Given('a definition matching the scenario', async () => { context = await testHelpers.context(joinSource); definition = new Definition(context); }); let leave; - let startMsg; + let endMsg; When('definition is ran', () => { leave = definition.waitFor('leave'); definition.broker.subscribeTmp( 'event', - 'activity.start', + 'activity.end', (_, msg) => { if (msg.content.id === 'join') { definition.broker.cancel(msg.fields.consumerTag); - startMsg = msg; + endMsg = msg; } }, { noAck: true } @@ -46,8 +48,12 @@ Feature('Parallel gateway', () => { expect(joinGw.inbound).to.have.length(4); }); - And('join start message inbound flows is greater then inbound sequence flows', () => { - expect(startMsg.content.inbound).to.have.length(6); + And('join end message inbound flows is greater then inbound sequence flows', () => { + expect(endMsg.content.inbound).to.have.length(6); + }); + + And('no pending inbound exists', () => { + expect(joinGw.broker.getQueue('inbound-q').messageCount).to.equal(0); }); When('ran again', () => { @@ -69,12 +75,90 @@ Feature('Parallel gateway', () => { }); And('join start message inbound flows is greater then inbound sequence flows', () => { - expect(startMsg.content.inbound).to.have.length(6); + expect(endMsg.content.inbound).to.have.length(6); + }); + + let stopped; + let state; + When('ran again with and a listener stopping run when converging gateway has started monitoring', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + + When('ran again with and a listener stopping run when converging gateway emits converging event', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.converge', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway on converge event', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; }); }); - Scenario('Multiple asynchronous tasks joining in parallel join with some inbound touched more than once (not recommended)', () => { - let context, definition; + Scenario('Multiple asynchronous tasks joining in parallel join with some inbound touched more than once', () => { + let context; + /** @type {Definition} */ + let definition; Given('a definition matching the scenario', async () => { context = await testHelpers.context(joinSource, { extensions: { @@ -111,6 +195,7 @@ Feature('Parallel gateway', () => { }); let joinLeavePromise; + let leave; When('definition is ran', () => { joinLeavePromise = new Promise((resolve) => { definition.broker.subscribeTmp( @@ -127,23 +212,97 @@ Feature('Parallel gateway', () => { }); definition.run(); + leave = definition.waitFor('leave'); }); - let joinGw, joinEndMsg; + let joinGw, joinLeaveMsg; Then('parallel join was taken once', async () => { - joinEndMsg = await joinLeavePromise; + joinLeaveMsg = await joinLeavePromise; joinGw = definition.getActivityById('join'); expect(joinGw.counters).to.deep.equal({ taken: 1, discarded: 0 }); }); - But('with unexpected number of inbound', () => { - expect(joinEndMsg.content.inbound).to.have.length(5); + But('with expected number of inbound', () => { + expect(joinLeaveMsg.content.inbound).to.have.length(6); + }); + + And('and no postponed elements', () => { + expect(definition.getPostponed()).to.have.length(0); + }); + + And('run completes', () => { + return leave; + }); + + let stopped; + let state; + When('ran again saving state at converging gateway executing', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'task4') { + definition.broker.cancel(msg.fields.consumerTag); + state = definition.getState(); + definition.stop(); + } + }, + { noAck: true } + ); + + stopped = definition.waitFor('stop'); + definition.run(); + }); + + Then('state is saved', () => { + return stopped; + }); + + When('definition is recovered and resumed from state', () => { + definition = new Definition(context.clone()); + leave = definition.waitFor('leave'); + return definition.recover(state).resume(); }); - And('one sequence flow is pending since parallel join is expecting more inbound', () => { - const postponed = definition.getPostponed(); - expect(postponed).to.have.length(1); - expect(postponed[0]).to.have.property('type', 'bpmn:SequenceFlow'); + Then('recovered run completes', () => { + return leave; + }); + + When('ran again with and a listener stopping run when converging gateway emits converging event', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.converge', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway on converge event', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; }); }); }); diff --git a/test/feature/parallel-gateway-fork-feature.js b/test/feature/parallel-gateway-fork-feature.js new file mode 100644 index 00000000..d7dd1a3d --- /dev/null +++ b/test/feature/parallel-gateway-fork-feature.js @@ -0,0 +1,567 @@ +import { Definition } from 'bpmn-elements'; +import factory from '../helpers/factory.js'; +import testHelpers from '../helpers/testHelpers.js'; + +const forkSource = factory.resource('fork-inbound.bpmn'); +const forkSourceWithLoopback = factory.resource('fork-inbound-with-loopback.bpmn'); +const forkSourceWithPreInbound = factory.resource('fork-inbound-with-pre-inbound.bpmn'); + +Feature('Parallel gateway fork', () => { + Scenario('A process with a parallel fork', () => { + let context; + /** @type {Definition} */ + let definition; + Given('a definition matching the scenario', async () => { + context = await testHelpers.context(forkSource); + definition = new Definition(context, { + services: getTakeServices(), + }); + }); + + let leave; + When('definition is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + let joinGw; + And('parallel join was taken once', () => { + joinGw = definition.getActivityById('join'); + expect(joinGw.counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('has the expected number of inbound flows', () => { + expect(joinGw.inbound).to.have.length(2); + }); + + And('no pending inbound exists', () => { + expect(joinGw.broker.getQueue('inbound-q').messageCount).to.equal(0); + }); + + When('ran again', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + let forkGw; + And('parallel fork was taken again', () => { + forkGw = definition.getActivityById('fork'); + expect(forkGw.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('has the expected number of inbound flows', () => { + expect(forkGw.inbound).to.have.length(1); + }); + + let stopped; + let state; + When('ran again with and a listener stopping run when converging gateway has started monitoring', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + + When('ran again with and a listener stopping run when converging gateway emits converging event', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.converge', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway on converge event', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + }); + + Scenario('A process with a parallel fork that is touched before preceeding join is executed', () => { + let context; + /** @type {Definition} */ + let definition; + Given('a definition matching the scenario', async () => { + context = await testHelpers.context(forkSourceWithPreInbound); + definition = new Definition(context, { + services: getTakeServices(), + }); + }); + + let leave; + When('definition is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + let joinGw; + And('parallel join was taken once', () => { + joinGw = definition.getActivityById('join'); + expect(joinGw.counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('has the expected number of inbound flows', () => { + expect(joinGw.inbound).to.have.length(2); + }); + + And('no pending inbound exists', () => { + expect(joinGw.broker.getQueue('inbound-q').messageCount).to.equal(0); + }); + + When('ran again', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + let forkGw; + And('parallel fork was taken again', () => { + forkGw = definition.getActivityById('fork'); + expect(forkGw.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('has the expected number of inbound flows', () => { + expect(forkGw.inbound).to.have.length(1); + }); + + let stopped; + let state; + When('ran again with and a listener stopping run when converging gateway has started monitoring', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + + When('ran again with and a listener stopping run when converging gateway emits converging event', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.converge', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway on converge event', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + }); + + Scenario('A process with a parallel fork preceeded by a converging gateway surrounded by a loopback', () => { + let context; + /** @type {Definition} */ + let definition; + Given('a definition matching the scenario', async () => { + context = await testHelpers.context(forkSourceWithLoopback); + definition = new Definition(context, { + services: getTakeServices(), + }); + }); + + let leave; + When('definition is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + let forkGw; + And('parallel fork was taken twice', () => { + forkGw = definition.getActivityById('join'); + expect(forkGw.counters).to.deep.equal({ taken: 2, discarded: 1 }); + }); + + let joinGw; + And('parallel join was taken twice', () => { + joinGw = definition.getActivityById('join'); + expect(joinGw.counters).to.deep.equal({ taken: 2, discarded: 1 }); + }); + + And('no pending inbound exists', () => { + expect(joinGw.broker.getQueue('inbound-q').messageCount).to.equal(0); + }); + + When('ran again', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + And('parallel fork was taken twice again', () => { + forkGw = definition.getActivityById('fork'); + expect(forkGw.counters).to.deep.equal({ taken: 4, discarded: 0 }); + }); + + And('parallel join was taken twice again', () => { + joinGw = definition.getActivityById('join'); + expect(joinGw.counters).to.deep.equal({ taken: 4, discarded: 2 }); + }); + + let stopped; + let state; + When('ran again with and a listener stopping run when converging gateway has started monitoring', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + + When('ran again with and a listener stopping run when converging gateway emits converging event', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.converge', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway on converge event', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + }); + + Scenario('Multiple asynchronous tasks joining in parallel join with some inbound touched more than once', () => { + let context; + /** @type {Definition} */ + let definition; + Given('a definition matching the scenario', async () => { + context = await testHelpers.context(forkSourceWithLoopback, { + extensions: { + makeAsync: { + extension(activity) { + if (activity.type !== 'bpmn:Task') return; + + const broker = activity.broker; + const consumerTag = 'make-async'; + return { + activate() { + broker.subscribeTmp( + 'event', + 'activity.start', + () => { + broker.publish('format', 'run.format.onstart', { endRoutingKey: 'run.format.onstart.end' }); + + setImmediate(() => { + broker.publish('format', 'run.format.onstart.end'); + }); + }, + { consumerTag, noAck: true } + ); + }, + deactivate() { + broker.cancel(consumerTag); + }, + }; + }, + }, + }, + }); + definition = new Definition(context, { + services: getTakeServices(), + }); + }); + + let leave; + When('definition is ran', () => { + definition.run(); + leave = definition.waitFor('leave'); + }); + + Then('run completes', () => { + return leave; + }); + + And('join was taken the expected number of times', () => { + const joinGw = definition.getActivityById('join'); + expect(joinGw.counters).to.deep.equal({ taken: 2, discarded: 1 }); + }); + + And('fork was taken the expected number of times', () => { + const forkGw = definition.getActivityById('fork'); + expect(forkGw.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + let stopped; + let state; + When('ran again saving state at converging gateway executing', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'task4') { + definition.broker.cancel(msg.fields.consumerTag); + state = definition.getState(); + definition.stop(); + } + }, + { noAck: true } + ); + + stopped = definition.waitFor('stop'); + definition.run(); + }); + + Then('state is saved', () => { + return stopped; + }); + + When('definition is recovered and resumed from state', () => { + definition = new Definition(context.clone()); + leave = definition.waitFor('leave'); + return definition.recover(state).resume(); + }); + + Then('recovered run completes', () => { + return leave; + }); + + And('join was taken the expected number of times', () => { + const joinGw = definition.getActivityById('join'); + expect(joinGw.counters).to.deep.equal({ taken: 3, discarded: 2 }); + }); + + And('fork was taken the expected number of times', () => { + const forkGw = definition.getActivityById('fork'); + expect(forkGw.counters).to.deep.equal({ taken: 3, discarded: 0 }); + }); + + When('ran again with and a listener stopping run when converging gateway emits converging event', () => { + definition = new Definition(context.clone()); + + definition.broker.subscribeTmp( + 'event', + 'activity.converge', + (_, msg) => { + if (msg.content.id === 'join') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from converging gateway on converge event', () => { + definition = new Definition(context.clone()).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + }); +}); + +function getTakeServices() { + return { + takeFlow() { + return true; + }, + takeOnce({ content, environment }) { + const onceId = `${environment.variables.content.executionId}_${content.id}`; + const count = environment.variables[onceId] ?? 0; + environment.variables[onceId] = count + 1; + return count === 0; + }, + takeTwice({ content, environment }) { + const onceId = `${environment.variables.content.executionId}_${content.id}`; + const count = environment.variables[onceId] ?? 0; + environment.variables[onceId] = count + 1; + return count === 1; + }, + }; +} diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index 48ea9c9e..f5f8789e 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -124,7 +124,6 @@ Feature('Shaking', () => { Then('execution sequence is presented in first start event shake end message', () => { expect(messages).to.have.length(3); - expect(messages[0].content).to.have.property('sequence').that.is.an('array'); const sequence = messages[0].content.sequence; expect(sequence[0]).to.have.property('id', 'start1'); @@ -151,7 +150,8 @@ Feature('Shaking', () => { And('second start event loop sequence is presented in shake loop message', () => { expect(messages[2].content).to.have.property('sequence').that.is.an('array'); const sequence = messages[2].content.sequence; - expect(sequence).to.have.length(8); + + expect(sequence).to.have.length(7); expect(sequence[0]).to.have.property('id', 'start2'); expect(sequence[1]).to.have.property('id', 'from22Task'); expect(sequence[2]).to.have.property('id', 'task'); @@ -159,7 +159,6 @@ Feature('Shaking', () => { expect(sequence[4]).to.have.property('id', 'gateway'); expect(sequence[5]).to.have.property('id', 'back2Task'); expect(sequence[6]).to.have.property('id', 'task'); - expect(sequence[7]).to.have.property('id', 'fromTask2Gateway'); }); let start1, start2; @@ -281,8 +280,7 @@ Feature('Shaking', () => { expect(sequence.sequence[4]).to.have.property('id', 'gateway'); expect(sequence.sequence[5]).to.have.property('id', 'back2Task'); expect(sequence.sequence[6]).to.have.property('id', 'task'); - expect(sequence.sequence[7]).to.have.property('id', 'fromTask2Gateway'); - expect(sequence.sequence).to.have.length(8); + expect(sequence.sequence).to.have.length(7); }); And('event messsages are forwarded from event activity', () => { @@ -306,6 +304,7 @@ Feature('Shaking', () => { expect(sequence.sequence).to.have.length(3); sequence = result.gateway[1]; + expect(sequence.sequence[0]).to.have.property('id', 'gateway'); expect(sequence.sequence[1]).to.have.property('id', 'back2Task'); expect(sequence.sequence[2]).to.have.property('id', 'task'); @@ -551,6 +550,7 @@ Feature('Shaking', () => { And('sub process sequence is included', () => { const subProcess = result.start[0].sequence[2]; + expect(subProcess).to.be.an('object').with.property('sequence').that.is.an('object').with.property('task'); expect(subProcess.sequence.task).to.be.an('array').with.length(1); expect(subProcess.sequence.task[0]).to.have.property('sequence').that.is.an('array').with.length(3); @@ -625,4 +625,43 @@ Feature('Shaking', () => { }); }); }); + + // [ + // 'join-paradox-1.bpmn', + // 'join-paradox-2.bpmn', + // 'join-paradox-3.bpmn', + // 'join-inbound.bpmn', + // 'issue-42-same-target-sequence-flows.bpmn', + // ].forEach((source) => { + // Scenario(`${source} with parallel join gateways should shake as expected`, () => { + // /** @type {Definition} */ + // let definition; + // Given('a process matching scenario', async () => { + // const context = await testHelpers.context(factory.resource(source)); + + // definition = new Definition(context, { + // settings: { skipDiscard: true }, + // variables: { input: 0 }, + // services: { + // takeFlow() { + // return true; + // }, + // takeOnce({ environment }) { + // const count = environment.variables[environment.variables.content.executionId] ?? 0; + // environment.variables[environment.variables.content.executionId] = count + 1; + // return count === 0; + // }, + // }, + // }); + // }); + + // When('shook', () => { + // console.log('---SHAKE', definition.shake()); + // }); + + // Then('join parallel gateway has expected inbound', () => { + // console.log(definition.getProcesses()[0].getActivityById('join').expectedInboundSources); + // }); + // }); + // }); }); diff --git a/test/feature/skip-discard-feature.js b/test/feature/skip-discard-feature.js index 15392d40..a5d41078 100644 --- a/test/feature/skip-discard-feature.js +++ b/test/feature/skip-discard-feature.js @@ -230,8 +230,18 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { }); }); - ['join-inbound.bpmn', 'join-paradox-1.bpmn', 'issue-42-same-target-sequence-flows.bpmn'].forEach((source) => { - Scenario(`${source} with parallel join gateways should complete as expected`, () => { + [ + 'join-paradox-2.bpmn', + 'join-paradox-1.bpmn', + 'join-paradox-3.bpmn', + 'join-paradox-3-with-loopback.bpmn', + 'join-paradox-4.bpmn', + 'join-paradox-5.bpmn', + 'join-inbound.bpmn', + 'issue-42-same-target-sequence-flows.bpmn', + 'parallel-join-edgecase.bpmn', + ].forEach((source) => { + Scenario(`${source} with parallel converging gateways should complete as expected`, () => { /** @type {Definition} */ let definition; Given('a process matching scenario', async () => { @@ -247,11 +257,23 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { takeFlow() { return true; }, + takeOnce({ content, environment }) { + const onceId = `${environment.variables.content.executionId}_${content.id}`; + const count = environment.variables[onceId] ?? 0; + environment.variables[onceId] = count + 1; + return count === 0; + }, + takeTwice({ content, environment }) { + const onceId = `${environment.variables.content.executionId}_${content.id}`; + const count = environment.variables[onceId] ?? 0; + environment.variables[onceId] = count + 1; + return count === 1; + }, }, }); }); - And('a listener for wait immediately signalling or discarding if touched more than trice', () => { + And('a listener for wait immediately signalling or discarding if touched more than thrice', () => { definition.broker.subscribeTmp( 'event', 'activity.wait', @@ -279,6 +301,17 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { ); }); + And('a guard for infinite loop', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (definition.getActivityById(msg.content.id)?.counters.taken > 5) throw new Error('eternal loop'); + }, + { noAck: true } + ); + }); + let end; When('ran', () => { end = definition.waitFor('end'); @@ -288,10 +321,6 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { Then('run completes', () => { return end; }); - - And('with discarded flows', () => { - expect(discardedFlows.length).to.be.above(0); - }); }); }); }); diff --git a/test/helpers/setup.js b/test/helpers/setup.js index baac7901..d88b1862 100644 --- a/test/helpers/setup.js +++ b/test/helpers/setup.js @@ -1,4 +1,4 @@ import 'chai/register-expect.js'; process.env.NODE_ENV = 'test'; -Error.stackTraceLimit = 20; +Error.stackTraceLimit = 50; diff --git a/test/helpers/testHelpers.js b/test/helpers/testHelpers.js index 113ee4e0..c7299dd4 100644 --- a/test/helpers/testHelpers.js +++ b/test/helpers/testHelpers.js @@ -20,6 +20,11 @@ export default { camundaBpmnModdle, }; +/** + * Context helper + * @param {Buffer|string} source BPMN2 source + * @param {...any} args + */ async function context(source, ...args) { const logger = Logger('test-helpers:context'); diff --git a/test/resources/fork-inbound-with-loopback.bpmn b/test/resources/fork-inbound-with-loopback.bpmn new file mode 100644 index 00000000..55dd8e3e --- /dev/null +++ b/test/resources/fork-inbound-with-loopback.bpmn @@ -0,0 +1,211 @@ + + + + + to-split + + + + to-task1 + back2-task1 + to-task2 + + + + to-task2 + from-task2 + + + + to-task3 + back2-task3 + to-task4 + + + + to-task4 + from-task4 + back2-task3 + + + + + + ${environment.services.takeOnce()} + + + from-task4 + from-task2 + to-task5 + + + to-task5 + back2-task1 + to-fork + + + + ${environment.services.takeOnce()} + + + + to-fork + to-task6 + to-task7 + + + to-task6 + from-task6 + + + + to-task7 + from-task7 + + + + to-end + + + + + to-split + to-task1 + to-task3 + + + + from-task6 + from-task7 + to-end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/fork-inbound-with-pre-inbound.bpmn b/test/resources/fork-inbound-with-pre-inbound.bpmn new file mode 100644 index 00000000..ca101941 --- /dev/null +++ b/test/resources/fork-inbound-with-pre-inbound.bpmn @@ -0,0 +1,209 @@ + + + + + to-split + + + + to-task1 + to-task2 + from-task1 + + + + to-task2 + from-task2 + + + + to-task3 + back2-task3 + to-task4 + + + + to-task4 + from-task4 + back2-task3 + + + + + + ${environment.services.takeOnce()} + + + from-task4 + from-task2 + to-task5 + + + to-task5 + from-task1 + to-fork + + + + + to-fork + to-task6 + to-task7 + + + to-task6 + from-task6 + + + + to-task7 + from-task7 + + + + to-end + + + + + to-split + to-task1 + to-task3 + + + + from-task6 + from-task7 + to-end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/fork-inbound.bpmn b/test/resources/fork-inbound.bpmn new file mode 100644 index 00000000..96d6ada7 --- /dev/null +++ b/test/resources/fork-inbound.bpmn @@ -0,0 +1,200 @@ + + + + + to-split + + + + to-task1 + to-task2 + + + + to-task2 + from-task2 + + + + to-task3 + back2-task3 + to-task4 + + + + to-task4 + from-task4 + back2-task3 + + + + + + ${environment.services.takeOnce()} + + + from-task4 + from-task2 + to-task5 + + + to-task5 + to-fork + + + + + to-fork + to-task6 + to-task7 + + + to-task6 + from-task6 + + + + to-task7 + from-task7 + + + + to-end + + + + + to-split + to-task1 + to-task3 + + + + from-task6 + from-task7 + to-end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/issue-42-same-target-sequence-flows.bpmn b/test/resources/issue-42-same-target-sequence-flows.bpmn index 1860545c..a9597732 100644 --- a/test/resources/issue-42-same-target-sequence-flows.bpmn +++ b/test/resources/issue-42-same-target-sequence-flows.bpmn @@ -1,5 +1,5 @@ - + to-task1 @@ -60,7 +60,7 @@ to-fork from-fork-1 from-fork-2 - from-fork-0 + to-task6 @@ -70,7 +70,7 @@ to-end - + from-task5-1 @@ -97,7 +97,7 @@ - from-fork-0 + to-task6 from-task6 @@ -122,6 +122,9 @@ + + + @@ -129,19 +132,16 @@ - - - + + + - - - @@ -198,13 +198,17 @@ + + + + - + @@ -213,10 +217,6 @@ - - - - @@ -244,4 +244,4 @@ - \ No newline at end of file + diff --git a/test/resources/join-inbound.bpmn b/test/resources/join-inbound.bpmn index 7e8bab78..33318165 100644 --- a/test/resources/join-inbound.bpmn +++ b/test/resources/join-inbound.bpmn @@ -1,25 +1,25 @@ - + - Flow_0jzmhc7 + to-gw1 - - Flow_0jzmhc7 - Flow_173yyzu + + to-gw1 + to-gw2 to-task3 to-split - + - Flow_173yyzu + to-gw2 to-task1 to-task2 - + to-task3 - to-gw-collect + from-task3 ${false} @@ -36,7 +36,7 @@ ${false} - + from-task1 from-task2 @@ -62,26 +62,26 @@ ${true} - + ${true} - + to-split to-task4 to-task5 - Flow_1i3ndql + from-bound-task3 - to-gw-collect - Flow_1i3ndql + from-task3 + from-bound-task3 from-gw-collect - - + + to-task5 from-task5 @@ -125,18 +125,18 @@ - + - + - + @@ -154,7 +154,7 @@ - + @@ -198,7 +198,7 @@ - + diff --git a/test/resources/join-paradox-1.bpmn b/test/resources/join-paradox-1.bpmn index cc13c9af..1c83c032 100644 --- a/test/resources/join-paradox-1.bpmn +++ b/test/resources/join-paradox-1.bpmn @@ -1,5 +1,5 @@ - + to-sub @@ -21,15 +21,15 @@ to-task2 from-task2 - to-task3 + backto-task3 - to-task3 + backto-task3 from-task3 - - ${false} + + ${environment.services.takeOnce()} @@ -50,24 +50,24 @@ to-fork - from-fork-1 - from-fork-2 - to-task5 + from-fork + to-fork-task-2 + to-fork-task1 - from-fork-1 - from-fork-2 - from-fork-task + from-fork + from-fork-task1 + from-fork-task2 to-sub-end - - to-task5 - from-fork-task + + to-fork-task1 + from-fork-task1 - - - - + + + + @@ -76,6 +76,11 @@ + + to-fork-task-2 + from-fork-task2 + + @@ -88,9 +93,6 @@ - - - @@ -112,6 +114,10 @@ + + + + @@ -130,11 +136,7 @@ - - - - - + @@ -142,73 +144,84 @@ + + + + - - - - - - - - - + - - - + + + + + + + - - - - - - - - - - + - + - - + - + - + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/join-paradox-2.bpmn b/test/resources/join-paradox-2.bpmn new file mode 100644 index 00000000..1bda0dd5 --- /dev/null +++ b/test/resources/join-paradox-2.bpmn @@ -0,0 +1,262 @@ + + + + + from-task3 + to-task1 + to-task2 + to-task4 + + + to-task2 + from-task2 + backto-task3 + + + backto-task3 + from-task3 + + + to-task4 + from-task4 + to-task5 + + + to-end + + + from-task2 + from-task4 + from-task5 + to-fork + + + to-fork + from-fork-1 + to-fork-task2 + to-fork-task5 + + + from-fork-1 + from-fork-task1 + from-fork-task2 + to-loopback + + + to-fork-task5 + from-fork-task1 + + + to-task5 + from-task5 + + + to-gw + + + + + + + + ${environment.services.takeOnce()} + + + + + + + + + + + + to-gw + backto-gw + to-task1 + + + + to-loopback + to-end + backto-count-script + + + + ${environment.services.takeOnce()} + + + to-fork-task2 + from-fork-task2 + + + + + backto-count-script + backto-gw + const countId = `${content.parent.executionId}.${content.id}`; +const count = environment.variables[countId] = (environment.variables[countId] || 0)++; + +next(count === 1 ? null : new Error('more than once')); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/join-paradox-3-with-loopback.bpmn b/test/resources/join-paradox-3-with-loopback.bpmn new file mode 100644 index 00000000..95f084cd --- /dev/null +++ b/test/resources/join-paradox-3-with-loopback.bpmn @@ -0,0 +1,196 @@ + + + + + to-run-twice + + + + to-fork + to-task3 + to-task5 + to-task6 + to-task1 + + + to-task3 + from-task3 + + + + to-task5 + from-task5 + + + + to-task6 + from-task6 + + + + from-task3 + from-task5 + from-task6 + from-task4 + + + + + + to-task1 + to-task2 + + + + to-task2 + from-task2 + + + + + + from-task2 + from-task4 + to-end + + + Flow_0j7v9b8 + + + + to-end + Flow_0j7v9b8 + from-loopback + + + + to-run-twice + from-loopback + to-fork + + + + ${environment.services.takeOnce()} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/join-paradox-3.bpmn b/test/resources/join-paradox-3.bpmn new file mode 100644 index 00000000..2ce1a0be --- /dev/null +++ b/test/resources/join-paradox-3.bpmn @@ -0,0 +1,156 @@ + + + + + to-fork + + + + to-fork + to-task3 + to-task5 + to-task6 + to-task1 + + + to-task3 + from-task3 + + + + to-task5 + from-task5 + + + + to-task6 + from-task6 + + + + from-task3 + from-task5 + from-task6 + from-task4 + + + + + + to-task1 + to-task2 + + + + to-task2 + from-task2 + + + + + + from-task2 + from-task4 + to-end + + + to-end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/join-paradox-4.bpmn b/test/resources/join-paradox-4.bpmn new file mode 100644 index 00000000..41445ac7 --- /dev/null +++ b/test/resources/join-paradox-4.bpmn @@ -0,0 +1,157 @@ + + + + + to-fork + + + + to-fork + to-task3 + to-task5 + to-task1 + + + to-task3 + from-task3 + + + + to-task5 + backto-task5 + from-task5 + + + + backto-task6 + backto-task5 + + + from-task3 + from-task5 + from-task4 + backto-task6 + + + + + to-task1 + to-task2 + + + + to-task2 + from-task2 + + + + + + from-task2 + from-task4 + to-end + + + to-end + + + + ${environment.services.takeOnce()} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/join-paradox-5.bpmn b/test/resources/join-paradox-5.bpmn new file mode 100644 index 00000000..a70a7e69 --- /dev/null +++ b/test/resources/join-paradox-5.bpmn @@ -0,0 +1,180 @@ + + + + + to-fork + + + + to-fork + to-task3 + to-task5 + to-task1 + + + to-task3 + from-task3 + to-task3-1 + + + + to-task5 + backto-task5 + from-task5 + + + + backto-task6 + backto-task5 + + + from-task3 + from-task5 + from-task3-1 + from-task4 + backto-task6 + + + + + to-task1 + to-task2 + + + + to-task2 + from-task2 + + + + + + from-task2 + from-task4 + to-end + + + to-end + + + + ${environment.services.takeOnce()} + + + + to-task3-1 + from-task3-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/link-to-bypass-logic.bpmn b/test/resources/link-to-bypass-logic.bpmn new file mode 100644 index 00000000..cf8f5838 --- /dev/null +++ b/test/resources/link-to-bypass-logic.bpmn @@ -0,0 +1,169 @@ + + + + + Flow_05b3201 + + + Flow_05b3201 + Flow_08arx01 + + + + Flow_08arx01 + Flow_18te781 + to-throw-link + + + + Flow_18te781 + Flow_06pnthd + Flow_1docann + + + + Flow_06pnthd + Flow_1loxf70 + + + + Flow_1docann + Flow_1bhj6pc + + + + Flow_1bhj6pc + Flow_0e0fdrh + + + + + + Flow_0ylq3fh + from-catch-link + Flow_0dwk1fj + + + + Flow_0dwk1fj + + + + ${environment.variables.condition} + + + to-throw-link + + + + + from-catch-link + + + + Flow_0e0fdrh + Flow_1loxf70 + Flow_0ylq3fh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/link-to-bypass-parallel-join.bpmn b/test/resources/link-to-bypass-parallel-join.bpmn new file mode 100644 index 00000000..ab36db5e --- /dev/null +++ b/test/resources/link-to-bypass-parallel-join.bpmn @@ -0,0 +1,169 @@ + + + + + Flow_05b3201 + + + Flow_05b3201 + Flow_08arx01 + + + + Flow_08arx01 + Flow_18te781 + to-throw-link + + + + Flow_18te781 + Flow_06pnthd + Flow_1docann + + + + Flow_06pnthd + Flow_1loxf70 + + + + Flow_1docann + Flow_1bhj6pc + + + + Flow_1bhj6pc + Flow_0e0fdrh + + + + + + to-complete-task + from-catch-link + to-end + + + + to-end + + + + ${environment.variables.condition} + + + to-throw-link + + + + + from-catch-link + + + + Flow_0e0fdrh + Flow_1loxf70 + to-complete-task + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/link-to-parallel-join.bpmn b/test/resources/link-to-parallel-join.bpmn new file mode 100644 index 00000000..7c77555f --- /dev/null +++ b/test/resources/link-to-parallel-join.bpmn @@ -0,0 +1,165 @@ + + + + + Flow_05b3201 + + + Flow_05b3201 + Flow_08arx01 + + + + Flow_08arx01 + Flow_18te781 + to-throw-link + + + + Flow_18te781 + Flow_06pnthd + Flow_1docann + + + + Flow_06pnthd + Flow_1loxf70 + + + + Flow_1docann + Flow_1bhj6pc + + + + Flow_1bhj6pc + Flow_0e0fdrh + + + + + + to-complete-task + to-end + + + + to-end + + + + ${environment.variables.condition} + + + to-throw-link + + + + + from-catch-link + + + + Flow_0e0fdrh + Flow_1loxf70 + from-catch-link + to-complete-task + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/multiple-links-to-bypass-logic.bpmn b/test/resources/multiple-links-to-bypass-logic.bpmn new file mode 100644 index 00000000..a0756a60 --- /dev/null +++ b/test/resources/multiple-links-to-bypass-logic.bpmn @@ -0,0 +1,215 @@ + + + + + Flow_05b3201 + + + Flow_05b3201 + Flow_08arx01 + + + + + Flow_18te781 + Flow_06pnthd + Flow_1docann + + + + Flow_06pnthd + Flow_1loxf70 + + + + Flow_1docann + Flow_1bhj6pc + + + + Flow_1bhj6pc + Flow_0e0fdrh + + + + + + Flow_0ylq3fh + from-catch-link-a + from-catch-link-b + to-end + + + + to-end + + + + ${environment.variables.condition1} + + + to-throw-link-a + + + + + from-catch-link-a + + + + Flow_0e0fdrh + Flow_1loxf70 + Flow_0ylq3fh + + + ${environment.variables.condition2} + + + to-throw-link-b + + + + + from-catch-link-b + + + + Flow_08arx01 + Flow_18te781 + to-throw-link-a + to-throw-link-b + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/parallel-converging-execution.bpmn b/test/resources/parallel-converging-execution.bpmn new file mode 100644 index 00000000..187e916a --- /dev/null +++ b/test/resources/parallel-converging-execution.bpmn @@ -0,0 +1,286 @@ + + + + + Flow_15tnji0 + + + + Flow_15tnji0 + Flow_0ofzpge + + Flow_0lsswbd + Flow_1ehr91y + + + Flow_1ehr91y + Flow_0wtons3 + Flow_1jivpm1 + + + Flow_1xbleu8 + Flow_1tzff1u + Flow_0wtons3 + Flow_003cbl3 + + + Flow_003cbl3 + + + + Flow_1epiilt + + + + Flow_1jivpm1 + Flow_1xbleu8 + + + + Flow_1tzff1u + + + + Flow_0qi5sp3 + Flow_0lsswbd + + + Flow_1epiilt + + + + + + + + + + + + Flow_0qi5sp3 + + + + + + Flow_1ql8vqf + + + + + Flow_1ql8vqf + + + + + + Flow_1ltcgbb + Flow_027fq2l + + + Flow_027fq2l + + + + Flow_1ltcgbb + + + + Flow_0ofzpge + + + + Flow_0m5rdao + + + + + Flow_0m5rdao + Flow_1wsmm4q + + + + Flow_1wsmm4q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/parallel-join-edgecase.bpmn b/test/resources/parallel-join-edgecase.bpmn index 7ae4d359..4b34bcd3 100644 --- a/test/resources/parallel-join-edgecase.bpmn +++ b/test/resources/parallel-join-edgecase.bpmn @@ -1,38 +1,38 @@ - + - toDecision + to-decision - - toDecision - toTask2 - toJoin2 - toTask1 + + to-decision + from-decision-2 + from-decision + from-decision-1 - + - toTask2 - toTask1 - toJoin1 + from-decision-2 + from-decision-1 + from-task - + ${true} - + ${false} - + - toJoin2 - toJoin1 - toEnd + from-decision + from-task + to-end - + - toEnd + to-end - + @@ -45,35 +45,23 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + @@ -81,7 +69,22 @@ - + + + + + + + + + + + + + + + + @@ -89,10 +92,7 @@ - - - - + diff --git a/test/resources/wait-activities.bpmn b/test/resources/wait-activities.bpmn index e45d7466..2707c54f 100644 --- a/test/resources/wait-activities.bpmn +++ b/test/resources/wait-activities.bpmn @@ -1,5 +1,5 @@ - + Flow_1ctc6d5 @@ -80,31 +80,31 @@ Flow_0tahxlv Flow_117f3fe - Flow_0r2k43e + to-split - Flow_0kkbnnp - Flow_105w7o1 - Flow_0vvh5as + from-utask5 + from-utask4 + from-split Flow_0fgg8fg - + Flow_19quxxd - Flow_105w7o1 + from-utask4 - + Flow_0qwinoy - Flow_0kkbnnp + from-utask5 - - - - + + + + - Flow_0r2k43e - Flow_0vvh5as + to-split + from-split Flow_19quxxd Flow_0qwinoy @@ -182,9 +182,11 @@ + + @@ -285,21 +287,21 @@ - + - + - + - + diff --git a/test/tasks/ServiceTask-test.js b/test/tasks/ServiceTask-test.js index fb8a5c2a..81c698f9 100644 --- a/test/tasks/ServiceTask-test.js +++ b/test/tasks/ServiceTask-test.js @@ -15,7 +15,7 @@ describe('ServiceTask', () => { `; - const context = await testHelpers.context(source, { settings: { disableDummyService: true } }); + const context = await testHelpers.context(source, { settings: { skipDiscard: false, disableDummyService: true } }); const task = context.getActivityById('task'); let error; @@ -290,7 +290,7 @@ describe('ServiceTask', () => { `; - context = await testHelpers.context(source); + context = await testHelpers.context(source, { settings: { skipDiscard: false } }); context.environment.addService('postMessage', (ctx, next) => { next(null, true); }); @@ -323,7 +323,7 @@ describe('ServiceTask', () => { }); it('error in callback is caught by bound error event', async () => { - context.environment.addService('postMessage', (message, callback) => { + context.environment.addService('postMessage', (_message, callback) => { callback(new Error('Failed')); }); @@ -338,7 +338,7 @@ describe('ServiceTask', () => { }); it('error in callback discards task', async () => { - context.environment.addService('postMessage', (message, callback) => { + context.environment.addService('postMessage', (_message, callback) => { callback(new Error('Failed')); }); diff --git a/types/types.d.ts b/types/types.d.ts index e797f315..3dd12495 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -375,7 +375,7 @@ declare class Environment { recover(state?: EnvironmentState): Environment; clone(overrideOptions?: EnvironmentOptions): Environment; assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): void; + assignSettings(newSettings: Record): Environment; registerScript(activity: any): Script; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; getServiceByName(serviceName: string): CallableFunction; From c626bcfdab1c9c1928ee37bc2de5df8955bba774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 9 May 2026 06:35:21 +0200 Subject: [PATCH 06/31] wip --- .gitignore | 4 + AGENTS.md | 71 +++++++++++++++ package.json | 10 +-- src/activity/Activity.js | 4 +- src/eventDefinitions/LinkEventDefinition.js | 18 +++- src/process/ProcessExecution.js | 3 + test/feature/linking-feature.js | 58 +++++++++++++ test/helpers/services-helper.js | 23 +++++ test/resources/link-basic.bpmn | 96 +++++++++++++++++++++ test/resources/link-event.bpmn | 89 +++++++++++++------ 10 files changed, 342 insertions(+), 34 deletions(-) create mode 100644 AGENTS.md create mode 100644 test/helpers/services-helper.js create mode 100644 test/resources/link-basic.bpmn diff --git a/.gitignore b/.gitignore index d1deff88..e8795bb5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,10 @@ coverage* *.iml .vscode +# Agent files (AGENTS.md is the canonical, agent-agnostic doc) +.claude +CLAUDE.md + # Compiled client resources /public/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..efdbf5e5 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,71 @@ +# AGENTS.md + +This file provides guidance to coding agents (Claude Code, and any tool that reads `AGENTS.md`) when working with code in this repository. + +## Workflow + +- **TDD is the default.** Red → green → refactor: write or adjust a failing test before changing implementation. Don't delete or weaken existing assertions to land a change — extend them. +- **Performance and coverage are the project's USP.** Avoid regressions in either. On hot paths (broker dispatch, flow traversal, activity activation, joins, multi-instance loops), prefer existing `Context` Maps/refs over rebuilt scans, and avoid per-message allocations/closures where they can be hoisted. +- Before declaring done: `npm test` (full suite + lint + `dist` rebuild). For coverage-sensitive work, also `npm run cov:html`. + +## Commands + +- `npm test` — run the full suite in parallel (mocha, `mocha-cakes-2` UI, hot-bev reporter, 3000ms timeout). `posttest` then runs lint and rebuilds `dist/`. +- `npm run lint` — `eslint . --cache && prettier . --check --cache`. +- `npm run dist` — Babel transpile `src/` → `dist/` (also runs on `prepack`). +- `npm run cov:html` — c8 HTML coverage report. +- `npm run test:md` — run texample against code blocks in the documentation markdown files. +- Single test file: `npx mocha test/feature/activity-feature.js`. `.mocharc.json` auto-loads `mocha-cakes-2` and `test/helpers/setup.js` (which registers chai `expect` globally and sets `NODE_ENV=test`). +- Single scenario: add `-g "scenario name"` to the mocha invocation above. +- Note: default mocharc timeout is 1000ms; the `npm test` script bumps it to 3000ms. Long-running scenarios may need `-t 3000` when run standalone. + +## Architecture + +The library executes BPMN 2.0 workflows. The execution model is message-driven — almost nothing happens by direct method call — so this section focuses on what you cannot learn from any single file. + +### Execution hierarchy: Definition → Process → Activity + +Each layer pairs a structural wrapper with a dedicated execution orchestrator: + +- `src/definition/Definition.js` + `src/definition/DefinitionExecution.js` — top-level, manages executable processes and inter-process messaging. +- `src/process/Process.js` + `src/process/ProcessExecution.js` — owns one ``, handles flow traversal, joins, and parallel activation. +- `src/activity/Activity.js` + `src/activity/ActivityExecution.js` — wraps any element (task, event, gateway), tracks postponed/waiting state, drives a per-run behavior instance. + +### Message-driven core via `smqp` + +All coordination is async message passing on an in-memory AMQP-like broker (`smqp`, a runtime dependency). Each element owns its own `EventBroker` (`src/EventBroker.js`) with exchanges named `event`, `run`, `format`, `execution`, and `api`. Per-element factories wire these up: `DefinitionBroker`, `ProcessBroker`, `ActivityBroker`, `MessageFlowBroker`. + +Execution is driven by publishing routing keys like `execute.start`, `execute.completed`, `execute.error`, `run.enter`, `run.end`, `run.discard`, and subscribing via `broker.subscribeTmp()` / `subscribeOnce()`. Messages with `mandatory: true` surface errors if undelivered. The `EventBroker` exposes convenience methods: `on`, `once`, `waitFor`, `emit`, `emitFatal`. If you try to read `ActivityExecution` or `ProcessExecution` as imperative code you will get lost — keep the publish/subscribe model in mind. + +### Activity vs Behaviour + +An element type like `ServiceTask` is not a class. It is a factory function that returns an `Activity` constructed with a `Behaviour` class: + +- `Activity` holds structural info: id, type, inbound/outbound flows, broker, lifecycle state. +- `Behaviour` implements the element-specific `execute(executeMessage)` logic, publishing results back through the broker. + +When an activity is activated, `ActivityExecution` instantiates the Behaviour and calls its `execute`. To replace an element type entirely, supply a new Behaviour — see `docs/Extend.md`. + +### `Context` and `Environment` + +- `src/Context.js` is a per-execution **registry and lazy factory**. It stores activities, flows, and processes in `refs` Maps and instantiates them on first access via `upsertActivity` / `upsertSequenceFlow` / `upsertProcess`. It bridges the parsed moddle context (from `bpmn-moddle` via `moddle-context-serializer`) to runtime instances and wires extensions through `ExtensionsMapper`. Contexts are cheap to clone and are isolated per execution scope. +- `src/Environment.js` holds global execution config: `variables`, injected `services`, `timers`, `Scripts` engine, `expressions`, `Logger` factory, and settings such as `batchSize`. Cloned and merged per Definition. + +### Api objects + +`src/Api.js` produces `ActivityApi` / `ProcessApi` / `DefinitionApi` / `FlowApi`. These are lightweight wrappers over broker messages that event listeners receive (e.g. `definition.on('end', api => …)`). They expose `.signal()`, `.cancel()`, `.fail()`, `.stop()`, `.discard()`, `.resolveExpression()` and serialize running state via `content` and `messageProperties`. + +### Extension models + +Documented in `docs/Extend.md` and `docs/Extension.md`: + +1. **Replace a Behaviour** by passing `{ types: { 'bpmn:StartEvent': MyStartEvent } }` to `Definition`. Use when you need full control over an element's execution. +2. **Non-invasive extension hooks** via `{ extensions: { myExt(activity, context) { … } } }`. Each extension runs once per activity after instantiation and typically attaches listeners or publishes format messages — used for cross-cutting concerns (forms, logging, output capture). + +## Testing patterns + +- Framework: mocha + `mocha-cakes-2` BDD UI. `Feature` / `Scenario` / `Given` / `When` / `Then` / `And` / `But` are globals in test files (declared in `eslint.config.js`). Chai `expect` is registered globally via `test/helpers/setup.js`. +- Layout: scenario-style coverage in `test/feature/*.js`; unit tests mirror the `src/` directory tree (`test/activity`, `test/process`, `test/gateways`, `test/tasks`, `test/eventDefinitions`, `test/flows`, …). +- BPMN sources: raw XML templates in `test/helpers/factory.js` (helpers like `factory.valid()`, `factory.userTask()`, `factory.resource('name')`) plus `.bpmn` files under `test/resources/`. +- Primary helper: `test/helpers/testHelpers.js` — `context(source, options)` parses BPMN via `bpmn-moddle`, serializes via `moddle-context-serializer`, and returns a runtime `Context`. Also exposes `Logger`, `emptyContext`, and `AssertMessage` for asserting broker message sequences. +- `test/helpers/JavaScripts.js` is a mock Scripts engine for isolating ScriptTask tests. diff --git a/package.json b/package.json index 24f2ca55..48a79b36 100644 --- a/package.json +++ b/package.json @@ -90,19 +90,19 @@ "c8": "^10.1.1", "camunda-bpmn-moddle": "^7.0.1", "chai": "^6.2.1", - "chronokinesis": "^7.0.0", + "chronokinesis": "^8.0.0", "debug": "^4.3.4", "eslint": "^9.0.0", "globals": "^17.0.0", "mocha": "^11.0.1", "mocha-cakes-2": "^3.3.0", - "moddle-context-serializer": "^4.2.1", + "moddle-context-serializer": "^5.0.0", "nock": "^14.0.0", "prettier": "^3.2.5", - "texample": "^0.1.0" + "texample": "^1.0.1" }, "dependencies": { - "@0dep/piso": "^3.0.1", - "smqp": "^11.0.1" + "@0dep/piso": "^4.0.0", + "smqp": "^12.0.0" } } diff --git a/src/activity/Activity.js b/src/activity/Activity.js index 2e592443..eca2340b 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -87,7 +87,7 @@ function Activity(Behaviour, activityDef, context) { this[kFlags] = { isEnd: !outboundSequenceFlows.length, - isStart: !inboundTriggers.length && !behaviour.triggeredByEvent, + isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, isMultiInstance: !!behaviour.loopCharacteristics, isForCompensation, @@ -102,7 +102,6 @@ function Activity(Behaviour, activityDef, context) { this[kExec] = new Map(); this[kMessageHandlers] = { - // onInbound: isParallelJoin ? this._onJoinInbound.bind(this) : this._onInbound.bind(this), onInbound: this._onInbound.bind(this), onRunMessage: this._onRunMessage.bind(this), onApiMessage: this._onApiMessage.bind(this), @@ -266,7 +265,6 @@ Activity.prototype.deactivate = function deactivate() { this.removeInboundListeners(); broker.cancel('_run-on-inbound'); broker.cancel('_format-consumer'); - // if (this.isParallelJoin) this[kFlows].inboundSourceIds = new Map(this[kFlows].inboundSequenceFlows.map(({ sourceId }) => [sourceId, 0])); }; Activity.prototype.init = function init(initContent) { diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 546cae8e..ab04ab68 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -26,8 +26,14 @@ export default function LinkEventDefinition(activity, eventDefinition) { if (!isThrowing) { const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(reference.linkName)}-q`; + this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); + + console.log({ messageQueueName, pattern: `*.${reference.referenceType}.#` }); + broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); + broker.consume(messageQueueName, this._onApiMessage.bind(this), { consumerTag: '_start-link-catch' }); + broker.subscribeTmp('api', `activity.shake.${reference.referenceType}`, this._onApiMessage.bind(this), { noAck: true }); } else { broker.subscribeTmp( @@ -123,12 +129,16 @@ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessag }; LinkEventDefinition.prototype._onCatchLink = function onCatchLink(routingKey, message) { + console.log('--------------------------'); + if (message.content.message?.linkName !== this.reference.linkName) return; if (message.content.state === 'discard') return this._discard(); return this._complete('caught', message.content.message); }; LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { + console.log('CATCH', { [this.id]: routingKey, ...message.properties }); + switch (message.properties.type) { case 'discard': { return this._discard(); @@ -137,6 +147,10 @@ LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, this._stop(); break; } + case 'link': { + console.log(message.content); + break; + } case 'shake': { if (message.content.message?.linkName !== this.reference.linkName) return; @@ -178,8 +192,8 @@ LinkEventDefinition.prototype._discard = function discard() { }; LinkEventDefinition.prototype._stop = function stop() { - const broker = this.broker, - executionId = this.executionId; + const broker = this.broker; + const executionId = this.executionId; broker.cancel(`_api-link-${executionId}`); broker.cancel(`_api-parent-${executionId}`); broker.cancel(`_api-${executionId}`); diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index e35bfa39..59283eeb 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -891,6 +891,9 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou for (const child of this[kElements].children) { if (child.placeholder) continue; + + console.log({ [child.id]: routingKey }); + child.broker.publish('api', routingKey, cloneContent(message.content), message.properties); if (consumed && !continueOnConsumed) break; } diff --git a/test/feature/linking-feature.js b/test/feature/linking-feature.js index 3f2de32d..abbcea08 100644 --- a/test/feature/linking-feature.js +++ b/test/feature/linking-feature.js @@ -2,6 +2,7 @@ import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; import JsExtension from '../resources/extensions/JsExtension.js'; +import { getTakeServices } from '../helpers/services-helper.js'; Feature('Linking', () => { Scenario('Link intermediate throw event & link intermediate catch event', () => { @@ -41,6 +42,63 @@ Feature('Linking', () => { [false, true].forEach((skipDiscard) => { describe(`run with skipDiscard=${skipDiscard}`, () => { + Scenario('basic link event definition', () => { + /** @type {Definition} */ + let definition; + Given('a flow matching scenario', async () => { + const source = factory.resource('link-basic.bpmn'); + const context = await testHelpers.context(source); + + definition = new Definition(context, { + settings: { + skipDiscard, + }, + services: getTakeServices(), + }); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + Given('decision changes to take', () => { + definition.environment.variables.condition = true; + }); + + When('definition is ran again', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + }); + }); + Scenario('Link within discard flow', () => { /** @type {Definition} */ let definition; diff --git a/test/helpers/services-helper.js b/test/helpers/services-helper.js new file mode 100644 index 00000000..c132c12b --- /dev/null +++ b/test/helpers/services-helper.js @@ -0,0 +1,23 @@ +/** + * Get take conditional sequence flow services + * @returns services to use in conditional sequence flows + */ +export function getTakeServices() { + return { + takeFlow() { + return true; + }, + takeOnce({ content, environment }) { + const onceId = `${environment.variables.content.executionId}_${content.id}`; + const count = environment.variables[onceId] ?? 0; + environment.variables[onceId] = count + 1; + return count === 0; + }, + takeTwice({ content, environment }) { + const onceId = `${environment.variables.content.executionId}_${content.id}`; + const count = environment.variables[onceId] ?? 0; + environment.variables[onceId] = count + 1; + return count === 1; + }, + }; +} diff --git a/test/resources/link-basic.bpmn b/test/resources/link-basic.bpmn new file mode 100644 index 00000000..709d1fca --- /dev/null +++ b/test/resources/link-basic.bpmn @@ -0,0 +1,96 @@ + + + + + Flow_1l06o3o + + + Flow_1l06o3o + Flow_0nezlgs + Flow_011w5tr + + + + ${true} + + + Flow_0nezlgs + + + + Flow_011w5tr + Flow_1j0pk3d + + + + Flow_132srsk + + + + Flow_132srsk + Flow_1qj9tz9 + + + + Flow_1qj9tz9 + + + + Flow_1j0pk3d + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/link-event.bpmn b/test/resources/link-event.bpmn index aafb1ce3..80510fbb 100644 --- a/test/resources/link-event.bpmn +++ b/test/resources/link-event.bpmn @@ -1,33 +1,74 @@ - - + + - flow1 + to-task1 - - flow1 - flow2 - environment.services.log("task1"); next() + + + + to-throw + + + + to-task1 + to-throw + environment.services.log(this.content.id); +next(); - - flow4 - - flow3 - + Flow_1ef9asg + - - flow3 - flow4 - environment.services.log("task2"); next() + + + Flow_1ef9asg + to-end + environment.services.log(this.content.id); +next(); - - flow2 - - - - - - + + to-end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a7249cd901e17462127407b6d96f66b5978c676f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 9 May 2026 07:07:25 +0200 Subject: [PATCH 07/31] fix linked event definition --- src/eventDefinitions/LinkEventDefinition.js | 167 +++------- .../LinkEventDefinition-test.js | 315 +++++------------- test/feature/link-as-goto-feature.js | 223 +++++++++++++ test/feature/linking-feature.js | 30 +- test/resources/link-basic.bpmn | 20 +- 5 files changed, 375 insertions(+), 380 deletions(-) create mode 100644 test/feature/link-as-goto-feature.js diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index ab04ab68..390ff79f 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -1,8 +1,6 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); const kExecuteMessage = Symbol.for('executeMessage'); export default function LinkEventDefinition(activity, eventDefinition) { @@ -12,51 +10,42 @@ export default function LinkEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - const reference = (this.reference = { + this.reference = { id: behaviour.name, linkName: behaviour.name, referenceType: 'link', - }); + }; this.isThrowing = isThrowing; this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - this[kCompleted] = false; - - if (!isThrowing) { - const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(reference.linkName)}-q`; - - this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - console.log({ messageQueueName, pattern: `*.${reference.referenceType}.#` }); - - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); - broker.consume(messageQueueName, this._onApiMessage.bind(this), { consumerTag: '_start-link-catch' }); - - broker.subscribeTmp('api', `activity.shake.${reference.referenceType}`, this._onApiMessage.bind(this), { noAck: true }); - } else { + if (isThrowing) { broker.subscribeTmp( 'event', 'activity.shake.start', (_, msg) => { broker.publish( 'event', - `activity.shake.${reference.referenceType}`, + `activity.shake.${this.reference.referenceType}`, cloneContent(msg.content, { sourceId: this.id, targetId: undefined, message: { ...this.reference } }), { type: 'shake', delegate: true } ); }, - { - noAck: true, - consumerTag: '_link-parent-shake', - priority: 1000, - } + { noAck: true, consumerTag: '_link-parent-shake', priority: 1000 } ); - - broker.subscribeTmp('event', 'activity.discard', this._onDiscard.bind(this), { + } else { + broker.subscribeTmp('api', `activity.shake.${this.reference.referenceType}`, this._onShakeMessage.bind(this), { + noAck: true, + consumerTag: '_link-catch-shake', + }); + const queueName = `link-${brokerSafeId(id)}-${brokerSafeId(this.reference.linkName)}-q`; + broker.assertQueue(queueName, { autoDelete: false, durable: true }); + broker.bindQueue(queueName, 'api', '*.link.#', { durable: true }); + broker.consume(queueName, this._onLinkApiMessage.bind(this), { noAck: true, - consumerTag: '_link-parent-discard', + consumerTag: '_link-catch-listener', }); } } @@ -73,39 +62,30 @@ LinkEventDefinition.prototype.execute = function execute(executeMessage) { LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent.executionId; - this[kMessageQ].consume(this._onCatchLink.bind(this), { - noAck: true, - consumerTag: `_api-link-${executionId}`, - }); + const linkMessage = executeContent.message ?? executeContent.input ?? { ...this.reference }; - if (this[kCompleted]) return; + this.logger.debug(`<${executionId} (${this.activity.id})> caught link ${this.reference.linkName}`); const broker = this.broker; - const onApiMessage = this._onApiMessage.bind(this); - broker.subscribeTmp('api', `activity.stop.${parentExecutionId}`, onApiMessage, { - noAck: true, - consumerTag: `_api-parent-${executionId}`, - }); - broker.subscribeTmp('api', `activity.#.${executionId}`, onApiMessage, { - noAck: true, - consumerTag: `_api-${executionId}`, - }); - - this._debug(`expect link ${this.reference.linkName}`); - - const waitContent = cloneContent(executeContent, { - executionId: parentExecutionId, + const catchContent = cloneContent(executeContent, { link: { ...this.reference }, + message: { ...linkMessage }, + executionId: parentExecutionId, }); - waitContent.parent = shiftParent(parent); + catchContent.parent = shiftParent(parent); + + broker.publish('event', 'activity.catch', catchContent, { type: 'catch' }); - broker.publish('event', 'activity.wait', waitContent); + return broker.publish( + 'execution', + 'execute.completed', + cloneContent(executeContent, { output: linkMessage, state: 'catch' }) + ); }; LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { @@ -128,90 +108,21 @@ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessag return broker.publish('execution', 'execute.completed', cloneContent(executeContent)); }; -LinkEventDefinition.prototype._onCatchLink = function onCatchLink(routingKey, message) { - console.log('--------------------------'); - +LinkEventDefinition.prototype._onLinkApiMessage = function onLinkApiMessage(_, message) { + if (message.properties.type !== 'link') return; if (message.content.message?.linkName !== this.reference.linkName) return; - if (message.content.state === 'discard') return this._discard(); - return this._complete('caught', message.content.message); -}; - -LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { - console.log('CATCH', { [this.id]: routingKey, ...message.properties }); - - switch (message.properties.type) { - case 'discard': { - return this._discard(); - } - case 'stop': { - this._stop(); - break; - } - case 'link': { - console.log(message.content); - break; - } - case 'shake': { - if (message.content.message?.linkName !== this.reference.linkName) return; - - const content = cloneContent(message.content, { targetId: this.id, isLinked: true }); - content.sequence = content.sequence || []; - content.sequence.push({ id: this.id, type: this.type }); - - return this.broker.publish('event', 'activity.shake.linked', content, { persistent: false, type: 'shake' }); - } - } -}; - -LinkEventDefinition.prototype._complete = function complete(verb, output) { - this[kCompleted] = true; - - this._stop(); - - this._debug(`${verb} link ${this.reference.linkName}`); - - const executeContent = this[kExecuteMessage].content; - const parent = executeContent.parent; - const catchContent = cloneContent(executeContent, { - link: { ...this.reference }, - message: { ...output }, - executionId: parent.executionId, - }); - catchContent.parent = shiftParent(parent); - - const broker = this.broker; - broker.publish('event', 'activity.catch', catchContent, { type: 'catch' }); - - return broker.publish('execution', 'execute.completed', cloneContent(executeContent, { output, state: 'catch' })); -}; + if (this.activity.isRunning) return; -LinkEventDefinition.prototype._discard = function discard() { - this[kCompleted] = true; - this._stop(); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content)); + this.activity.run(message.content.message); }; -LinkEventDefinition.prototype._stop = function stop() { - const broker = this.broker; - const executionId = this.executionId; - broker.cancel(`_api-link-${executionId}`); - broker.cancel(`_api-parent-${executionId}`); - broker.cancel(`_api-${executionId}`); - this[kMessageQ].purge(); -}; +LinkEventDefinition.prototype._onShakeMessage = function onShakeMessage(_, message) { + if (message.properties.type !== 'shake') return; + if (message.content.message?.linkName !== this.reference.linkName) return; -LinkEventDefinition.prototype._onDiscard = function onDiscard(_, message) { - this.broker.publish( - 'event', - 'activity.link.discard', - cloneContent(message.content, { - message: { ...this.reference }, - state: 'discard', - }), - { type: 'link', delegate: true } - ); -}; + const content = cloneContent(message.content, { targetId: this.id, isLinked: true }); + content.sequence = content.sequence || []; + content.sequence.push({ id: this.id, type: this.type }); -LinkEventDefinition.prototype._debug = function debug(msg) { - this.logger.debug(`<${this.executionId} (${this.activity.id})> ${msg}`); + return this.broker.publish('event', 'activity.shake.linked', content, { persistent: false, type: 'shake' }); }; diff --git a/test/eventDefinitions/LinkEventDefinition-test.js b/test/eventDefinitions/LinkEventDefinition-test.js index cb037398..0414f92f 100644 --- a/test/eventDefinitions/LinkEventDefinition-test.js +++ b/test/eventDefinitions/LinkEventDefinition-test.js @@ -14,306 +14,178 @@ describe('LinkEventDefinition', () => { }); describe('catching', () => { - it('publishes wait event on parent broker', () => { - const catchSignal = new LinkEventDefinition(event, { + it('completes immediately on execute, publishing activity.catch and execute.completed with the link payload', () => { + const catchEd = new LinkEventDefinition(event, { type: 'bpmn:LinkEventDefinition', behaviour: { name: 'LINKA' }, }); - const messages = []; - event.broker.subscribeTmp( - 'event', - 'activity.*', - (_, msg) => { - messages.push(msg); - }, - { noAck: true } - ); + const eventMessages = []; + const executionMessages = []; + event.broker.subscribeTmp('event', 'activity.#', (_, msg) => eventMessages.push(msg), { noAck: true }); + event.broker.subscribeTmp('execution', 'execute.#', (_, msg) => executionMessages.push(msg), { noAck: true }); - catchSignal.execute({ + catchEd.execute({ fields: {}, content: { executionId: 'event_1_0', index: 0, + message: { linkName: 'LINKA', payload: { hello: 'world' } }, parent: { - id: 'bound', + id: 'event', executionId: 'event_1', - path: [ - { - id: 'theProcess', - executionId: 'theProcess_0', - }, - ], + path: [{ id: 'theProcess', executionId: 'theProcess_0' }], }, }, }); - expect(messages).to.have.length(1); - expect(messages[0].fields).to.have.property('routingKey', 'activity.wait'); - expect(messages[0].content).to.have.property('executionId', 'event_1'); - expect(messages[0].content.parent).to.have.property('id', 'theProcess'); - expect(messages[0].content.parent).to.have.property('executionId', 'theProcess_0'); + const catchMsg = eventMessages.find((m) => m.fields.routingKey === 'activity.catch'); + expect(catchMsg, 'activity.catch').to.exist; + expect(catchMsg.content.link).to.deep.include({ linkName: 'LINKA', referenceType: 'link' }); + + const completedMsg = executionMessages.find((m) => m.fields.routingKey === 'execute.completed'); + expect(completedMsg, 'execute.completed').to.exist; + expect(completedMsg.content).to.have.property('state', 'catch'); + expect(completedMsg.content.output).to.deep.include({ linkName: 'LINKA', payload: { hello: 'world' } }); }); - it('completes and clears listeners when signal is caught', () => { - const catchSignal = new LinkEventDefinition(event, { + it('does not publish activity.wait', () => { + const catchEd = new LinkEventDefinition(event, { type: 'bpmn:LinkEventDefinition', behaviour: { name: 'LINKA' }, }); - const messages = []; - event.broker.subscribeTmp( - 'execution', - 'execute.completed', - (_, msg) => { - messages.push(msg); - }, - { noAck: true, consumerTag: '_test-tag' } - ); + const waitMessages = []; + event.broker.subscribeTmp('event', 'activity.wait', (_, msg) => waitMessages.push(msg), { noAck: true }); - catchSignal.execute({ + catchEd.execute({ fields: {}, content: { executionId: 'event_1_0', - index: 0, + message: { linkName: 'LINKA' }, parent: { - id: 'bound', + id: 'event', executionId: 'event_1', - path: [ - { - id: 'theProcess', - executionId: 'theProcess_0', - }, - ], + path: [{ id: 'theProcess', executionId: 'theProcess_0' }], }, }, }); - event.broker.publish('api', 'activity.link.event_1', { message: { linkName: 'LINKA' } }); - event.broker.cancel('_test-tag'); - - expect(messages).to.have.length(1); - - expect(event.broker).to.have.property('consumerCount', 0); + expect(waitMessages).to.have.length(0); }); - it('completes and clears listeners if signaled before execution', () => { - const catchSignal = new LinkEventDefinition(event, { + it('binds a durable named queue for link delivery so messages survive stop/recover', () => { + new LinkEventDefinition(event, { type: 'bpmn:LinkEventDefinition', behaviour: { name: 'LINKA' }, }); - - event.broker.publish('api', 'activity.link.event_1', { message: { linkName: 'LINKA' } }); - - const messages = []; - event.broker.subscribeTmp( - 'execution', - 'execute.completed', - (_, msg) => { - messages.push(msg); - }, - { noAck: true, consumerTag: '_test-tag' } - ); - - catchSignal.execute({ - fields: {}, - content: { - executionId: 'event_1_0', - index: 0, - parent: { - id: 'bound', - executionId: 'event_1', - path: [ - { - id: 'theProcess', - executionId: 'theProcess_0', - }, - ], - }, - }, - }); - - event.broker.cancel('_test-tag'); - - expect(messages).to.have.length(1); - - expect(event.broker).to.have.property('consumerCount', 0); + const q = event.broker.getQueue('link-event-LINKA-q'); + expect(q, 'durable link queue').to.exist; + expect(q.options).to.include({ durable: true, autoDelete: false }); }); - it('completes and clears listeners if discarded', () => { - const catchSignal = new LinkEventDefinition(event, { + it('responds to shake.link with matching linkName', () => { + const catchEd = new LinkEventDefinition(event, { type: 'bpmn:LinkEventDefinition', behaviour: { name: 'LINKA' }, }); - const messages = []; - event.broker.subscribeTmp( - 'execution', - 'execute.discard', - (_, msg) => { - messages.push(msg); - }, - { noAck: true, consumerTag: '_test-tag' } - ); - - catchSignal.execute({ - fields: {}, - content: { - executionId: 'event_1_0', - index: 0, - parent: { - id: 'bound', - executionId: 'event_1', - path: [ - { - id: 'theProcess', - executionId: 'theProcess_0', - }, - ], - }, - }, - }); - - event.broker.publish('api', 'activity.discard.event_1_0', {}, { type: 'discard' }); + const linkedMessages = []; + event.broker.subscribeTmp('event', 'activity.shake.linked', (_, msg) => linkedMessages.push(msg), { noAck: true }); - event.broker.cancel('_test-tag'); - - expect(messages).to.have.length(1); + event.broker.publish( + 'api', + 'activity.shake.link', + { sourceId: 'thrower', sequence: [], message: { linkName: 'LINKA' } }, + { type: 'shake' } + ); - expect(event.broker).to.have.property('consumerCount', 0); + expect(linkedMessages).to.have.length(1); + expect(linkedMessages[0].content).to.have.property('targetId', catchEd.id); + expect(linkedMessages[0].content).to.have.property('isLinked', true); }); - it('stops and clears listeners if stopped', () => { - const catchSignal = new LinkEventDefinition(event, { + it('ignores shake.link with mismatching linkName', () => { + new LinkEventDefinition(event, { type: 'bpmn:LinkEventDefinition', behaviour: { name: 'LINKA' }, }); - const messages = []; - event.broker.subscribeTmp( - 'execution', - 'execute.#', - (_, msg) => { - messages.push(msg); - }, - { noAck: true, consumerTag: '_test-tag' } - ); + const linkedMessages = []; + event.broker.subscribeTmp('event', 'activity.shake.linked', (_, msg) => linkedMessages.push(msg), { noAck: true }); - catchSignal.execute({ - fields: {}, - content: { - executionId: 'event_1_0', - index: 0, - parent: { - id: 'bound', - executionId: 'event_1', - path: [ - { - id: 'theProcess', - executionId: 'theProcess_0', - }, - ], - }, - }, - }); - - event.broker.publish('api', 'activity.stop.event_1_0', {}, { type: 'stop' }); - - event.broker.cancel('_test-tag'); - - expect(messages).to.have.length(0); + event.broker.publish( + 'api', + 'activity.shake.link', + { sourceId: 'thrower', sequence: [], message: { linkName: 'OTHER' } }, + { type: 'shake' } + ); - expect(event.broker).to.have.property('consumerCount', 0); + expect(linkedMessages).to.have.length(0); }); + }); + + describe('throwing', () => { + it('publishes activity.link with delegate:true and the link payload', () => { + event.isThrowing = true; - it('ignores link message on link name mismatch', () => { - const catchSignal = new LinkEventDefinition(event, { + const throwEd = new LinkEventDefinition(event, { + type: 'bpmn:LinkEventDefinition', behaviour: { name: 'LINKA' }, }); const messages = []; - event.broker.subscribeTmp( - 'execution', - 'execute.completed', - (_, msg) => { - messages.push(msg); - }, - { noAck: true, consumerTag: '_test-tag' } - ); + event.broker.subscribeTmp('event', 'activity.link', (_, msg) => messages.push(msg), { noAck: true }); - catchSignal.execute({ + throwEd.execute({ fields: {}, content: { executionId: 'event_1_0', index: 0, parent: { - id: 'bound', + id: 'intermediate', executionId: 'event_1', - path: [ - { - id: 'theProcess', - executionId: 'theProcess_0', - }, - ], + path: [{ id: 'theProcess', executionId: 'theProcess_0' }], }, }, }); - event.broker.cancel('_test-tag'); - - event.broker.publish('api', 'activity.link.event_1', { message: { linkName: 'LINKB' } }); - - expect(messages).to.have.length(0); - - expect(event.broker).to.have.property('consumerCount').that.is.above(1); + expect(messages).to.have.length(1); + expect(messages[0].fields).to.have.property('routingKey', 'activity.link'); + expect(messages[0].properties).to.have.property('delegate', true); + expect(messages[0].properties).to.have.property('type', 'link'); + expect(messages[0].content.message).to.deep.include({ linkName: 'LINKA', referenceType: 'link' }); + expect(messages[0].content).to.have.property('state', 'throw'); + expect(messages[0].content).to.have.property('executionId', 'event_1'); }); - }); - describe('throwing', () => { - it('publishes signal event on parent broker', () => { + it('also publishes execute.completed for itself so the activity terminates', () => { event.isThrowing = true; - const definition = new LinkEventDefinition(event, { + const throwEd = new LinkEventDefinition(event, { type: 'bpmn:LinkEventDefinition', behaviour: { name: 'LINKA' }, }); const messages = []; - event.broker.subscribeTmp( - 'event', - 'activity.link', - (_, msg) => { - messages.push(msg); - }, - { noAck: true } - ); + event.broker.subscribeTmp('execution', 'execute.completed', (_, msg) => messages.push(msg), { noAck: true }); - definition.execute({ + throwEd.execute({ fields: {}, content: { executionId: 'event_1_0', - index: 0, parent: { id: 'intermediate', executionId: 'event_1', - path: [ - { - id: 'theProcess', - executionId: 'theProcess_0', - }, - ], + path: [{ id: 'theProcess', executionId: 'theProcess_0' }], }, }, }); expect(messages).to.have.length(1); - expect(messages[0].fields).to.have.property('routingKey', 'activity.link'); - expect(messages[0].content).to.have.property('executionId', 'event_1'); - expect(messages[0].content.parent).to.have.property('id', 'theProcess'); - expect(messages[0].content.parent).to.have.property('executionId', 'theProcess_0'); }); - it('publishes signal discard event on parent broker if parent is discarded', () => { + it('on activity.shake.start, publishes activity.shake.link with the linkName', () => { event.isThrowing = true; new LinkEventDefinition(event, { @@ -322,30 +194,19 @@ describe('LinkEventDefinition', () => { }); const messages = []; - event.broker.subscribeTmp( - 'event', - 'activity.link.discard', - (_, msg) => { - messages.push(msg); - }, - { noAck: true, consumerTag: '_test-tag' } - ); + event.broker.subscribeTmp('event', 'activity.shake.link', (_, msg) => messages.push(msg), { noAck: true }); - event.broker.publish('event', 'activity.discard', { + event.broker.publish('event', 'activity.shake.start', { executionId: 'event_1', - parent: { - id: 'theProcess', - executionId: 'theProcess_0', - }, + sequence: [], + parent: { id: 'theProcess', executionId: 'theProcess_0' }, }); expect(messages).to.have.length(1); - expect(messages[0].content).to.have.property('executionId', 'event_1'); - expect(messages[0].content).to.have.property('state', 'discard'); - expect(messages[0].content.parent).to.have.property('executionId', 'theProcess_0'); - - event.broker.cancel('_test-tag'); - expect(event.broker, 'discard consumer only').to.have.property('consumerCount', 1); + expect(messages[0].properties).to.have.property('delegate', true); + expect(messages[0].properties).to.have.property('type', 'shake'); + expect(messages[0].content.message).to.deep.include({ linkName: 'LINKA', referenceType: 'link' }); + expect(messages[0].content).to.have.property('sourceId', 'event'); }); }); }); diff --git a/test/feature/link-as-goto-feature.js b/test/feature/link-as-goto-feature.js new file mode 100644 index 00000000..42beabe7 --- /dev/null +++ b/test/feature/link-as-goto-feature.js @@ -0,0 +1,223 @@ +import { Definition } from 'bpmn-elements'; +import testHelpers from '../helpers/testHelpers.js'; + +const linkSource = ` + + + + + + + + + \${environment.variables.go} + + + + + + + + + + +`; + +Feature('Link as goto', () => { + Scenario('throw → catch invocation when branch is taken', () => { + /** @type {Definition} */ + let definition; + Given('a process with a throw and a paired catch', async () => { + const context = await testHelpers.context(linkSource); + definition = new Definition(context, { variables: { go: true } }); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('catch event was taken once', () => { + expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('downstream end after catch was reached', () => { + expect(definition.getActivityById('end2').counters).to.have.property('taken', 1); + }); + }); + + Scenario('catch is dormant when throw branch is discarded', () => { + /** @type {Definition} */ + let definition; + Given('a process where the throw branch is bypassed', async () => { + const context = await testHelpers.context(linkSource); + definition = new Definition(context, { variables: { go: false } }); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes', () => { + return end; + }); + + And('throw event counters stay at 0', () => { + expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 0, discarded: 0 }); + }); + + And('catch event was never invoked — counters stay at 0', () => { + expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 0, discarded: 0 }); + }); + + And('catch is not running', () => { + expect(definition.getActivityById('catch')).to.have.property('isRunning', false); + }); + + And('end2 (downstream of catch) was not reached', () => { + expect(definition.getActivityById('end2').counters).to.have.property('taken', 0); + }); + }); + + Scenario('catch never publishes activity.wait', () => { + let definition; + let waitMessages; + Given('a process with a paired throw/catch', async () => { + const context = await testHelpers.context(linkSource); + definition = new Definition(context, { variables: { go: true } }); + waitMessages = []; + definition.broker.subscribeTmp( + 'event', + 'activity.wait', + (_, msg) => { + if (msg.content.id === 'catch') waitMessages.push(msg); + }, + { noAck: true } + ); + }); + + When('definition is ran to completion', async () => { + const end = definition.waitFor('end'); + definition.run(); + await end; + }); + + Then('no activity.wait was published for the catch', () => { + expect(waitMessages).to.have.length(0); + }); + }); + + Scenario('pending link throw survives stop/recover/resume', () => { + /** @type {Definition} */ + let definition; + let context; + let state; + + Given('a process with throw and catch where stop happens after throw fires', async () => { + const source = ` + + + + + + + + + + + + + + + + `; + context = await testHelpers.context(source); + definition = new Definition(context); + }); + + let end, wait; + When('definition is ran and pauses at the user task downstream of catch', async () => { + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + definition.run(); + await wait; + }); + + And('definition is stopped while userTask is waiting', () => { + definition.stop(); + }); + + And('state is captured', () => { + state = JSON.parse(JSON.stringify(definition.getState())); + }); + + When('definition is recovered into a fresh instance and resumed', () => { + definition = new Definition(context).recover(state); + end = definition.waitFor('end'); + definition.resume(); + }); + + And('the user task is signaled', async () => { + const userTask = definition.getPostponed().find((api) => api.id === 'userTask'); + expect(userTask, 'userTask api').to.exist; + userTask.signal(); + }); + + Then('definition completes', () => { + return end; + }); + + And('catch ran exactly once across the lifecycle', () => { + expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('throw was taken exactly once', () => { + expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + }); + + Scenario('throw with no matching catch silently completes', () => { + /** @type {Definition} */ + let definition; + + Given('a process whose throw has no catch with the same linkName', async () => { + const source = ` + + + + + + + + + `; + const context = await testHelpers.context(source); + definition = new Definition(context); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes', () => { + return end; + }); + + And('throw was taken', () => { + expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + }); +}); diff --git a/test/feature/linking-feature.js b/test/feature/linking-feature.js index abbcea08..fdcc9047 100644 --- a/test/feature/linking-feature.js +++ b/test/feature/linking-feature.js @@ -67,12 +67,12 @@ Feature('Linking', () => { return end; }); - And('throw event was taken', () => { - expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 1, discarded: 0 }); + And('throw event was not reached (default flow taken)', () => { + expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 0, discarded: skipDiscard ? 0 : 1 }); }); - And('catch event was taken', () => { - expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 1, discarded: 0 }); + And('catch event stayed dormant', () => { + expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 0, discarded: 0 }); }); Given('decision changes to take', () => { @@ -95,7 +95,7 @@ Feature('Linking', () => { And('catch event was taken', () => { expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); }); }); @@ -164,7 +164,7 @@ Feature('Linking', () => { }); And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); }); @@ -188,7 +188,7 @@ Feature('Linking', () => { And('catch event was taken', () => { expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); }); }); @@ -256,7 +256,7 @@ Feature('Linking', () => { }); And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); }); @@ -280,7 +280,7 @@ Feature('Linking', () => { And('catch event was taken', () => { expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); }); }); @@ -342,8 +342,8 @@ Feature('Linking', () => { expect(user).to.have.property('id', 'start'); }); - And('throw event is waiting as well', () => { - expect(definition.getActivityById('catch')).to.have.property('isRunning', true); + And('catch is dormant — not running while waiting for the throw', () => { + expect(definition.getActivityById('catch')).to.have.property('isRunning', false); }); Given('execution is stopped', () => { @@ -368,7 +368,7 @@ Feature('Linking', () => { }); And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); }); @@ -383,8 +383,8 @@ Feature('Linking', () => { expect(user).to.have.property('id', 'start'); }); - And('throw event is waiting as well', () => { - expect(definition.getActivityById('catch')).to.have.property('isRunning', true); + And('catch is dormant — not running while waiting for the throw', () => { + expect(definition.getActivityById('catch')).to.have.property('isRunning', false); }); Given('execution is stopped', () => { @@ -429,7 +429,7 @@ Feature('Linking', () => { And('catch event was taken', () => { expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); }); }); diff --git a/test/resources/link-basic.bpmn b/test/resources/link-basic.bpmn index 709d1fca..6976bcf0 100644 --- a/test/resources/link-basic.bpmn +++ b/test/resources/link-basic.bpmn @@ -10,10 +10,10 @@ Flow_011w5tr - - ${true} + + ${environment.variables.condition} - + Flow_0nezlgs @@ -22,7 +22,7 @@ Flow_1j0pk3d - + Flow_132srsk @@ -30,11 +30,11 @@ Flow_132srsk Flow_1qj9tz9 - - + + Flow_1qj9tz9 - + Flow_1j0pk3d @@ -54,16 +54,16 @@ - + - + - + From b76e2ccbe2627651def4de59ac4069ef90d2e189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 9 May 2026 09:00:09 +0200 Subject: [PATCH 08/31] parallel gateway listens for peer enter --- src/activity/Activity.js | 62 +-- src/gateways/ParallelGateway.js | 61 ++- src/process/ProcessExecution.js | 2 - test/Environment-test.js | 16 +- test/activities-test.js | 46 +- test/activity/Activity-test.js | 680 ------------------------- test/events/BoundaryEvent-test.js | 88 ---- test/feature/Process-feature.js | 2 - test/flows/SequenceFlow-test.js | 7 +- test/gateways/ExclusiveGateway-test.js | 18 - test/gateways/InclusiveGateway-test.js | 10 - test/gateways/ParallelGateway-test.js | 131 ++--- test/tasks/ServiceTask-test.js | 4 +- test/tasks/SubProcess-test.js | 1 + 14 files changed, 130 insertions(+), 998 deletions(-) diff --git a/src/activity/Activity.js b/src/activity/Activity.js index eca2340b..a8cf13f7 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -79,10 +79,6 @@ function Activity(Behaviour, activityDef, context) { inboundTriggers, outboundSequenceFlows, outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows), - ...(isParallelJoin && { - inboundJoinFlows: new Set(), - inboundSourceIds: new Map(inboundSequenceFlows.map(({ sourceId }) => [sourceId, 0])), - }), }; this[kFlags] = { @@ -241,11 +237,6 @@ Object.defineProperties(Activity.prototype, { return this.context.getActivityParentById(this.id); }, }, - expectedInboundSources: { - get() { - return new Map(this[kFlows].inboundSourceIds); - }, - }, initialized: { get() { return !!this[kExec]?.get('initExecutionId'); @@ -475,7 +466,6 @@ Activity.prototype._discardRun = function discardRun() { }; Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { - // if (this.isParallelJoin) { if (this[kFlags].isParallelGateway) { const message = cloneMessage(sourceMessage, { join: this.id }); message.content.sequence.push({ id: this.id, type: this.type }); @@ -547,56 +537,11 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { let discardSequence; if (content.discardSequence) discardSequence = content.discardSequence.slice(); const context = { inbound, discardSequence }; - // return this.isParallelJoin ? this.run(context) : this._runDiscard(context); return this[kFlags].isParallelGateway ? this.run(context) : this._runDiscard(context); } } }; -Activity.prototype._onJoinInbound = function onJoinInbound(routingKey, message) { - const { inboundJoinFlows, inboundSourceIds } = this[kFlows]; - - let expectedInboundCount = 0; - for (const [, a] of inboundSourceIds) { - expectedInboundCount += a || 0; - } - - // const expectedInboundCount = [...inboundSourceIds.values()].reduce((s, a) => s + (a || 1), 0); - - inboundJoinFlows.add(message); - - const remaining = expectedInboundCount - inboundJoinFlows.size; - - if (remaining) { - return this.logger.debug(`<${this.id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`); - } - - const inbound = []; - - let taken; - for (const im of inboundJoinFlows) { - if (im.fields.routingKey === 'flow.take') taken = true; - im.ack(); - inbound.push(cloneContent(im.content)); - } - - const discardSequence = new Set(); - if (!taken) { - for (const im of inboundJoinFlows) { - if (!im.content.discardSequence) continue; - for (const sourceId of im.content.discardSequence) { - discardSequence.add(sourceId); - } - } - } - - inboundJoinFlows.clear(); - this.broker.cancel('_run-on-inbound'); - - if (!taken) return this._runDiscard({ inbound, discardSequence: [...discardSequence] }); - return this.run({ inbound }); -}; - Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message) { const { fields, content, properties } = message; const inboundQ = this.broker.getQueue('inbound-q'); @@ -609,12 +554,7 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message } break; } - case 'flow.shake': { - if (this.isParallelJoin) { - let count = this[kFlows].inboundSourceIds.get(content.sourceId); - this[kFlows].inboundSourceIds.set(content.sourceId, ++count); - } - } + case 'flow.shake': case 'activity.shake.start': return this._onShakeMessage(message); case 'association.take': diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index 1126429f..f0a7ee9d 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -107,6 +107,11 @@ ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { consumerTag: '_parallel-execution-execute-tag', }); + this.broker.subscribeTmp('execution', 'execute.start', this._onPeerEnterMessage.bind(this), { + noAck: true, + consumerTag: '_parallel-execution-peer-enter-tag', + }); + this.peerMonitor.execute(message); const inboundQ = this.broker.getQueue('inbound-q'); @@ -121,7 +126,9 @@ ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { { consumerTag: '_converging-inbound', exclusive: true, prefetch: 10000 } ); - this.broker.publish('event', 'activity.converge', cloneContent(executeContent)); + if (this.isConverging) { + this.broker.publish('event', 'activity.converge', cloneContent(executeContent)); + } return this.broker.publish( 'execution', @@ -137,6 +144,12 @@ ParallelGatewayBehaviour.prototype._onExecuteMessage = function onExecuteMessage } }; +ParallelGatewayBehaviour.prototype._onPeerEnterMessage = function onPeerEnterMessage(_, message) { + if (!message.properties.monitor) return; + const peer = this.peerMonitor.watching.get(message.content.id); + if (peer) this.peerMonitor.running.set(message.content.id, peer); +}; + ParallelGatewayBehaviour.prototype._complete = function complete() { const take = this.peerMonitor.inbound.some(({ action }) => action === 'take'); @@ -158,6 +171,7 @@ ParallelGatewayBehaviour.prototype._stop = function stop() { this.broker.cancel('_converging-inbound'); this.broker.cancel('_api-stop-execution'); this.broker.cancel('_parallel-execution-execute-tag'); + this.broker.cancel('_parallel-execution-peer-enter-tag'); this.peerMonitor.stop(); }; @@ -199,25 +213,43 @@ PeerMonitor.prototype.execute = function execute(executeMessage) { this.touched.add(inbound.sourceId); for (const target of this.targets.values()) { - if (target.status || target.initialized) this.monitor(target); + this.monitor(target); } return this.running.size; }; PeerMonitor.prototype.monitor = function monitor(peerActivity) { - if (this.running.has(peerActivity.id)) return; + if (this.watching.has(peerActivity.id)) return; this.activity.logger.debug(`<${this.id}> monitor <${peerActivity.id}> with status: ${peerActivity.status}`); - this.running.set(peerActivity.id, peerActivity); + this.watching.set(peerActivity.id, peerActivity); - this.broker.publish('execution', 'execute.start', { - id: this.id, - peerId: peerActivity.id, - executionId: peerActivity.executionId, - isRootScope: false, - }); + if (peerActivity.status || peerActivity.initialized) { + this.running.set(peerActivity.id, peerActivity); + } + + peerActivity.broker.createShovel( + `_on-enter-${this.id}`, + { + exchange: 'event', + pattern: 'activity.enter', + }, + { + broker: this.broker, + exchange: 'execution', + exchangeKey: 'execute.start', + publishProperties: { + monitor: true, + }, + }, + { + cloneMessage(sourceMessage) { + return cloneMessage(sourceMessage, { isRootScope: false }); + }, + } + ); peerActivity.broker.createShovel( `_on-leave-${this.id}`, @@ -242,19 +274,14 @@ PeerMonitor.prototype.monitor = function monitor(peerActivity) { }; PeerMonitor.prototype._onCompleteMessage = function onCompleteMessage(_routingKey, message) { - const peerActivity = this.running.get(message.content.id); - peerActivity.broker.closeShovel(`_on-leave-${this.id}`); this.running.delete(message.content.id); - for (const target of this.targets.values()) { - if (target.status || target.initialized) this.monitor(target); - } - return !this.running.size; }; PeerMonitor.prototype.stop = function stop() { - for (const peerActivity of this.running.values()) { + for (const peerActivity of this.watching.values()) { peerActivity.broker.closeShovel(`_on-leave-${this.id}`); + peerActivity.broker.closeShovel(`_on-enter-${this.id}`); } }; diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 59283eeb..ba3a06ab 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -892,8 +892,6 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou for (const child of this[kElements].children) { if (child.placeholder) continue; - console.log({ [child.id]: routingKey }); - child.broker.publish('api', routingKey, cloneContent(message.content), message.properties); if (consumed && !continueOnConsumed) break; } diff --git a/test/Environment-test.js b/test/Environment-test.js index 9da9a825..30d3eade 100644 --- a/test/Environment-test.js +++ b/test/Environment-test.js @@ -3,8 +3,8 @@ import { Timers } from '../src/Timers.js'; describe('Environment', () => { describe('ctor', () => { - it('sets settings', () => { - expect(new Environment()).to.have.property('settings').that.deep.equal({}); + it('sets settings with skipDiscard default', () => { + expect(new Environment()).to.have.property('settings').that.deep.equal({ skipDiscard: true }); expect( new Environment({ settings: { @@ -14,11 +14,12 @@ describe('Environment', () => { ) .to.have.property('settings') .that.eql({ + skipDiscard: true, test: 1, }); }); - it('shallow clones settings', () => { + it('shallow clones settings while preserving skipDiscard default', () => { const settings = { test: 1, }; @@ -28,6 +29,7 @@ describe('Environment', () => { settings.test = 2; expect(environment).to.have.property('settings').that.eql({ + skipDiscard: true, test: 1, }); }); @@ -267,13 +269,13 @@ describe('Environment', () => { it('ignored if non-object is passed', () => { const environment = new Environment({ settings: { before: true } }); environment.assignSettings(); - expect(environment.settings).to.eql({ before: true }); + expect(environment.settings).to.eql({ skipDiscard: true, before: true }); environment.assignSettings(null); - expect(environment.settings).to.eql({ before: true }); + expect(environment.settings).to.eql({ skipDiscard: true, before: true }); environment.assignSettings('null'); - expect(environment.settings).to.eql({ before: true }); + expect(environment.settings).to.eql({ skipDiscard: true, before: true }); environment.assignSettings(1); - expect(environment.settings).to.eql({ before: true }); + expect(environment.settings).to.eql({ skipDiscard: true, before: true }); }); }); diff --git a/test/activities-test.js b/test/activities-test.js index 224d554e..0db53f50 100644 --- a/test/activities-test.js +++ b/test/activities-test.js @@ -32,7 +32,7 @@ describe('activity', () => { singleFlowDefinition = await SingleFlowDefinition(activityType); }); - it('run() publish messages in the expected sequence', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('run() publish messages in the expected sequence', async () => { const processContext = await testHelpers.context(simpleDefinition); const activity = processContext.getActivityById('activity'); @@ -64,7 +64,7 @@ describe('activity', () => { assertMessage('activity.leave'); }); - it('run() after run() resets messages', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('run() after run() resets messages', async () => { const processContext = await testHelpers.context(simpleDefinition); const activity = processContext.getActivityById('activity'); @@ -101,7 +101,7 @@ describe('activity', () => { assertMessage('activity.leave'); }); - it('discard() on enter discards outbound', async () => { + it('discard() on enter takes the activity through enter → discard → leave', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); expect(activity.outbound.length).to.equal(2); @@ -132,11 +132,9 @@ describe('activity', () => { assertMessage('activity.enter'); assertMessage('activity.discard'); assertMessage('activity.leave'); - - expect(activity.outbound.every((flow) => flow.counters.discard)).to.be.ok; }); - it('discard() on start discards outbound', async () => { + it('discard() on start takes the activity through enter → start → discard → leave', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -167,7 +165,6 @@ describe('activity', () => { assertMessage('activity.leave'); expect(activity.outbound.length).to.equal(2); - expect(activity.outbound.every((flow) => flow.counters.discard)).to.be.ok; }); it('discard() on discard is ignored', async () => { @@ -211,10 +208,9 @@ describe('activity', () => { assertMessage('activity.leave'); expect(activity.outbound.length).to.equal(2); - expect(activity.outbound.every((flow) => flow.counters.discard)).to.be.ok; }); - it('discard() on end is ignored', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('discard() on end is ignored', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -255,7 +251,7 @@ describe('activity', () => { expect(activity.outbound.some((flow) => flow.counters.take)).to.be.ok; }); - it('discard() on leave is ignored', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('discard() on leave is ignored', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -360,7 +356,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume stopped on enter continuous execution', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume stopped on enter continuous execution', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -400,7 +396,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume recovered on enter continuous execution', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered on enter continuous execution', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -447,7 +443,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume recovered new instance on enter continuous execution', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered new instance on enter continuous execution', async () => { const context = await testHelpers.context(singleFlowDefinition); let activity = context.getActivityById('activity'); @@ -507,7 +503,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume stopped on start continuous execution', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume stopped on start continuous execution', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -550,7 +546,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume recovered on start continuous execution', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered on start continuous execution', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -596,7 +592,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume recovered new instance on start continuous execution', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered new instance on start continuous execution', async () => { const context = await testHelpers.context(singleFlowDefinition); let activity = context.getActivityById('activity'); @@ -653,7 +649,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume stopped on end leaves activity', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume stopped on end leaves activity', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -701,7 +697,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume stopped on end leaves activity', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume stopped on end leaves activity', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -749,7 +745,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume recovered on end leaves activity', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered on end leaves activity', async () => { const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -800,7 +796,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume recovered new instance on end leaves activity', async () => { + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered new instance on end leaves activity', async () => { const context = await testHelpers.context(singleFlowDefinition); let activity = context.getActivityById('activity'); @@ -863,7 +859,8 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume stopped while discarded leaves activity', async () => { + it('resume stopped while discarded leaves activity', async function resumeWhileDiscarded() { + if (activityType === 'bpmn:ParallelGateway') return this.skip(); const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -904,7 +901,8 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('resume recovered while discarded leaves activity', async () => { + it('resume recovered while discarded leaves activity', async function resumeRecoveredWhileDiscarded() { + if (activityType === 'bpmn:ParallelGateway') return this.skip(); const context = await testHelpers.context(singleFlowDefinition); const activity = context.getActivityById('activity'); @@ -987,7 +985,9 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('discards if inbound discarded', async () => { + it('discards if inbound discarded', async function discards() { + if (activityType === 'bpmn:ParallelGateway') return this.skip(); + const messages = []; activity.broker.subscribeTmp( 'event', diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index 26070ba9..61ae8154 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -582,324 +582,6 @@ describe('Activity', () => { expect(runQ, 'run queue consumer active').to.have.property('consumerCount', 0); }); - describe('parallel gateway join', () => { - it('publishes activity enter with taken flows', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return sequenceFlows; - }, - }); - const sequenceFlow1 = new SequenceFlow({ id: 'flow1', sourceId: 'task1', parent: { id: 'process1' } }, context); - const sequenceFlow2 = new SequenceFlow({ id: 'flow2', sourceId: 'task2', parent: { id: 'process1' } }, context); - - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - isParallelGateway: true, - parent: { - id: 'process1', - }, - }, - context - ); - - activity.activate(); - - let message; - activity.broker.subscribeOnce('event', 'activity.enter', (_, msg) => { - message = msg; - }); - - sequenceFlow1.take(); - sequenceFlow2.take(); - - expect(message).to.be.ok; - expect(message.content.inbound).to.have.length(2); - expect(message.content.inbound[0]).to.include({ - id: 'flow1', - type: 'sequenceflow', - action: 'take', - }); - expect(message.content.inbound[1]).to.include({ - id: 'flow2', - type: 'sequenceflow', - action: 'take', - }); - - expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); - expect(activity.broker.getQueue('inbound-q')).to.have.property('consumerCount', 0); - }); - - it('publishes activity enter if at least one flow is taken', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return sequenceFlows; - }, - }); - const sequenceFlow1 = new SequenceFlow({ id: 'flow1', sourceId: 'task1', parent: { id: 'process1' } }, context); - const sequenceFlow2 = new SequenceFlow({ id: 'flow2', sourceId: 'task2', parent: { id: 'process1' } }, context); - - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - isParallelGateway: true, - parent: { - id: 'process1', - }, - }, - context - ); - - activity.activate(); - - let message; - activity.broker.subscribeOnce('event', 'activity.enter', (_, msg) => { - message = msg; - }); - - sequenceFlow1.discard(); - sequenceFlow2.take(); - - expect(message).to.be.ok; - expect(message.content.inbound).to.have.length(2); - expect(message.content.inbound[0]).to.include({ - id: 'flow1', - type: 'sequenceflow', - action: 'discard', - }); - expect(message.content.inbound[1]).to.include({ - id: 'flow2', - type: 'sequenceflow', - action: 'take', - }); - - expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); - }); - - it('publishes activity enter if at least one flow is taken, regardless of order', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return sequenceFlows; - }, - }); - const sequenceFlow1 = new SequenceFlow({ id: 'flow1', sourceId: 'task1', parent: { id: 'process1' } }, context); - const sequenceFlow2 = new SequenceFlow({ id: 'flow2', sourceId: 'task2', parent: { id: 'process1' } }, context); - - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - isParallelGateway: true, - parent: { - id: 'process1', - }, - }, - context - ); - - activity.activate(); - - let message; - activity.broker.subscribeOnce('event', 'activity.enter', (_, msg) => { - message = msg; - }); - - sequenceFlow1.take(); - sequenceFlow2.discard(); - - expect(message).to.be.ok; - expect(message.content.inbound).to.have.length(2); - expect(message.content.inbound[0]).to.include({ - id: 'flow1', - type: 'sequenceflow', - action: 'take', - }); - expect(message.content.inbound[1]).to.include({ - id: 'flow2', - type: 'sequenceflow', - action: 'discard', - }); - - expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); - }); - - it('publishes activity discard if all flows were discarded', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return sequenceFlows; - }, - }); - const sequenceFlow1 = new SequenceFlow({ id: 'flow1', sourceId: 'task1', parent: { id: 'process1' } }, context); - const sequenceFlow2 = new SequenceFlow({ id: 'flow2', sourceId: 'task2', parent: { id: 'process1' } }, context); - - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - isParallelGateway: true, - parent: { - id: 'process1', - }, - }, - context - ); - - activity.activate(); - - let message; - activity.broker.subscribeOnce('event', 'activity.discard', (_, msg) => { - message = msg; - }); - - sequenceFlow1.discard(); - sequenceFlow2.discard(); - - expect(message).to.be.ok; - expect(message.content.inbound).to.have.length(2); - expect(message.content.inbound[0]).to.include({ - id: 'flow1', - type: 'sequenceflow', - action: 'discard', - }); - expect(message.content.inbound[1]).to.include({ - id: 'flow2', - type: 'sequenceflow', - action: 'discard', - }); - - expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); - }); - - it('queues inbound before each inbound flow is taken', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return sequenceFlows; - }, - }); - const sequenceFlow1 = new SequenceFlow({ id: 'flow1', sourceId: 'task1', parent: { id: 'process1' } }, context); - const sequenceFlow2 = new SequenceFlow({ id: 'flow2', sourceId: 'task2', parent: { id: 'process1' } }, context); - - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - isParallelGateway: true, - parent: { - id: 'process1', - }, - }, - context - ); - - activity.activate(); - - let message; - activity.broker.subscribeOnce('event', 'activity.enter', (_, msg) => { - message = msg; - }); - - sequenceFlow1.take(); - sequenceFlow1.take(); - sequenceFlow1.take(); - sequenceFlow2.take(); - - expect(message).to.be.ok; - expect(message.content.inbound).to.have.length(4); - expect(message.content.inbound[0]).to.have.property('id', 'flow1'); - expect(message.content.inbound[1]).to.have.property('id', 'flow1'); - expect(message.content.inbound[2]).to.have.property('id', 'flow1'); - expect(message.content.inbound[3]).to.have.property('id', 'flow2'); - - expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); - }); - - it('takes next when all inbound flows have been evaluated', async () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return sequenceFlows; - }, - }); - const sequenceFlow1 = new SequenceFlow( - { id: 'flow1', targetId: 'activity', sourceId: 'task1', parent: { id: 'process1' } }, - context - ); - const sequenceFlow2 = new SequenceFlow( - { id: 'flow2', targetId: 'activity', sourceId: 'task2', parent: { id: 'process1' } }, - context - ); - - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const activity = new Activity( - behaviours.CompleteBehaviour, - { - id: 'activity', - isParallelGateway: true, - parent: { - id: 'process1', - }, - }, - context - ); - - activity.activate(); - - let message; - activity.broker.subscribeTmp( - 'event', - 'activity.enter', - (_, msg) => { - message = msg; - }, - { noAck: true } - ); - - let leave = activity.waitFor('leave'); - - sequenceFlow1.take(); - sequenceFlow1.take(); - sequenceFlow1.take(); - sequenceFlow2.take(); - sequenceFlow2.take(); - - expect(message).to.be.ok; - expect(message.content.inbound).to.have.length(4); - expect(message.content.inbound[0]).to.have.property('id', 'flow1'); - expect(message.content.inbound[1]).to.have.property('id', 'flow1'); - expect(message.content.inbound[2]).to.have.property('id', 'flow1'); - expect(message.content.inbound[3]).to.have.property('id', 'flow2'); - - expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 1); - - await leave; - - leave = activity.waitFor('leave'); - - sequenceFlow1.discard(); - - await leave; - - expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); - }); - }); }); describe('run()', () => { @@ -1039,7 +721,6 @@ describe('Activity', () => { activity.discard(); - expect(sequenceFlow.counters).to.have.property('discard', 1); return leave; }); @@ -1078,7 +759,6 @@ describe('Activity', () => { const leave = activity.waitFor('leave'); activity.run(); - expect(sequenceFlow.counters).to.have.property('discard', 1); return leave; }); @@ -1115,7 +795,6 @@ describe('Activity', () => { const leave = activity.waitFor('leave'); activity.discard(); - expect(sequenceFlow.counters).to.have.property('discard', 1); return leave; }); @@ -1152,7 +831,6 @@ describe('Activity', () => { await leave; - expect(sequenceFlow.counters).to.have.property('discard', 1); const runQ = activity.broker.getQueue('run-q'); @@ -1193,7 +871,6 @@ describe('Activity', () => { await leave; - expect(sequenceFlow.counters).to.have.property('discard', 1); }); it('next run can be discarded by discard', async () => { @@ -1770,106 +1447,6 @@ describe('Activity', () => { activity.run(); expect(sequenceFlow1.counters).to.have.property('take', 1); - expect(sequenceFlow2.counters).to.have.property('discard', 1); - - return leave; - }); - - it('discards outbound when discarded', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return []; - }, - getOutboundSequenceFlows() { - return sequenceFlows; - }, - }); - - const sequenceFlow = new SequenceFlow({ id: 'flow', parent: { id: 'process1' } }, context); - sequenceFlows.push(sequenceFlow); - - const activity = new Activity( - behaviours.CompleteBehaviour, - { - id: 'activity', - type: 'bpmn:Task', - parent: { - id: 'process1', - }, - }, - context - ); - - const leave = activity.waitFor('leave'); - - activity.discard(); - - expect(sequenceFlow.counters).to.have.property('discard', 1); - - return leave; - }); - - it('respects all outbound discarded during execution', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return []; - }, - getOutboundSequenceFlows() { - return sequenceFlows; - }, - }); - - const sequenceFlow1 = new SequenceFlow( - { id: 'flow1', sourceId: 'source1', targetId: 'target1', parent: { id: 'process1' } }, - context - ); - const sequenceFlow2 = new SequenceFlow( - { id: 'flow2', sourceId: 'source2', targetId: 'target2', parent: { id: 'process1' } }, - context - ); - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - function SpecialBehaviour({ broker }) { - return { - execute({ content }) { - broker.publish('execution', 'execute.completed', { - ...content, - outbound: [ - { - id: 'flow1', - action: 'discard', - }, - { - id: 'flow2', - action: 'discard', - }, - ], - }); - }, - }; - } - - const activity = new Activity( - SpecialBehaviour, - { - id: 'activity', - type: 'bpmn:ExclusiveGateway', - parent: { - id: 'process1', - }, - }, - context - ); - - const leave = activity.waitFor('leave'); - - activity.activate(); - activity.run(); - - expect(sequenceFlow1.counters).to.have.property('discard', 1); - expect(sequenceFlow2.counters).to.have.property('discard', 1); return leave; }); @@ -1937,201 +1514,10 @@ describe('Activity', () => { activity.run(); expect(sequenceFlow1.counters).to.have.property('take', 1); - expect(sequenceFlow2.counters).to.have.property('discard', 1); return leave; }); - it('discards flows and adds activity id to discard sequence when discarded', () => { - const sequenceFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return []; - }, - getOutboundSequenceFlows() { - return sequenceFlows; - }, - }); - - const sequenceFlow1 = new SequenceFlow( - { id: 'flow1', sourceId: 'activity', targetId: 'target1', parent: { id: 'process1' } }, - context - ); - const sequenceFlow2 = new SequenceFlow( - { id: 'flow2', sourceId: 'activity', targetId: 'target2', parent: { id: 'process1' } }, - context - ); - - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const messages = []; - sequenceFlow1.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - sequenceFlow2.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - - function SpecialBehaviour({ broker }) { - return { - execute({ content }) { - broker.publish('execution', 'execute.completed', { - ...content, - outbound: [ - { - id: 'flow1', - action: 'discard', - }, - { - id: 'flow2', - action: 'discard', - }, - ], - }); - }, - }; - } - - const activity = new Activity( - SpecialBehaviour, - { - id: 'activity', - type: 'bpmn:ExclusiveGateway', - parent: { - id: 'process1', - }, - }, - context - ); - - const leave = activity.waitFor('leave'); - - activity.activate(); - activity.run(); - - expect(messages).to.have.length(2); - expect(messages[0]).to.have.property('discardSequence').that.eql(['activity']); - expect(messages[1]).to.have.property('discardSequence').that.eql(['activity']); - - return leave; - }); - - it('discards flows and appends activity id to discard sequence if discarded', () => { - const inboundFlows = []; - const outboundFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return inboundFlows; - }, - getOutboundSequenceFlows() { - return outboundFlows; - }, - }); - - const sequenceFlow0 = new SequenceFlow({ id: 'flow0', sourceId: 'start', targetId: 'activity', parent: { id: 'process1' } }, context); - inboundFlows.push(sequenceFlow0); - - const sequenceFlow1 = new SequenceFlow( - { id: 'flow1', sourceId: 'activity', targetId: 'target1', parent: { id: 'process1' } }, - context - ); - const sequenceFlow2 = new SequenceFlow( - { id: 'flow2', sourceId: 'activity', targetId: 'target2', parent: { id: 'process1' } }, - context - ); - outboundFlows.push(sequenceFlow1, sequenceFlow2); - - const messages = []; - sequenceFlow1.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - sequenceFlow2.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - type: 'bpmn:ExclusiveGateway', - parent: { - id: 'process1', - }, - }, - context - ); - - const leave = activity.waitFor('leave'); - - activity.activate(); - sequenceFlow0.discard(); - - expect(messages).to.have.length(2); - expect(messages[0]).to.have.property('discardSequence').that.eql(['start', 'activity']); - expect(messages[1]).to.have.property('discardSequence').that.eql(['start', 'activity']); - - return leave; - }); - - it('join activity concats discard sequence when discarded', () => { - const inboundFlows = []; - const outboundFlows = []; - const context = getContext({ - getInboundSequenceFlows() { - return inboundFlows; - }, - getOutboundSequenceFlows() { - return outboundFlows; - }, - }); - - const sequenceFlow1 = new SequenceFlow({ id: 'flow1', sourceId: 'start1', parent: { id: 'process1' } }, context); - const sequenceFlow2 = new SequenceFlow({ id: 'flow2', sourceId: 'task', parent: { id: 'process1' } }, context); - - inboundFlows.push(sequenceFlow1, sequenceFlow2); - - const sequenceFlow3 = new SequenceFlow( - { id: 'flow3', sourceId: 'activity', targetId: 'target1', parent: { id: 'process1' } }, - context - ); - const sequenceFlow4 = new SequenceFlow( - { id: 'flow4', sourceId: 'activity', targetId: 'target2', parent: { id: 'process1' } }, - context - ); - outboundFlows.push(sequenceFlow3, sequenceFlow4); - - const messages = []; - sequenceFlow3.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - sequenceFlow4.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - isParallelGateway: true, - parent: { - id: 'process1', - }, - }, - context - ); - - const leave = activity.waitFor('leave'); - - activity.activate(); - sequenceFlow1.discard(); - sequenceFlow2.discard({ discardSequence: ['start2'] }); - - expect(messages).to.have.length(2); - expect(messages[0]).to.have.property('discardSequence').that.eql(['start1', 'start2', 'task', 'activity']); - expect(messages[1]).to.have.property('discardSequence').that.eql(['start1', 'start2', 'task', 'activity']); - - return leave; - }); }); describe('extensions', () => { @@ -2385,72 +1771,6 @@ describe('Activity', () => { expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); }); - it('discards activity outbound with discard sequence if attachedTo is discarded', () => { - const attachedTo = { - id: 'task', - parent: { - id: 'process1', - }, - broker: ActivityBroker().broker, - }; - - const sequenceFlows = []; - const context = getContext({ - getActivityById(id) { - if (id === 'task') return attachedTo; - }, - getOutboundSequenceFlows() { - return sequenceFlows; - }, - }); - - const sequenceFlow1 = new SequenceFlow( - { id: 'flow1', sourceId: 'activity', targetId: 'target1', parent: { id: 'process1' } }, - context - ); - const sequenceFlow2 = new SequenceFlow( - { id: 'flow2', sourceId: 'activity', targetId: 'target2', parent: { id: 'process1' } }, - context - ); - sequenceFlows.push(sequenceFlow1, sequenceFlow2); - - const messages = []; - sequenceFlow1.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - sequenceFlow2.broker.subscribeOnce('event', 'flow.discard', (_, { content }) => { - messages.push(content); - }); - - const activity = new Activity( - behaviours.Behaviour, - { - id: 'activity', - type: 'bpmn:BoundaryEvent', - behaviour: { - attachedTo: { - id: 'task', - }, - }, - parent: { - id: 'process1', - }, - }, - context - ); - - activity.activate(); - const leave = activity.waitFor('leave'); - - attachedTo.broker.publish('event', 'activity.discard', { id: 'task', type: 'bpmn:ServiceTask', discardSequence: ['start'] }); - - expect(messages).to.have.length(2); - expect(messages[0]).to.have.property('discardSequence').that.eql(['start', 'activity']); - expect(messages[1]).to.have.property('discardSequence').that.eql(['start', 'activity']); - - return leave; - }); - it('queues attached to starts if already running', () => { const attachedTo = { id: 'task', diff --git a/test/events/BoundaryEvent-test.js b/test/events/BoundaryEvent-test.js index c2cda912..acd40786 100644 --- a/test/events/BoundaryEvent-test.js +++ b/test/events/BoundaryEvent-test.js @@ -857,67 +857,6 @@ describe('BoundaryEvent', () => { expect(messages[1].content).to.have.property('id', 'service'); }); - it('adds attachedTo id to discardSequence when attachedTo completes', async () => { - context.environment.addService('test', (arg, next) => { - next(); - }); - - const task = context.getActivityById('service'); - const event = context.getActivityById('errorEvent'); - - let discardMessage; - - event.outbound[0].broker.subscribeOnce('event', 'flow.discard', (_, message) => { - discardMessage = message; - }); - - const leave = event.waitFor('leave'); - - event.activate(); - task.run(); - - await leave; - - expect(event.counters).to.have.property('discarded', 1); - - expect(discardMessage).to.be.ok; - expect(discardMessage.content).to.have.property('discardSequence').that.eql(['service', 'errorEvent']); - }); - - it('adds attachedTo id to discardSequence if discarded during execution', async () => { - let executing; - const execute = new Promise((resolve) => { - executing = resolve; - }); - - context.environment.addService('test', () => { - executing(); - }); - - const task = context.getActivityById('service'); - const event = context.getActivityById('errorEvent'); - - let discardMessage; - event.outbound[0].broker.subscribeOnce('event', 'flow.discard', (_, message) => { - discardMessage = message; - }); - - const leave = event.waitFor('leave'); - - event.activate(); - task.run(); - - await execute; - task.discard(); - - await leave; - - expect(event.counters).to.have.property('discarded', 1); - - expect(discardMessage).to.be.ok; - expect(discardMessage.content).to.have.property('discardSequence').that.eql(['service', 'errorEvent']); - }); - it('is discarded if attached activity is discarded', async () => { const task = context.getActivityById('service'); const event = context.getActivityById('errorEvent'); @@ -933,33 +872,6 @@ describe('BoundaryEvent', () => { expect(event.counters).to.have.property('discarded', 1); }); - it('is discarded with attached inbound discard sequence when attached is discarded', async () => { - const task = context.getActivityById('service'); - const event = context.getActivityById('errorEvent'); - - let discardMessage, taskDiscardMessage; - task.outbound[0].broker.subscribeOnce('event', 'flow.discard', (_, message) => { - taskDiscardMessage = message; - }); - event.outbound[0].broker.subscribeOnce('event', 'flow.discard', (_, message) => { - discardMessage = message; - }); - - const leave = event.waitFor('leave'); - - event.activate(); - task.activate(); - task.inbound[0].discard({ discardSequence: ['hittepa-1'] }); - - await leave; - - expect(event.counters).to.have.property('discarded', 1); - - expect(taskDiscardMessage).to.be.ok; - expect(taskDiscardMessage.content).to.have.property('discardSequence').that.eql(['hittepa-1', 'start', 'service']); - expect(discardMessage).to.be.ok; - expect(discardMessage.content).to.have.property('discardSequence').that.eql(['hittepa-1', 'start', 'errorEvent']); - }); }); describe('non-interrupting with error event definition', () => { diff --git a/test/feature/Process-feature.js b/test/feature/Process-feature.js index 717d4b35..6c51cf86 100644 --- a/test/feature/Process-feature.js +++ b/test/feature/Process-feature.js @@ -626,7 +626,6 @@ Feature('Process', () => { assertMessage('activity.end', 'decision'); assertMessage('activity.enter', 'join'); assertMessage('activity.start', 'join'); - assertMessage('activity.converge', 'join'); assertMessage('activity.leave', 'decision'); assertMessage('activity.end', 'join'); assertMessage('activity.enter', 'end'); @@ -840,7 +839,6 @@ Feature('Process', () => { assertMessage('activity.end', 'start'); assertMessage('activity.enter', 'fork'); assertMessage('activity.start', 'fork'); - assertMessage('activity.converge', 'fork'); assertMessage('activity.leave', 'start'); assertMessage('activity.end', 'fork'); diff --git a/test/flows/SequenceFlow-test.js b/test/flows/SequenceFlow-test.js index f20ad8ee..fd813166 100644 --- a/test/flows/SequenceFlow-test.js +++ b/test/flows/SequenceFlow-test.js @@ -124,7 +124,6 @@ describe('SequenceFlow', () => { expect(activity.outbound[1].counters).to.have.property('take', 1); expect(activity.outbound[2]).to.have.property('id', 'flow4withExpression'); - expect(activity.outbound[2].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); }); @@ -158,7 +157,6 @@ describe('SequenceFlow', () => { activity.run(); expect(activity.outbound[0]).to.have.property('id', 'flow2'); - expect(activity.outbound[0].counters).to.have.property('discard', 1); expect(activity.outbound[0].counters).to.have.property('take', 0); expect(activity.outbound[1]).to.have.property('id', 'flowWithSyncScript'); @@ -166,7 +164,6 @@ describe('SequenceFlow', () => { expect(activity.outbound[1].counters).to.have.property('take', 1); expect(activity.outbound[2]).to.have.property('id', 'flowWithScript'); - expect(activity.outbound[2].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); expect(activity.outbound[3]).to.have.property('id', 'flowWithoutCondition'); @@ -201,7 +198,6 @@ describe('SequenceFlow', () => { activity.run(); expect(activity.outbound[1]).to.have.property('id', 'flow3withExpression'); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 0); }); @@ -246,7 +242,6 @@ describe('SequenceFlow', () => { activity.run(); expect(activity.outbound[1]).to.have.property('id', 'flow3withExternalResource'); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 0); ctx.environment.variables.input = 4; @@ -254,7 +249,6 @@ describe('SequenceFlow', () => { activity.run(); expect(activity.outbound[1]).to.have.property('id', 'flow3withExternalResource'); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 1); expect(count).to.equal(2); @@ -649,6 +643,7 @@ describe('SequenceFlow', () => { { id: flow.id, isSequenceFlow: true, + sourceId: flow.sourceId, targetId: 'decision-1', type: 'bpmn:SequenceFlow', }, diff --git a/test/gateways/ExclusiveGateway-test.js b/test/gateways/ExclusiveGateway-test.js index 0f03daf0..2479d74c 100644 --- a/test/gateways/ExclusiveGateway-test.js +++ b/test/gateways/ExclusiveGateway-test.js @@ -42,9 +42,7 @@ describe('ExclusiveGateway', () => { expect(activity.outbound[0].counters).to.have.property('take', 1); expect(activity.outbound[0].counters).to.have.property('discard', 0); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('takes the first conditional flow even if more than one meet condition', async () => { @@ -61,9 +59,7 @@ describe('ExclusiveGateway', () => { expect(activity.outbound[0].counters).to.have.property('take', 1); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('takes first conditional flow regardless of position in definition', async () => { @@ -78,11 +74,9 @@ describe('ExclusiveGateway', () => { await leave; expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 1); expect(activity.outbound[1].counters).to.have.property('discard', 0); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('takes default flow if no other flows were taken', async () => { @@ -96,9 +90,7 @@ describe('ExclusiveGateway', () => { await leave; expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 1); expect(activity.outbound[2].counters).to.have.property('discard', 0); }); @@ -168,7 +160,6 @@ describe('ExclusiveGateway', () => { expect(activity.outbound[0].counters).to.have.property('take', 1); expect(activity.outbound[0].counters).to.have.property('discard', 0); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); }); it('discards all outbound if inbound was discarded', async () => { @@ -182,11 +173,8 @@ describe('ExclusiveGateway', () => { await leave; expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('emits error when no flow was taken', async () => { @@ -277,9 +265,7 @@ describe('ExclusiveGateway', () => { expect(activity.outbound[0].counters).to.have.property('take', 1); expect(activity.outbound[0].counters).to.have.property('discard', 0); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); }); @@ -324,8 +310,6 @@ describe('ExclusiveGateway', () => { bp2.signal({ id: 'usertask' }); expect(bp2.counters).to.have.property('completed', 1); - const end = bp2.getActivityById('end'); - expect(end.counters).to.have.property('discarded', 1); }); it('save state on decision to usertask regardless of sequenceFlow order in source', async () => { @@ -369,8 +353,6 @@ describe('ExclusiveGateway', () => { bp2.signal({ id: 'usertask' }); expect(bp2.counters).to.have.property('completed', 1); - const end = bp2.getActivityById('end'); - expect(end.counters).to.have.property('discarded', 1); }); }); }); diff --git a/test/gateways/InclusiveGateway-test.js b/test/gateways/InclusiveGateway-test.js index 4c3d1864..7590bca1 100644 --- a/test/gateways/InclusiveGateway-test.js +++ b/test/gateways/InclusiveGateway-test.js @@ -42,9 +42,7 @@ describe('InclusiveGateway', () => { expect(activity.outbound[0].counters).to.have.property('take', 1); expect(activity.outbound[0].counters).to.have.property('discard', 0); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('discards default outbound if one outbound was taken', async () => { @@ -59,11 +57,9 @@ describe('InclusiveGateway', () => { await leave; expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 1); expect(activity.outbound[1].counters).to.have.property('discard', 0); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('discards default outbound if more than one outbound was taken', async () => { @@ -83,7 +79,6 @@ describe('InclusiveGateway', () => { expect(activity.outbound[1].counters).to.have.property('take', 1); expect(activity.outbound[1].counters).to.have.property('discard', 0); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('takes default outbound if no conditional flow was taken', async () => { @@ -99,9 +94,7 @@ describe('InclusiveGateway', () => { await leave; expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 1); expect(activity.outbound[2].counters).to.have.property('discard', 0); }); @@ -119,11 +112,8 @@ describe('InclusiveGateway', () => { await leave; expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 1); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); expect(activity.outbound[2].counters).to.have.property('take', 0); - expect(activity.outbound[2].counters).to.have.property('discard', 1); }); it('emits error if no flow was taken', async () => { diff --git a/test/gateways/ParallelGateway-test.js b/test/gateways/ParallelGateway-test.js index 57f06259..4791427f 100644 --- a/test/gateways/ParallelGateway-test.js +++ b/test/gateways/ParallelGateway-test.js @@ -1,3 +1,4 @@ +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; @@ -19,7 +20,7 @@ describe('ParallelGateway', () => { let context; beforeEach(async () => { - context = await testHelpers.context(source); + context = await testHelpers.context(source, { settings: { skipDiscard: false } }); }); it('takes all outbound', async () => { @@ -57,14 +58,24 @@ describe('ParallelGateway', () => { describe('join', () => { describe('join from different source activities', () => { - const sourceSameSourceId = ` + const source = ` - - - + + + + + + \${environment.variables.take1} + + + \${environment.variables.take2} + + + \${environment.variables.take3} + @@ -77,91 +88,47 @@ describe('ParallelGateway', () => { `; - let context; - beforeEach(async () => { - context = await testHelpers.context(sourceSameSourceId); - }); - - it('waits for all inbound', async () => { - const activity = context.getActivityById('join'); - - activity.activate(); - - const leave = activity.waitFor('leave'); - activity.inbound[0].take(); - activity.inbound[1].take(); - activity.inbound[2].take(); - + async function runWith(takes) { + const context = await testHelpers.context(source); + const definition = new Definition(context, { + variables: { take1: takes[0], take2: takes[1], take3: takes[2] }, + }); + const leave = definition.waitFor('leave'); + definition.run(); await leave; - - const outboundFlow = activity.outbound[0]; - expect(outboundFlow.counters).to.have.property('take', 1); - expect(outboundFlow.counters).to.have.property('discard', 0); + return definition.getActivityById('join'); + } + + it('takes outbound once when all three branches lead to a task that takes', async () => { + const join = await runWith([true, true, true]); + expect(join.counters).to.deep.equal({ taken: 1, discarded: 0 }); + expect(join.outbound[0].counters).to.have.property('take', 1); + expect(join.outbound[0].counters).to.have.property('discard', 0); }); - it('discards outbound if all inbound were discarded', async () => { - const activity = context.getActivityById('join'); - - activity.activate(); - - const leave = activity.waitFor('leave'); - activity.inbound[0].discard(); - activity.inbound[1].discard(); - activity.inbound[2].discard(); - - await leave; - - const outboundFlow = activity.outbound[0]; - expect(outboundFlow.counters).to.have.property('discard', 1); - expect(outboundFlow.counters).to.have.property('take', 0); + it('discards outbound when all three branches skip their task (all inbound discarded)', async () => { + const join = await runWith([false, false, false]); + expect(join.counters).to.deep.equal({ taken: 0, discarded: 1 }); + expect(join.outbound[0].counters).to.have.property('take', 0); + expect(join.outbound[0].counters).to.have.property('discard', 1); }); - it('takes outbound if one inbound is discarded', async () => { - const activity = context.getActivityById('join'); - - activity.activate(); - - const leave = activity.waitFor('leave'); - activity.inbound[0].take(); - activity.inbound[1].take(); - activity.inbound[2].discard(); - - await leave; - - expect(activity.outbound[0].counters).to.have.property('take', 1); - expect(activity.outbound[0].counters).to.have.property('discard', 0); + it('takes outbound when at least one branch takes (one discarded, two taken)', async () => { + const join = await runWith([true, true, false]); + expect(join.counters).to.deep.equal({ taken: 1, discarded: 0 }); + expect(join.outbound[0].counters).to.have.property('take', 1); }); - it('takes outbound if all but one inbound is discarded', async () => { - const activity = context.getActivityById('join'); - - activity.activate(); - - const leave = activity.waitFor('leave'); - activity.inbound[0].take(); - activity.inbound[1].discard(); - activity.inbound[2].discard(); - - await leave; - - expect(activity.outbound[0].counters).to.have.property('take', 1); - expect(activity.outbound[0].counters).to.have.property('discard', 0); + it('takes outbound when only one branch takes (two discarded, one taken)', async () => { + const join = await runWith([true, false, false]); + expect(join.counters).to.deep.equal({ taken: 1, discarded: 0 }); + expect(join.outbound[0].counters).to.have.property('take', 1); }); - it('takes outbound if first inbound is discarded but the rest are taken', async () => { - const activity = context.getActivityById('join'); - - activity.activate(); - - const leave = activity.waitFor('leave'); - activity.inbound[0].discard(); - activity.inbound[1].take(); - activity.inbound[2].take(); - - await leave; - - expect(activity.outbound[0].counters).to.have.property('take', 1); - expect(activity.outbound[0].counters).to.have.property('discard', 0); + it('takes outbound regardless of which branch is discarded (first discarded, rest taken)', async () => { + const join = await runWith([false, true, true]); + expect(join.counters).to.deep.equal({ taken: 1, discarded: 0 }); + expect(join.outbound[0].counters).to.have.property('take', 1); }); }); @@ -182,7 +149,7 @@ describe('ParallelGateway', () => { let context; beforeEach(async () => { - context = await testHelpers.context(sourceSameSourceId); + context = await testHelpers.context(sourceSameSourceId, { settings: { skipDiscard: false } }); }); it('waits for one inbound', async () => { diff --git a/test/tasks/ServiceTask-test.js b/test/tasks/ServiceTask-test.js index 81c698f9..02b83b7f 100644 --- a/test/tasks/ServiceTask-test.js +++ b/test/tasks/ServiceTask-test.js @@ -6,7 +6,7 @@ import { ActivityError } from '../../src/error/Errors.js'; describe('ServiceTask', () => { describe('behaviour', () => { - it('no service on execution returns error if disableDummyService is enabled', async () => { + it('no service on execution returns error if enableDummyService is false', async () => { const source = ` @@ -15,7 +15,7 @@ describe('ServiceTask', () => { `; - const context = await testHelpers.context(source, { settings: { skipDiscard: false, disableDummyService: true } }); + const context = await testHelpers.context(source, { settings: { skipDiscard: false, enableDummyService: false } }); const task = context.getActivityById('task'); let error; diff --git a/test/tasks/SubProcess-test.js b/test/tasks/SubProcess-test.js index 28952b50..e9ff3a17 100644 --- a/test/tasks/SubProcess-test.js +++ b/test/tasks/SubProcess-test.js @@ -118,6 +118,7 @@ describe('SubProcess', () => { }); it('discarded child activity still completes sub process', async () => { + context = await testHelpers.context(subProcessSource, { settings: { skipDiscard: false } }); const subProcess = context.getActivityById('subProcess'); subProcess.activate(); From 01a81a3659db3da0e12df826638296cceb823b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 10 May 2026 07:41:10 +0200 Subject: [PATCH 09/31] revisit link event definition --- dist/Environment.js | 3 +- dist/Tracker.js | 1 + dist/activity/Activity.js | 108 +++----- dist/activity/ActivityExecution.js | 5 +- dist/definition/Definition.js | 2 +- dist/eventDefinitions/LinkEventDefinition.js | 184 +++++-------- dist/flows/SequenceFlow.js | 38 ++- dist/gateways/ParallelGateway.js | 246 +++++++++++++++++- dist/process/ProcessExecution.js | 150 +++++------ src/activity/Activity.js | 4 - src/eventDefinitions/LinkEventDefinition.js | 17 +- src/process/ProcessExecution.js | 6 + test/activities-test.js | 196 +++++++------- test/activity/Activity-test.js | 7 - .../LinkEventDefinition-test.js | 48 +++- test/events/BoundaryEvent-test.js | 1 - test/feature/link-as-goto-feature.js | 53 +++- test/feature/shake-feature.js | 72 +++++ test/gateways/EventBasedGateway-test.js | 2 +- test/resources/link-to-parallel-join.bpmn | 55 ++-- 20 files changed, 720 insertions(+), 478 deletions(-) diff --git a/dist/Environment.js b/dist/Environment.js index 7f21606f..fb87034a 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -97,11 +97,12 @@ Environment.prototype.assignVariables = function assignVariables(newVars) { }; }; Environment.prototype.assignSettings = function assignSettings(newSettings) { - if (!newSettings || typeof newSettings !== 'object') return; + if (!newSettings || typeof newSettings !== 'object') return this; this.settings = { ...this.settings, ...newSettings }; + return this; }; Environment.prototype.getScript = function getScript(...args) { return this.scripts.getScript(...args); diff --git a/dist/Tracker.js b/dist/Tracker.js index 4cc56101..682e07ff 100644 --- a/dist/Tracker.js +++ b/dist/Tracker.js @@ -36,6 +36,7 @@ ActivityTracker.prototype.track = function track(routingKey, message) { this._executing(executionId); break; case 'activity.execution.outbound.take': + case 'activity.converge': case 'activity.detach': case 'activity.call': case 'activity.wait': diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index ddf139c9..60a84615 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -85,36 +85,34 @@ function Activity(Behaviour, activityDef, context) { inboundTriggers = inboundSequenceFlows.slice(); } const outboundSequenceFlows = context.getOutboundSequenceFlows(id); - const isParallelJoin = activityDef.isParallelGateway && inboundSequenceFlows.length > 1; + const inboundSourceIds = new Set(inboundSequenceFlows.map(({ + sourceId + }) => sourceId)); + const isParallelJoin = activityDef.isParallelGateway && inboundSourceIds.size > 1; this[kFlows] = { inboundSequenceFlows, inboundAssociations, inboundTriggers, outboundSequenceFlows, - outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows), - ...(isParallelJoin && { - inboundJoinFlows: new Set(), - inboundSourceIds: new Map(inboundSequenceFlows.map(({ - sourceId - }) => [sourceId, 0])) - }) + outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows) }; this[kFlags] = { isEnd: !outboundSequenceFlows.length, - isStart: !inboundTriggers.length && !behaviour.triggeredByEvent, + isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, isMultiInstance: !!behaviour.loopCharacteristics, isForCompensation, attachedTo, isTransaction: activityDef.isTransaction, isParallelJoin, + isParallelGateway: activityDef.isParallelGateway, isThrowing: activityDef.isThrowing, isCatching: activityDef.isCatching, lane: activityDef.lane?.id }; this[kExec] = new Map(); this[kMessageHandlers] = { - onInbound: isParallelJoin ? this._onJoinInbound.bind(this) : this._onInbound.bind(this), + onInbound: this._onInbound.bind(this), onRunMessage: this._onRunMessage.bind(this), onApiMessage: this._onApiMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this) @@ -252,9 +250,9 @@ Object.defineProperties(Activity.prototype, { return this.context.getActivityParentById(this.id); } }, - expectedInboundSources: { + initialized: { get() { - return new Map(this[kFlows].inboundSourceIds); + return !!this[kExec]?.get('initExecutionId'); } } }); @@ -269,9 +267,6 @@ Activity.prototype.deactivate = function deactivate() { this.removeInboundListeners(); broker.cancel('_run-on-inbound'); broker.cancel('_format-consumer'); - if (this.isParallelJoin) this[kFlows].inboundSourceIds = new Map(this[kFlows].inboundSequenceFlows.map(({ - sourceId - }) => [sourceId, 0])); }; Activity.prototype.init = function init(initContent) { const id = this.id; @@ -326,7 +321,8 @@ Activity.prototype.getState = function getState() { }; Activity.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running activity <${this.id}>`); - if (!state) return; + if (!state) return; // TODO: return this + this.stopped = state.stopped; this.status = state.status; const exec = this[kExec]; @@ -472,7 +468,7 @@ Activity.prototype._discardRun = function discardRun() { this._consumeRunQ(); }; Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { - if (this.isParallelJoin) { + if (this[kFlags].isParallelGateway) { const message = (0, _messageHelper.cloneMessage)(sourceMessage, { join: this.id }); @@ -489,12 +485,15 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { }; Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { const message = (0, _messageHelper.cloneMessage)(sourceMessage); - message.content.sequence = message.content.sequence || []; - message.content.sequence.push({ + const sequence = message.content.sequence = message.content.sequence || []; + const count = 1; + const looped = sequence?.find(f => f.id === this.id); + sequence.push({ id: this.id, - type: this.type + type: this.type, + count: looped ? looped.count + 1 : count }); - this.broker.publish('event', 'activity.shake.start', message.content, { + this.broker.publish('api', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); @@ -518,12 +517,6 @@ Activity.prototype._consumeInbound = function consumeInbound() { if (this.status || !this[kFlows].inboundTriggers.length) return; const inboundQ = this.broker.getQueue('inbound-q'); const onInbound = this[kMessageHandlers].onInbound; - if (this[kFlags].isParallelJoin) { - return inboundQ.assertConsumer(onInbound, { - consumerTag: '_run-on-inbound', - prefetch: 1000 - }); - } return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); @@ -548,50 +541,14 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { { let discardSequence; if (content.discardSequence) discardSequence = content.discardSequence.slice(); - return this._runDiscard({ + const context = { inbound, discardSequence - }); + }; + return this[kFlags].isParallelGateway ? this.run(context) : this._runDiscard(context); } } }; -Activity.prototype._onJoinInbound = function onJoinInbound(routingKey, message) { - const { - inboundJoinFlows, - inboundSourceIds - } = this[kFlows]; - const expectedInboundCount = [...inboundSourceIds.values()].reduce((s, a) => s + (a || 1)); - inboundJoinFlows.add(message); - const remaining = expectedInboundCount - inboundJoinFlows.size; - if (remaining) { - return this.logger.debug(`<${this.id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`); - } - const inbound = []; - let taken; - for (const im of inboundJoinFlows) { - if (im.fields.routingKey === 'flow.take') taken = true; - im.ack(); - inbound.push((0, _messageHelper.cloneContent)(im.content)); - } - const discardSequence = new Set(); - if (!taken) { - for (const im of inboundJoinFlows) { - if (!im.content.discardSequence) continue; - for (const sourceId of im.content.discardSequence) { - discardSequence.add(sourceId); - } - } - } - inboundJoinFlows.clear(); - this.broker.cancel('_run-on-inbound'); - if (!taken) return this._runDiscard({ - inbound, - discardSequence: [...discardSequence] - }); - return this.run({ - inbound - }); -}; Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message) { const { fields, @@ -609,12 +566,6 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message break; } case 'flow.shake': - { - if (this.isParallelJoin) { - let count = this[kFlows].inboundSourceIds.get(content.sourceId); - this[kFlows].inboundSourceIds.set(content.sourceId, ++count); - } - } case 'activity.shake.start': return this._onShakeMessage(message); case 'association.take': @@ -637,6 +588,7 @@ Activity.prototype._pauseRunQ = function pauseRunQ() { }; Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, messageProperties) { switch (routingKey) { + case 'run.execute.passthrough': case 'run.outbound.discard': case 'run.outbound.take': case 'run.next': @@ -841,11 +793,13 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, } case 'execution.cancel': case 'execution.discard': - this.status = 'discarded'; - broker.publish('run', 'run.discarded', content, { - correlationId - }); - break; + { + this.status = 'discarded'; + broker.publish('run', 'run.discarded', content, { + correlationId + }); + break; + } default: { this.status = 'executed'; diff --git a/dist/activity/ActivityExecution.js b/dist/activity/ActivityExecution.js index cf913e74..44f29f97 100644 --- a/dist/activity/ActivityExecution.js +++ b/dist/activity/ActivityExecution.js @@ -246,7 +246,7 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete isRootScope } = message.content; if (!isRootScope) { - this._debug('completed sub execution'); + this._debug('completed sub execution', executionId); if (!keep) message.ack(); if (postponed.size === 1) { const onlyMessage = postponed.values().next().value; @@ -353,11 +353,10 @@ ActivityExecution.prototype._debug = function debug(logMessage, executionId) { this.activity.logger.debug(`<${executionId} (${this.id})> ${logMessage}`); }; function getExecuteMessage(message) { - const result = (0, _messageHelper.cloneMessage)(message, { + return (0, _messageHelper.cloneMessage)(message, { ...(message.fields.redelivered && { isRecovered: true }), ignoreIfExecuting: undefined }); - return result; } \ No newline at end of file diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index 860c02ba..2e79879e 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -34,7 +34,7 @@ function Definition(context, options) { this.name = name; let environment; if (options) { - environment = this.environment = context.environment.clone(options); + environment = this.environment = context.environment.clone(options).assignSettings(options.settings); this.context = context.clone(environment); } else { environment = this.environment = context.environment; diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index 2daea74f..cc7854f5 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -6,8 +6,6 @@ Object.defineProperty(exports, "__esModule", { exports.default = LinkEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); const kExecuteMessage = Symbol.for('executeMessage'); function LinkEventDefinition(activity, eventDefinition) { const { @@ -22,7 +20,8 @@ function LinkEventDefinition(activity, eventDefinition) { } = eventDefinition; this.id = id; this.type = type; - const reference = this.reference = { + this.reference = { + id: behaviour.name, linkName: behaviour.name, referenceType: 'link' }; @@ -30,22 +29,9 @@ function LinkEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - this[kCompleted] = false; - if (!isThrowing) { - const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(reference.linkName)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { - autoDelete: false, - durable: true - }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { - durable: true - }); - broker.subscribeTmp('api', `activity.shake.${reference.referenceType}`, this._onApiMessage.bind(this), { - noAck: true - }); - } else { - broker.subscribeTmp('event', 'activity.shake.start', (_, msg) => { - broker.publish('event', `activity.shake.${reference.referenceType}`, (0, _messageHelper.cloneContent)(msg.content, { + if (isThrowing) { + broker.subscribeTmp('api', 'activity.shake.start', (_, msg) => { + broker.publish('event', `activity.shake.${this.reference.referenceType}`, (0, _messageHelper.cloneContent)(msg.content, { sourceId: this.id, targetId: undefined, message: { @@ -60,9 +46,22 @@ function LinkEventDefinition(activity, eventDefinition) { consumerTag: '_link-parent-shake', priority: 1000 }); - broker.subscribeTmp('event', 'activity.discard', this._onDiscard.bind(this), { + } else { + broker.subscribeTmp('api', `activity.shake.${this.reference.referenceType}`, this._onShakeMessage.bind(this), { + noAck: true, + consumerTag: '_link-catch-shake' + }); + const queueName = `link-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(this.reference.linkName)}-q`; + broker.assertQueue(queueName, { + autoDelete: false, + durable: true + }); + broker.bindQueue(queueName, 'api', '*.link.#', { + durable: true + }); + broker.consume(queueName, this._onLinkApiMessage.bind(this), { noAck: true, - consumerTag: '_link-parent-discard' + consumerTag: '_link-catch-listener' }); } } @@ -76,37 +75,34 @@ LinkEventDefinition.prototype.execute = function execute(executeMessage) { }; LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent.executionId; - this[kMessageQ].consume(this._onCatchLink.bind(this), { - noAck: true, - consumerTag: `_api-link-${executionId}` - }); - if (this[kCompleted]) return; + const linkMessage = executeContent.message ?? executeContent.input ?? { + ...this.reference + }; + this.logger.debug(`<${executionId} (${this.activity.id})> caught link ${this.reference.linkName}`); const broker = this.broker; - const onApiMessage = this._onApiMessage.bind(this); - broker.subscribeTmp('api', `activity.stop.${parentExecutionId}`, onApiMessage, { - noAck: true, - consumerTag: `_api-parent-${executionId}` - }); - broker.subscribeTmp('api', `activity.#.${executionId}`, onApiMessage, { - noAck: true, - consumerTag: `_api-${executionId}` - }); - this._debug(`expect link ${this.reference.linkName}`); - const waitContent = (0, _messageHelper.cloneContent)(executeContent, { - executionId: parentExecutionId, + const catchContent = (0, _messageHelper.cloneContent)(executeContent, { link: { ...this.reference - } + }, + message: { + ...linkMessage + }, + executionId: parentExecutionId }); - waitContent.parent = (0, _messageHelper.shiftParent)(parent); - broker.publish('event', 'activity.wait', waitContent); + catchContent.parent = (0, _messageHelper.shiftParent)(parent); + broker.publish('event', 'activity.catch', catchContent, { + type: 'catch' + }); + return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent, { + output: linkMessage, + state: 'catch' + })); }; LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; @@ -131,90 +127,32 @@ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessag }); return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); }; -LinkEventDefinition.prototype._onCatchLink = function onCatchLink(routingKey, message) { +LinkEventDefinition.prototype._onLinkApiMessage = function onLinkApiMessage(_, message) { + if (message.properties.type !== 'link') return; if (message.content.message?.linkName !== this.reference.linkName) return; - if (message.content.state === 'discard') return this._discard(); - return this._complete('caught', message.content.message); -}; -LinkEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { - switch (message.properties.type) { - case 'discard': - { - return this._discard(); - } - case 'stop': - { - this._stop(); - break; - } - case 'shake': - { - if (message.content.message?.linkName !== this.reference.linkName) return; - const content = (0, _messageHelper.cloneContent)(message.content, { - targetId: this.id, - isLinked: true - }); - content.sequence = content.sequence || []; - content.sequence.push({ - id: this.id, - type: this.type - }); - return this.broker.publish('event', 'activity.shake.linked', content, { - persistent: false, - type: 'shake' - }); - } - } + if (this.activity.isRunning) return; + this.activity.run(message.content.message); }; -LinkEventDefinition.prototype._complete = function complete(verb, output) { - this[kCompleted] = true; - this._stop(); - this._debug(`${verb} link ${this.reference.linkName}`); - const executeContent = this[kExecuteMessage].content; - const parent = executeContent.parent; - const catchContent = (0, _messageHelper.cloneContent)(executeContent, { - link: { - ...this.reference - }, - message: { - ...output - }, - executionId: parent.executionId +LinkEventDefinition.prototype._onShakeMessage = function onShakeMessage(_, message) { + if (message.properties.type !== 'shake') return; + if (message.content.message?.linkName !== this.reference.linkName) return; + const content = (0, _messageHelper.cloneContent)(message.content, { + targetId: this.id, + isLinked: true }); - catchContent.parent = (0, _messageHelper.shiftParent)(parent); - const broker = this.broker; - broker.publish('event', 'activity.catch', catchContent, { - type: 'catch' + content.sequence = content.sequence || []; + content.sequence.push({ + id: this.id, + type: this.type }); - return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent, { - output, - state: 'catch' - })); -}; -LinkEventDefinition.prototype._discard = function discard() { - this[kCompleted] = true; - this._stop(); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content)); -}; -LinkEventDefinition.prototype._stop = function stop() { - const broker = this.broker, - executionId = this.executionId; - broker.cancel(`_api-link-${executionId}`); - broker.cancel(`_api-parent-${executionId}`); - broker.cancel(`_api-${executionId}`); - this[kMessageQ].purge(); -}; -LinkEventDefinition.prototype._onDiscard = function onDiscard(_, message) { - this.broker.publish('event', 'activity.link.discard', (0, _messageHelper.cloneContent)(message.content, { - message: { - ...this.reference - }, - state: 'discard' - }), { - type: 'link', - delegate: true + this.broker.publish('event', 'activity.shake.linked', content, { + persistent: false, + type: 'shake' }); -}; -LinkEventDefinition.prototype._debug = function debug(msg) { - this.logger.debug(`<${this.executionId} (${this.activity.id})> ${msg}`); + const outbound = this.activity.outbound; + if (outbound?.length) { + for (const flow of outbound) flow.shake({ + content: (0, _messageHelper.cloneContent)(content) + }); + } }; \ No newline at end of file diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index eec72fd3..08a480ab 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -75,7 +75,7 @@ SequenceFlow.prototype.take = function take(content) { }; SequenceFlow.prototype.discard = function discard(content = {}) { const sequenceId = content?.sequenceId ?? (0, _shared.getUniqueId)(this.id); - const discardSequence = content.discardSequence = (content.discardSequence || []).slice(); + const discardSequence = content.discardSequence = content.discardSequence?.slice() || []; if (discardSequence.indexOf(this.targetId) > -1) { ++this[kCounters].looped; this.logger.debug(`<${this.id}> discard loop detected <${this.sourceId}> -> <${this.targetId}>. Stop.`); @@ -109,37 +109,33 @@ SequenceFlow.prototype.stop = function stop() { this.broker.stop(); }; SequenceFlow.prototype.shake = function shake(message) { - const content = (0, _messageHelper.cloneContent)(message.content, { - sourceId: this.sourceId, - targetId: this.targetId - }); + const content = (0, _messageHelper.cloneContent)(message.content); content.sequence = content.sequence || []; - const hasCondition = !!this.behaviour.conditionExpression; - content.sequence.push({ + const info = { id: this.id, type: this.type, isSequenceFlow: true, - hasCondition, + sourceId: this.sourceId, targetId: this.targetId - }); + }; if (content.id === this.targetId) { + content.sequence.push(info); return this.broker.publish('event', 'flow.shake.loop', content, { persistent: false, type: 'shake' }); + } else if (content.sequence?.find(f => f.id === this.id)) { + return this.broker.publish('event', 'flow.shake.loop', content, { + persistent: false, + type: 'shake' + }); + } else { + content.sequence.push(info); + this.broker.publish('event', 'flow.shake', content, { + persistent: false, + type: 'shake' + }); } - for (const s of message.content.sequence || []) { - if (s.id === this.id) { - return this.broker.publish('event', 'flow.shake.loop', content, { - persistent: false, - type: 'shake' - }); - } - } - this.broker.publish('event', 'flow.shake', content, { - persistent: false, - type: 'shake' - }); }; SequenceFlow.prototype.getCondition = function getCondition() { const conditionExpression = this.behaviour.conditionExpression; diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index cabf5fd8..5c4ab8f4 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -8,24 +8,246 @@ exports.default = ParallelGateway; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _messageHelper = require("../messageHelper.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } +const STATE_MONTITORING = 'monitoring'; +const STATE_SETUP = 'setup'; +const kPeers = Symbol.for('peers'); +const kInboundSourceIds = Symbol.for('inbound peers'); +const kTargets = Symbol.for('targets'); +const kExecuteMessage = Symbol.for('executeMessage'); function ParallelGateway(activityDef, context) { - return new _Activity.default(ParallelGatewayBehaviour, { + const activity = new _Activity.default(ParallelGatewayBehaviour, { ...activityDef, isParallelGateway: true }, context); + const id = this.id = activity.id; + activity.broker.cancel('_api-shake'); + activity.broker.subscribeTmp('api', 'activity.shake.continue', onApiShake, { + noAck: true, + consumerTag: '_api-shake', + priority: 1000 + }); + const peers = activity[kPeers] = new Map(activity.inbound.map(({ + id: flowId, + sourceId + }) => [flowId, new Set([sourceId])])); + return activity; + function onApiShake(_, message) { + const collect = new Set(); + let sequenceFlow; + for (const s of message.content.sequence) { + if (s.isSequenceFlow) { + sequenceFlow = s; + } else if (s.id === id) { + const peer = peers.get(sequenceFlow.id); + for (const c of collect) { + peer.add(c); + } + collect.clear(); + } else { + collect.add(s.id); + } + } + activity.logger.debug(`<${activity.id}> collected parallel gateway peers`); + activity.shake(message); + } } function ParallelGatewayBehaviour(activity) { + this.id = activity.id; + this.type = activity.type; + this.activity = activity; + this.broker = activity.broker; + this.inbound = new Set(); + this.isConverging = new Set(activity.inbound.map(({ + sourceId + }) => sourceId)).size > 1; + this[kExecuteMessage] = undefined; +} +Object.defineProperties(ParallelGatewayBehaviour.prototype, { + executionId: { + get() { + return this[kExecuteMessage]?.content.executionId; + } + } +}); +ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { + const routingKey = executeMessage.fields.routingKey; + const isRedelivered = executeMessage.fields.redelivered; + const executeContent = executeMessage.content; + if (executeContent.isRootScope) { + this[kExecuteMessage] = executeMessage; + switch (routingKey) { + case 'execute.start': + { + if (!isRedelivered && executeContent.state === STATE_SETUP && !this.peerMonitor.isRunning) { + return this._complete(); + } + if (executeContent.state !== 'start' && !isRedelivered) { + return; + } + return this.setup(executeMessage); + } + } + } +}; +ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { + const peerIds = new Set([...this.activity[kPeers].values()].map(v => [...v]).flat()); + this[kTargets] = new Map([...peerIds].map(pid => [pid, this.activity.getActivityById(pid)])); + this.peerMonitor = new PeerMonitor(this.activity, this.activity[kInboundSourceIds], this[kTargets]); + const message = this[kExecuteMessage] = (0, _messageHelper.cloneMessage)(executeMessage); + const executeContent = message.content; const { - id, - type, - broker - } = activity; - this.id = id; - this.type = type; - this.broker = broker; + executionId + } = executeContent; + this.inbound.add((0, _messageHelper.cloneContent)(executeMessage.content.inbound[0])); + this.broker.subscribeOnce('api', `activity.stop.${executionId}`, () => this._stop(), { + consumerTag: '_api-stop-execution' + }); + this.broker.subscribeTmp('execution', 'execute.completed', this._onExecuteMessage.bind(this), { + noAck: true, + consumerTag: '_parallel-execution-execute-tag' + }); + this.broker.subscribeTmp('execution', 'execute.start', this._onPeerEnterMessage.bind(this), { + noAck: true, + consumerTag: '_parallel-execution-peer-enter-tag' + }); + this.peerMonitor.execute(message); + const inboundQ = this.broker.getQueue('inbound-q'); + inboundQ.consume((_, inboundMessage) => { + this.inbound.add(inboundMessage); + message.content.inbound.push((0, _messageHelper.cloneContent)(inboundMessage.content)); + this.peerMonitor.execute(message); + }, { + consumerTag: '_converging-inbound', + exclusive: true, + prefetch: 10000 + }); + if (this.isConverging) { + this.broker.publish('event', 'activity.converge', (0, _messageHelper.cloneContent)(executeContent)); + } + return this.broker.publish('execution', 'execute.start', (0, _messageHelper.cloneContent)(executeMessage.content, { + preventComplete: true, + state: STATE_SETUP + })); +}; +ParallelGatewayBehaviour.prototype._onExecuteMessage = function onExecuteMessage(routingKey, message) { + this.activity.logger.debug(`<${this.executionId} (${this.id})> received completed from <${message.content.id}>`); + if (this.peerMonitor._onCompleteMessage(routingKey, message)) { + return this._complete(); + } +}; +ParallelGatewayBehaviour.prototype._onPeerEnterMessage = function onPeerEnterMessage(_, message) { + if (!message.properties.monitor) return; + const peer = this.peerMonitor.watching.get(message.content.id); + if (peer) this.peerMonitor.running.set(message.content.id, peer); +}; +ParallelGatewayBehaviour.prototype._complete = function complete() { + const take = this.peerMonitor.inbound.some(({ + action + }) => action === 'take'); + this.broker.cancel('_converging-inbound', false); + this._stop(); + const state = take ? 'completed' : 'discard'; + this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring with state: ${state}`); + const content = (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + isRootScope: true, + state + }); + content.inbound = this.peerMonitor.inbound; + return this.broker.publish('execution', `execute.${state}`, content); +}; +ParallelGatewayBehaviour.prototype._stop = function stop() { + this.broker.cancel('_converging-inbound'); + this.broker.cancel('_api-stop-execution'); + this.broker.cancel('_parallel-execution-execute-tag'); + this.broker.cancel('_parallel-execution-peer-enter-tag'); + this.peerMonitor.stop(); +}; +function PeerMonitor(activity, peers, targets) { + this.activity = activity; + this.id = activity.id; + this.broker = activity.broker; + this.running = 0; + this.index = 0; + this.discarded = 0; + this.running = new Map(); + this.watching = new Map(); + this.peers = peers; + this.targets = targets; + this.touched = new Set(); + this.inbound = []; } -ParallelGatewayBehaviour.prototype.execute = function execute({ - content -}) { - this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(content)); +Object.defineProperty(PeerMonitor.prototype, 'isRunning', { + get() { + return this.running.size > 0; + } +}); +PeerMonitor.prototype.execute = function execute(executeMessage) { + const message = (0, _messageHelper.cloneMessage)(executeMessage); + const inbound = message.content.inbound.pop(); + this.inbound.push((0, _messageHelper.cloneContent)(inbound)); + this.activity.logger.debug(`<${executeMessage.content.executionId} (${this.id})> start monitoring inbound <${inbound.id}> peers`); + this.activity.broker.publish('execution', 'execute.start', { + ...(0, _messageHelper.cloneContent)(executeMessage.content), + inbound: this.inbound.slice(), + state: STATE_MONTITORING, + preventComplete: true + }); + this.touched.add(inbound.sourceId); + for (const target of this.targets.values()) { + this.monitor(target); + } + return this.running.size; +}; +PeerMonitor.prototype.monitor = function monitor(peerActivity) { + if (this.watching.has(peerActivity.id)) return; + this.activity.logger.debug(`<${this.id}> monitor <${peerActivity.id}> with status: ${peerActivity.status}`); + this.watching.set(peerActivity.id, peerActivity); + if (peerActivity.status || peerActivity.initialized) { + this.running.set(peerActivity.id, peerActivity); + } + peerActivity.broker.createShovel(`_on-enter-${this.id}`, { + exchange: 'event', + pattern: 'activity.enter' + }, { + broker: this.broker, + exchange: 'execution', + exchangeKey: 'execute.start', + publishProperties: { + monitor: true + } + }, { + cloneMessage(sourceMessage) { + return (0, _messageHelper.cloneMessage)(sourceMessage, { + isRootScope: false + }); + } + }); + peerActivity.broker.createShovel(`_on-leave-${this.id}`, { + exchange: 'event', + pattern: 'activity.leave' + }, { + broker: this.broker, + exchange: 'execution', + exchangeKey: 'execute.completed', + publishProperties: { + monitor: true + } + }, { + cloneMessage(sourceMessage) { + return (0, _messageHelper.cloneMessage)(sourceMessage, { + isRootScope: false, + preventComplete: true + }); + } + }); +}; +PeerMonitor.prototype._onCompleteMessage = function onCompleteMessage(_routingKey, message) { + this.running.delete(message.content.id); + return !this.running.size; +}; +PeerMonitor.prototype.stop = function stop() { + for (const peerActivity of this.watching.values()) { + peerActivity.broker.closeShovel(`_on-leave-${this.id}`); + peerActivity.broker.closeShovel(`_on-enter-${this.id}`); + } }; \ No newline at end of file diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 001023b4..1d4bf1cc 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -44,7 +44,7 @@ function ProcessExecution(parentActivity, context) { startActivities: new Set(), triggeredByEvent: new Set(), detachedActivities: new Set(), - parallelJoins: new Set(), + convergingGateways: new Set(), startSequences: new Map() }; const exchangeName = this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution'; @@ -125,16 +125,14 @@ ProcessExecution.prototype.resume = function resume() { this._activate(); const { startActivities, - detachedActivities, postponed, - parallelJoins + detachedActivities, + convergingGateways } = this[kElements]; - if (startActivities.size > 1 || parallelJoins.size) { + if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); - if (this.environment.settings.skipDiscard !== result.settings.skipDiscard) { - this.environment.settings.skipDiscard = result.settings.skipDiscard; - this._debug(!result.settings.skipDiscard ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` : 'forced shake'); - } + const skipDiscard = this.environment.settings.skipDiscard = result.settings.skipDiscard; + this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); } postponed.clear(); detachedActivities.clear(); @@ -234,54 +232,6 @@ ProcessExecution.prototype.recover = function recover(state) { }; ProcessExecution.prototype.shake = function shake(fromId) { return Object.fromEntries(this._shakeElements(fromId).sequences); - // let executing = true; - // const id = this.id; - // if (!this.isRunning) { - // executing = false; - // this.executionId = getUniqueId(id); - // this._activate(); - // } - // const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; - - // const result = { - // settings: { - // skipDiscard: this.environment.settings.skipDiscard, - // }, - // }; - // const joins = new Set(); - // const consumerTag = `_shaker-${this.executionId}`; - - // this.broker.subscribeTmp( - // 'event', - // '*.shake.*', - // (routingKey, { content }) => { - // switch (routingKey) { - // case 'activity.shake.join': - // joins.add(content.join); - // result.settings.skipDiscard = false; - // case 'flow.shake.loop': - // case 'activity.shake.end': { - // const { id: shakeId, parent: shakeParent } = content; - // if (shakeParent.id !== id) return; - - // result[shakeId] = result[shakeId] || []; - // result[shakeId].push({ ...content, isLooped: routingKey === 'flow.shake.loop' }); - // break; - // } - // } - // }, - // { noAck: true, consumerTag } - // ); - - // for (const a of toShake) a.shake(); - // for (const joinId of joins) this.getActivityById(joinId).shake(); - - // console.log('---------------------------', result); - - // if (!executing) this._deactivate(); - // this.broker.cancel(consumerTag); - - // return result; }; ProcessExecution.prototype.stop = function stop() { this.getApi().stop(); @@ -364,16 +314,21 @@ ProcessExecution.prototype._start = function start() { startActivities, postponed, detachedActivities, - parallelJoins + convergingGateways } = this[kElements]; - if (startActivities.size > 1 || parallelJoins.size) { + if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); - this.environment.settings.skipDiscard = result.settings.skipDiscard; - this._debug(!result.settings.skipDiscard ? `forced shake, setting skipDiscard = false due to parallel gateways (${parallelJoins.size})` : 'forced shake'); + const skipDiscard = this.environment.settings.skipDiscard = result.settings.skipDiscard; + this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); } for (const a of startActivities) a.init(); this[kStatus] = 'executing'; for (const a of startActivities) a.run(); + if (!startActivities.size) { + for (const a of this[kElements].triggeredByEvent) { + if (a.isCatching && !a.isRunning) a.run(); + } + } postponed.clear(); detachedActivities.clear(); this[kActivityQ].assertConsumer(this[kMessageHandlers].onChildMessage, { @@ -405,8 +360,9 @@ ProcessExecution.prototype._activate = function activate() { flows, associations, startActivities, + startSequences, triggeredByEvent, - parallelJoins, + convergingGateways, children } = this[kElements]; for (const flow of outboundMessageFlows) { @@ -441,9 +397,16 @@ ProcessExecution.prototype._activate = function activate() { consumerTag: '_process-activity-consumer', priority: 200 }); - if (activity.isStart) startActivities.add(activity); + if (activity.isStart) { + startActivities.add(activity); + } if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); - if (activity.isParallelJoin) parallelJoins.add(activity); + if (activity.isParallelJoin) convergingGateways.add(activity); + } + if (startActivities.size > 1) { + for (const activity of startActivities) { + startSequences.set(activity.id, new Set()); + } } this[kActivated] = true; }; @@ -490,11 +453,12 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { }, sequences: new Map() }; - const manualShakes = new Set(); + const convergingGateways = new Map(); const consumerTag = `_shaker-${this.executionId}`; this.broker.subscribeTmp('event', '*.shake.*', (routingKey, { content }) => { + if (content.parent.id !== this.id) return; switch (routingKey) { case 'activity.shake.link': { @@ -507,8 +471,15 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { break; } case 'activity.shake.join': - manualShakes.add(content.join); - result.settings.skipDiscard = false; + { + const join = convergingGateways.get(content.join); + if (!join) { + convergingGateways.set(content.join, content); + } else { + join.sequence = join.sequence.concat(content.sequence); + } + break; + } case 'flow.shake.loop': case 'activity.shake.linked': case 'activity.shake.end': @@ -535,7 +506,15 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { consumerTag }); for (const a of toShake) a.shake(); - for (const aid of manualShakes) this.getActivityById(aid).shake(); + for (const [aid, c] of convergingGateways.entries()) { + this._debug(`manual shake of converging gateway <${aid}>`); + this.getActivityById(aid).broker.publish('api', 'activity.shake.continue', c, { + type: 'shake' + }); + } + if (result.settings.skipDiscard && convergingGateways.size) { + result.settings.skipDiscard = false; + } if (!executing) this._deactivate(); this.broker.cancel(consumerTag); return result; @@ -740,8 +719,14 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message const { id, type, - isEnd + isEnd, + isParallelGateway } = message.content; + if (isParallelGateway) { + for (const inb of message.content.inbound) { + this._popPostponed(inb)?.ack(); + } + } const { postponed, detachedActivities, @@ -754,7 +739,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message return this._complete('completed'); } message.ack(); - this._debug(`left <${id}> (${type}), pending activities ${postponedCount}`); + this._debug(`left <${id}> (${type}), pending activities ${postponedCount} ${[...postponed].map(m => m.content.id)}`); if (postponedCount && postponedCount === detachedActivities.size) { return this[kActivityQ].queueMessage({ routingKey: 'execution.discard.detached' @@ -955,27 +940,12 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { } }; ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { - const { - id, - targetId, - isLinked - } = message.content; - let seq = this[kElements].startSequences.get(id); - if (!seq) { - seq = new Set([id]); - this[kElements].startSequences.set(id, seq); - } - if (targetId) { - seq.add(targetId); - } - if (isLinked) { - let linkedSeq = this[kElements].startSequences.get(targetId); - if (!linkedSeq) { - linkedSeq = new Set(seq); - this[kElements].startSequences.set(targetId, linkedSeq); - } else { - linkedSeq.add(targetId); - } + if (message.fields.routingKey !== 'activity.shake.end') return; + let seq; + if (!(seq = this[kElements].startSequences.get(message.content.id))) return; + for (const s of message.content.sequence) { + if (s.isSequenceFlow) continue; + seq.add(s.id); } }; ProcessExecution.prototype._debug = function debugMessage(logMessage) { diff --git a/src/activity/Activity.js b/src/activity/Activity.js index a8cf13f7..facefdc8 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -764,10 +764,6 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, return this._ackRunExecuteMessage(); }); } - case 'execution.inbound.cancel': { - message.ack(); - return this.broker.cancel('_run-on-inbound'); - } case 'execution.error': { this.status = 'error'; broker.publish('run', 'run.error', content, { correlationId }); diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 390ff79f..f2b67836 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -23,14 +23,14 @@ export default function LinkEventDefinition(activity, eventDefinition) { if (isThrowing) { broker.subscribeTmp( - 'event', + 'api', 'activity.shake.start', (_, msg) => { broker.publish( 'event', `activity.shake.${this.reference.referenceType}`, cloneContent(msg.content, { sourceId: this.id, targetId: undefined, message: { ...this.reference } }), - { type: 'shake', delegate: true } + { type: 'shake' } ); }, { noAck: true, consumerTag: '_link-parent-shake', priority: 1000 } @@ -81,11 +81,7 @@ LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessag broker.publish('event', 'activity.catch', catchContent, { type: 'catch' }); - return broker.publish( - 'execution', - 'execute.completed', - cloneContent(executeContent, { output: linkMessage, state: 'catch' }) - ); + return broker.publish('execution', 'execute.completed', cloneContent(executeContent, { output: linkMessage, state: 'catch' })); }; LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { @@ -124,5 +120,10 @@ LinkEventDefinition.prototype._onShakeMessage = function onShakeMessage(_, messa content.sequence = content.sequence || []; content.sequence.push({ id: this.id, type: this.type }); - return this.broker.publish('event', 'activity.shake.linked', content, { persistent: false, type: 'shake' }); + this.broker.publish('event', 'activity.shake.linked', content, { persistent: false, type: 'shake' }); + + const outbound = this.activity.outbound; + if (outbound?.length) { + for (const flow of outbound) flow.shake({ content: cloneContent(content) }); + } }; diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index ba3a06ab..b52d793f 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -350,6 +350,12 @@ ProcessExecution.prototype._start = function start() { this[kStatus] = 'executing'; for (const a of startActivities) a.run(); + if (!startActivities.size) { + for (const a of this[kElements].triggeredByEvent) { + if (a.isCatching && !a.isRunning) a.run(); + } + } + postponed.clear(); detachedActivities.clear(); this[kActivityQ].assertConsumer(this[kMessageHandlers].onChildMessage, { diff --git a/test/activities-test.js b/test/activities-test.js index 0db53f50..b8c4cc72 100644 --- a/test/activities-test.js +++ b/test/activities-test.js @@ -443,65 +443,68 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered new instance on enter continuous execution', async () => { - const context = await testHelpers.context(singleFlowDefinition); - let activity = context.getActivityById('activity'); + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)( + 'resume recovered new instance on enter continuous execution', + async () => { + const context = await testHelpers.context(singleFlowDefinition); + let activity = context.getActivityById('activity'); - const messages = []; - activity.broker.subscribeTmp( - 'event', - 'activity.*', - (routingKey, message) => { - const api = assertApi(activity, message); - if (routingKey === 'activity.wait') return api.signal(); - messages.push(message); - }, - { noAck: true } - ); + const messages = []; + activity.broker.subscribeTmp( + 'event', + 'activity.*', + (routingKey, message) => { + const api = assertApi(activity, message); + if (routingKey === 'activity.wait') return api.signal(); + messages.push(message); + }, + { noAck: true } + ); - activity.broker.subscribeOnce('event', 'activity.enter', () => { - activity.stop(); - }); + activity.broker.subscribeOnce('event', 'activity.enter', () => { + activity.stop(); + }); - const stopped = activity.waitFor('stop'); - activity.run(); + const stopped = activity.waitFor('stop'); + activity.run(); - await stopped; + await stopped; - const state = activity.getState(); - expect(activity).to.have.property('stopped', true); - expect(activity).to.have.property('isRunning', false); - expect(state).to.have.property('stopped', true); + const state = activity.getState(); + expect(activity).to.have.property('stopped', true); + expect(activity).to.have.property('isRunning', false); + expect(state).to.have.property('stopped', true); - const assertMessage = AssertMessage(context, messages, true); - assertMessage('activity.enter'); - assertMessage('activity.stop'); - expect(messages, 'no more messages').to.have.length(0); + const assertMessage = AssertMessage(context, messages, true); + assertMessage('activity.enter'); + assertMessage('activity.stop'); + expect(messages, 'no more messages').to.have.length(0); - activity = context.clone().getActivityById('activity'); + activity = context.clone().getActivityById('activity'); - activity.broker.subscribeTmp( - 'event', - 'activity.*', - (routingKey, message) => { - const api = assertApi(activity, message); - if (routingKey === 'activity.wait') return api.signal(); - messages.push(message); - }, - { noAck: true } - ); + activity.broker.subscribeTmp( + 'event', + 'activity.*', + (routingKey, message) => { + const api = assertApi(activity, message); + if (routingKey === 'activity.wait') return api.signal(); + messages.push(message); + }, + { noAck: true } + ); - activity.recover(state); + activity.recover(state); - const leave = activity.waitFor('leave'); - activity.resume(); - await leave; + const leave = activity.waitFor('leave'); + activity.resume(); + await leave; - assertMessage('activity.start'); - assertMessage('activity.end'); - assertMessage('activity.leave'); - expect(messages, 'no more messages').to.have.length(0); - }); + assertMessage('activity.start'); + assertMessage('activity.end'); + assertMessage('activity.leave'); + expect(messages, 'no more messages').to.have.length(0); + } + ); (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume stopped on start continuous execution', async () => { const context = await testHelpers.context(singleFlowDefinition); @@ -592,62 +595,65 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume recovered new instance on start continuous execution', async () => { - const context = await testHelpers.context(singleFlowDefinition); - let activity = context.getActivityById('activity'); + (activityType === 'bpmn:ParallelGateway' ? it.skip : it)( + 'resume recovered new instance on start continuous execution', + async () => { + const context = await testHelpers.context(singleFlowDefinition); + let activity = context.getActivityById('activity'); - const messages = []; - activity.broker.subscribeTmp( - 'event', - 'activity.*', - (routingKey, message) => { - const api = assertApi(activity, message); - if (routingKey === 'activity.wait') return api.signal(); - messages.push(message); - }, - { noAck: true } - ); + const messages = []; + activity.broker.subscribeTmp( + 'event', + 'activity.*', + (routingKey, message) => { + const api = assertApi(activity, message); + if (routingKey === 'activity.wait') return api.signal(); + messages.push(message); + }, + { noAck: true } + ); - activity.broker.subscribeTmp('event', 'activity.start', function stop() { - activity.broker.unsubscribe('activity.start', stop); - activity.stop(); - }); + activity.broker.subscribeTmp('event', 'activity.start', function stop() { + activity.broker.unsubscribe('activity.start', stop); + activity.stop(); + }); - const stopped = activity.waitFor('stop'); - activity.activate(); - activity.run(); - await stopped; + const stopped = activity.waitFor('stop'); + activity.activate(); + activity.run(); + await stopped; - const state = activity.getState(); + const state = activity.getState(); - const assertMessage = AssertMessage(context, messages, true); - assertMessage('activity.enter'); - assertMessage('activity.start'); - assertMessage('activity.stop'); - expect(messages, 'no more messages').to.have.length(0); + const assertMessage = AssertMessage(context, messages, true); + assertMessage('activity.enter'); + assertMessage('activity.start'); + assertMessage('activity.stop'); + expect(messages, 'no more messages').to.have.length(0); - activity = context.clone().getActivityById('activity'); - activity.broker.subscribeTmp( - 'event', - 'activity.*', - (routingKey, message) => { - const api = assertApi(activity, message); - if (routingKey === 'activity.wait') return api.signal(); - messages.push(message); - }, - { noAck: true } - ); + activity = context.clone().getActivityById('activity'); + activity.broker.subscribeTmp( + 'event', + 'activity.*', + (routingKey, message) => { + const api = assertApi(activity, message); + if (routingKey === 'activity.wait') return api.signal(); + messages.push(message); + }, + { noAck: true } + ); - const left = activity.waitFor('leave'); - activity.recover(state); - activity.resume(); + const left = activity.waitFor('leave'); + activity.recover(state); + activity.resume(); - await left; + await left; - assertMessage('activity.end'); - assertMessage('activity.leave'); - expect(messages, 'no more messages').to.have.length(0); - }); + assertMessage('activity.end'); + assertMessage('activity.leave'); + expect(messages, 'no more messages').to.have.length(0); + } + ); (activityType === 'bpmn:ParallelGateway' ? it.skip : it)('resume stopped on end leaves activity', async () => { const context = await testHelpers.context(singleFlowDefinition); diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index 61ae8154..804a2112 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -581,7 +581,6 @@ describe('Activity', () => { expect(runQ, 'run queue messages').to.have.property('messageCount', 0); expect(runQ, 'run queue consumer active').to.have.property('consumerCount', 0); }); - }); describe('run()', () => { @@ -721,7 +720,6 @@ describe('Activity', () => { activity.discard(); - return leave; }); @@ -759,7 +757,6 @@ describe('Activity', () => { const leave = activity.waitFor('leave'); activity.run(); - return leave; }); @@ -795,7 +792,6 @@ describe('Activity', () => { const leave = activity.waitFor('leave'); activity.discard(); - return leave; }); @@ -831,7 +827,6 @@ describe('Activity', () => { await leave; - const runQ = activity.broker.getQueue('run-q'); expect(runQ).to.have.property('messageCount', 0); @@ -870,7 +865,6 @@ describe('Activity', () => { activity.discard(); await leave; - }); it('next run can be discarded by discard', async () => { @@ -1517,7 +1511,6 @@ describe('Activity', () => { return leave; }); - }); describe('extensions', () => { diff --git a/test/eventDefinitions/LinkEventDefinition-test.js b/test/eventDefinitions/LinkEventDefinition-test.js index 0414f92f..a3e7e9bf 100644 --- a/test/eventDefinitions/LinkEventDefinition-test.js +++ b/test/eventDefinitions/LinkEventDefinition-test.js @@ -13,6 +13,38 @@ describe('LinkEventDefinition', () => { }; }); + describe('executionId', () => { + it('is undefined before execute', () => { + const ed = new LinkEventDefinition(event, { + type: 'bpmn:LinkEventDefinition', + behaviour: { name: 'LINKA' }, + }); + expect(ed.executionId).to.be.undefined; + }); + + it('returns the execution id from the execute message after execute', () => { + const ed = new LinkEventDefinition(event, { + type: 'bpmn:LinkEventDefinition', + behaviour: { name: 'LINKA' }, + }); + + ed.execute({ + fields: {}, + content: { + executionId: 'event_1_0', + message: { linkName: 'LINKA' }, + parent: { + id: 'event', + executionId: 'event_1', + path: [{ id: 'theProcess', executionId: 'theProcess_0' }], + }, + }, + }); + + expect(ed.executionId).to.equal('event_1_0'); + }); + }); + describe('catching', () => { it('completes immediately on execute, publishing activity.catch and execute.completed with the link payload', () => { const catchEd = new LinkEventDefinition(event, { @@ -196,14 +228,18 @@ describe('LinkEventDefinition', () => { const messages = []; event.broker.subscribeTmp('event', 'activity.shake.link', (_, msg) => messages.push(msg), { noAck: true }); - event.broker.publish('event', 'activity.shake.start', { - executionId: 'event_1', - sequence: [], - parent: { id: 'theProcess', executionId: 'theProcess_0' }, - }); + event.broker.publish( + 'api', + 'activity.shake.start', + { + executionId: 'event_1', + sequence: [], + parent: { id: 'theProcess', executionId: 'theProcess_0' }, + }, + { type: 'shake' } + ); expect(messages).to.have.length(1); - expect(messages[0].properties).to.have.property('delegate', true); expect(messages[0].properties).to.have.property('type', 'shake'); expect(messages[0].content.message).to.deep.include({ linkName: 'LINKA', referenceType: 'link' }); expect(messages[0].content).to.have.property('sourceId', 'event'); diff --git a/test/events/BoundaryEvent-test.js b/test/events/BoundaryEvent-test.js index acd40786..93147834 100644 --- a/test/events/BoundaryEvent-test.js +++ b/test/events/BoundaryEvent-test.js @@ -871,7 +871,6 @@ describe('BoundaryEvent', () => { expect(event.counters).to.have.property('discarded', 1); }); - }); describe('non-interrupting with error event definition', () => { diff --git a/test/feature/link-as-goto-feature.js b/test/feature/link-as-goto-feature.js index 42beabe7..15de65f8 100644 --- a/test/feature/link-as-goto-feature.js +++ b/test/feature/link-as-goto-feature.js @@ -1,4 +1,5 @@ import { Definition } from 'bpmn-elements'; +import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; const linkSource = ` @@ -168,7 +169,7 @@ Feature('Link as goto', () => { definition.resume(); }); - And('the user task is signaled', async () => { + And('the user task is signaled', () => { const userTask = definition.getPostponed().find((api) => api.id === 'userTask'); expect(userTask, 'userTask api').to.exist; userTask.signal(); @@ -187,6 +188,56 @@ Feature('Link as goto', () => { }); }); + Scenario('link routes into a parallel join (link as alternate path to join)', () => { + /** @type {Definition} */ + let definition; + let join; + + Given('a process where one of the join inbound paths is reached only via a link', async () => { + const source = factory.resource('link-to-parallel-join.bpmn'); + const context = await testHelpers.context(source); + definition = new Definition(context, { variables: { condition: true } }); + join = definition.getActivityById('join'); + }); + + When('definition is ran with condition routing to the link', async () => { + const leave = definition.waitFor('leave'); + definition.run(); + await leave; + }); + + Then('process completes via the link → catch → join path', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + + And('the catch was invoked once', () => { + expect(definition.getActivityById('catch-link').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('the parallel join took once (link branch arrived as take, sibling branches discarded back to it)', () => { + expect(join.counters).to.have.property('taken', 1); + }); + + When('definition is ran again with condition flipped so link is bypassed', async () => { + definition.environment.variables.condition = false; + const leave = definition.waitFor('leave'); + definition.run(); + await leave; + }); + + Then('process completes via the non-link parallel paths', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); + + And('catch counter unchanged from the previous run', () => { + expect(definition.getActivityById('catch-link').counters).to.have.property('taken', 1); + }); + + And('the parallel join took twice in total', () => { + expect(join.counters).to.have.property('taken', 2); + }); + }); + Scenario('throw with no matching catch silently completes', () => { /** @type {Definition} */ let definition; diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index f5f8789e..a5c2a833 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -626,6 +626,78 @@ Feature('Shaking', () => { }); }); + Scenario('a process with paired link throw and catch', () => { + let definition; + Given('a process where a link throw is followed by a link catch leading to the end', async () => { + const source = ` + + + + + + + + + + + + + + `; + + const context = await testHelpers.context(source); + definition = new Definition(context); + }); + + const linkedMessages = []; + const shakeEndMessages = []; + let result; + When('definition is shaken from start', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.shake.linked', + (_, msg) => { + linkedMessages.push(msg); + }, + { noAck: true } + ); + + definition.broker.subscribeTmp( + 'event', + 'activity.shake.end', + (_, msg) => { + shakeEndMessages.push(msg); + }, + { noAck: true } + ); + + result = definition.shake('start'); + }); + + Then('the catch publishes a linked-shake response with the chain back to the throw', () => { + expect(linkedMessages).to.have.length(1); + const ids = linkedMessages[0].content.sequence.map((s) => s.id); + expect(ids).to.include.members(['throw', 'catch']); + expect(linkedMessages[0].content).to.have.property('isLinked', true); + expect(linkedMessages[0].content).to.have.property('targetId', 'catch'); + }); + + And('the shake walk continues past the catch and reaches the end event', () => { + const reachedEnd = shakeEndMessages.some((m) => m.content.sequence.some((s) => s.id === 'end')); + expect(reachedEnd, 'shake.end with end in sequence').to.be.true; + const endSequence = shakeEndMessages + .map((m) => m.content.sequence.map((s) => s.id)) + .find((ids) => ids.includes('end')); + expect(endSequence).to.include.members(['catch', 'from-catch', 'end']); + }); + + And('the shake result for start contains a sequence reaching the end via the link', () => { + expect(result).to.have.property('start').that.is.an('array'); + const sequenceIds = result.start.map((s) => s.sequence.map((e) => e.id)); + expect(sequenceIds.some((ids) => ids.includes('throw') && ids.includes('catch') && ids.includes('end'))).to.be.true; + }); + }); + // [ // 'join-paradox-1.bpmn', // 'join-paradox-2.bpmn', diff --git a/test/gateways/EventBasedGateway-test.js b/test/gateways/EventBasedGateway-test.js index 838615fc..c72899a6 100644 --- a/test/gateways/EventBasedGateway-test.js +++ b/test/gateways/EventBasedGateway-test.js @@ -66,7 +66,7 @@ describe('EventBasedGateway', () => { `; - const context = await testHelpers.context(source); + const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); const [bp] = context.getProcesses(); const gateway = bp.getActivityById('decision'); const usertask = bp.getActivityById('usertask'); diff --git a/test/resources/link-to-parallel-join.bpmn b/test/resources/link-to-parallel-join.bpmn index 7c77555f..46bc6eae 100644 --- a/test/resources/link-to-parallel-join.bpmn +++ b/test/resources/link-to-parallel-join.bpmn @@ -1,5 +1,5 @@ - + Flow_05b3201 @@ -21,23 +21,23 @@ Flow_1docann - + Flow_06pnthd - Flow_1loxf70 + from-task3 - - + + Flow_1docann Flow_1bhj6pc - - + + Flow_1bhj6pc - Flow_0e0fdrh + from-task5 - - - + + + to-complete-task to-end @@ -60,8 +60,8 @@ - Flow_0e0fdrh - Flow_1loxf70 + from-task5 + from-task3 from-catch-link to-complete-task @@ -82,6 +82,16 @@ + + + + + + + + + + @@ -92,21 +102,12 @@ - - - - - - - - - - - - + + + @@ -133,12 +134,12 @@ - + - + From 1082805d3a10a5b04220d60d305495222a326a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 10 May 2026 09:25:12 +0200 Subject: [PATCH 10/31] prepare for dts-buddy bundling of types --- .github/workflows/build.yaml | 2 +- .nvmrc | 2 +- CHANGELOG.md | 8 + dist/activity/Activity.js | 113 +++++ dist/eventDefinitions/LinkEventDefinition.js | 3 +- package.json | 4 +- src/Api.js | 70 +++ src/Context.js | 99 ++++ src/Environment.js | 52 +++ src/EventBroker.js | 55 +++ src/MessageFormatter.js | 14 +- src/activity/Activity.js | 97 +++- src/activity/ActivityExecution.js | 52 +++ src/definition/Definition.js | 92 ++++ src/definition/DefinitionExecution.js | 80 ++++ src/process/Process.js | 83 ++++ src/process/ProcessExecution.js | 81 ++++ test/activity/Activity-test.js | 15 + types/interfaces.d.ts | 355 ++++++++++++++ types/types.d.ts | 461 ++++--------------- 20 files changed, 1346 insertions(+), 392 deletions(-) create mode 100644 types/interfaces.d.ts diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9e089bd6..6a4651f6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18, 20, 22, 24, latest] + node-version: [20, 22, 24, latest] steps: - name: Checkout uses: actions/checkout@v6 diff --git a/.nvmrc b/.nvmrc index 3c032078..209e3ef4 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 +20 diff --git a/CHANGELOG.md b/CHANGELOG.md index 71e695b3..7b333459 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## Unreleased +- fix `Activity.recover()` to return the activity when called without state + +### Types + +- start migrating runtime types to JSDoc, covering `Activity`, `ActivityExecution`, `Context`, `Process`, `ProcessExecution`, `Definition`, `DefinitionExecution`, `Environment`, `Api`, `EventBroker`, and `MessageFormatter` +- separate hand-written contracts into `types/interfaces.d.ts` +- update `smqp` type imports for `smqp@12` + ## v18.0.0 - 2026-01-14 Refactor parallel converging and forking gateways. diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 60a84615..d93e95b1 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -28,6 +28,12 @@ const kMessageHandlers = Symbol.for('messageHandlers'); const kStateMessage = Symbol.for('stateMessage'); const kActivated = Symbol.for('activated'); var _default = exports.default = Activity; +/** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param {import('types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution + * @param {import('moddle-context-serializer').SerializableElement} activityDef Parsed BPMN element definition + * @param {import('types').ContextInstance} context Per-execution registry and factory + */ function Activity(Behaviour, activityDef, context) { const { id, @@ -124,6 +130,7 @@ function Activity(Behaviour, activityDef, context) { } Object.defineProperties(Activity.prototype, { counters: { + /** @returns {{ taken: number, discarded: number }} */ get() { return { ...this[kCounters] @@ -131,27 +138,32 @@ Object.defineProperties(Activity.prototype, { } }, execution: { + /** @returns {import('types').ActivityExecution | undefined} */ get() { return this[kExec].get('execution'); } }, executionId: { + /** @returns {string | undefined} */ get() { return this[kExec].get('executionId'); } }, extensions: { + /** @returns {import('types').IExtension} */ get() { return this[kExtensions]; } }, bpmnIo: { + /** @returns {import('types').IExtension | undefined} */ get() { const extensions = this[kExtensions]; return extensions?.extensions.find(e => e.type === 'bpmnio'); } }, formatter: { + /** @returns {import('types').MessageFormatter} */ get() { let formatter = this[kFormatter]; if (formatter) return formatter; @@ -160,72 +172,86 @@ Object.defineProperties(Activity.prototype, { } }, isRunning: { + /** @returns {boolean} */ get() { if (!this[kConsuming]) return false; return !!this.status; } }, outbound: { + /** @returns {import('types').SequenceFlow[]} */ get() { return this[kFlows].outboundSequenceFlows; } }, inbound: { + /** @returns {import('types').SequenceFlow[]} */ get() { return this[kFlows].inboundSequenceFlows; } }, isEnd: { + /** @returns {boolean} */ get() { return this[kFlags].isEnd; } }, isStart: { + /** @returns {boolean} */ get() { return this[kFlags].isStart; } }, isSubProcess: { + /** @returns {boolean} */ get() { return this[kFlags].isSubProcess; } }, isTransaction: { + /** @returns {boolean} */ get() { return this[kFlags].isTransaction; } }, isMultiInstance: { + /** @returns {boolean} */ get() { return this[kFlags].isMultiInstance; } }, isThrowing: { + /** @returns {boolean} */ get() { return this[kFlags].isThrowing; } }, isCatching: { + /** @returns {boolean} */ get() { return this[kFlags].isCatching; } }, isForCompensation: { + /** @returns {boolean} */ get() { return this[kFlags].isForCompensation; } }, isParallelJoin: { + /** @returns {boolean} */ get() { return this[kFlags].isParallelJoin; } }, triggeredByEvent: { + /** @returns {boolean} */ get() { return this[kActivityDef].triggeredByEvent; } }, attachedTo: { + /** @returns {import('types').Activity | null} */ get() { const attachedToId = this[kFlags].attachedTo; if (!attachedToId) return null; @@ -233,6 +259,7 @@ Object.defineProperties(Activity.prototype, { } }, lane: { + /** @returns {import('types').Lane | undefined} */ get() { const laneId = this[kFlags].lane; if (!laneId) return undefined; @@ -241,26 +268,37 @@ Object.defineProperties(Activity.prototype, { } }, eventDefinitions: { + /** @returns {import('types').EventDefinition[]} */ get() { return this[kEventDefinitions]; } }, parentElement: { + /** @returns {import('types').Process | import('types').Activity} Parent process or sub process reference */ get() { return this.context.getActivityParentById(this.id); } }, initialized: { + /** @returns {boolean} */ get() { return !!this[kExec]?.get('initExecutionId'); } } }); + +/** + * Subscribe to inbound flows and start consuming the inbound queue. + */ Activity.prototype.activate = function activate() { if (this[kActivated]) return; this[kActivated] = true; return this.addInboundListeners() && this._consumeInbound(); }; + +/** + * Cancel inbound subscriptions and any pending run/format consumers. + */ Activity.prototype.deactivate = function deactivate() { this[kActivated] = false; const broker = this.broker; @@ -268,6 +306,11 @@ Activity.prototype.deactivate = function deactivate() { broker.cancel('_run-on-inbound'); broker.cancel('_format-consumer'); }; + +/** + * Initialise activity executionId and emit init event without starting the run. + * @param {Record} [initContent] Optional content merged into the init message + */ Activity.prototype.init = function init(initContent) { const id = this.id; const exec = this[kExec]; @@ -279,6 +322,12 @@ Activity.prototype.init = function init(initContent) { executionId })); }; + +/** + * Start running the activity by publishing run.enter and run.start. + * @param {Record} [runContent] Optional content merged into the run message + * @throws {Error} if the activity is already running + */ Activity.prototype.run = function run(runContent) { const id = this.id; if (this.isRunning) throw new Error(`activity <${id}> is already running`); @@ -297,6 +346,12 @@ Activity.prototype.run = function run(runContent) { this[kConsuming] = true; this._consumeRunQ(); }; + +/** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + * @returns {import('types').ActivityState | undefined} + */ Activity.prototype.getState = function getState() { const status = this.status; const exec = this[kExec]; @@ -319,6 +374,13 @@ Activity.prototype.getState = function getState() { }) }; }; + +/** + * Restore activity state captured by getState. Cannot be called while running. + * @param {import('types').ActivityState} [state] + * @returns {Activity | undefined} this when state was applied + * @throws {Error} when activity is currently running + */ Activity.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running activity <${this.id}>`); if (!state) return; // TODO: return this @@ -337,6 +399,11 @@ Activity.prototype.recover = function recover(state) { this.broker.recover(state.broker); return this; }; + +/** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ Activity.prototype.resume = function resume() { if (this[kConsuming]) { throw new Error(`cannot resume running activity <${this.id}>`); @@ -351,6 +418,11 @@ Activity.prototype.resume = function resume() { this[kConsuming] = true; this._consumeRunQ(); }; + +/** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param {Record} [discardContent] Optional content propagated with the discard + */ Activity.prototype.discard = function discard(discardContent) { if (!this.status) return this._runDiscard(discardContent); const execution = this[kExec].get('execution'); @@ -362,6 +434,11 @@ Activity.prototype.discard = function discard(discardContent) { this[kConsuming] = true; this._consumeRunQ(); }; + +/** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns {number} count of subscribed triggers + */ Activity.prototype.addInboundListeners = function addInboundListeners() { const triggers = this[kFlows].inboundTriggers; if (triggers.length) { @@ -388,16 +465,29 @@ Activity.prototype.addInboundListeners = function addInboundListeners() { } return triggers.length; }; + +/** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ Activity.prototype.removeInboundListeners = function removeInboundListeners() { const triggerConsumerTag = `_inbound-${this.id}`; for (const trigger of this[kFlows].inboundTriggers) { trigger.broker.cancel(triggerConsumerTag); } }; + +/** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ Activity.prototype.stop = function stop() { if (!this[kConsuming]) return this.broker.cancel('_run-on-inbound'); return this.getApi(this[kStateMessage]).stop(); }; + +/** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + * @returns {import('types').ElementBrokerMessage | false | undefined} + */ Activity.prototype.next = function next() { if (!this.environment.settings.step) return; const stateMessage = this[kStateMessage]; @@ -408,19 +498,42 @@ Activity.prototype.next = function next() { stateMessage.ack(); return current; }; + +/** + * Walk outbound flows to discover the activity graph from this point. + */ Activity.prototype.shake = function shake() { this._shakeOutbound({ content: this._createMessage() }); }; + +/** + * Evaluate outbound sequence flows for the given source message. + * @param {import('types').ElementBrokerMessage} fromMessage Source run message + * @param {boolean} discardRestAtTake When true, take only the first matching flow and discard the rest + * @param {(err: Error, evaluationResult: any) => void} callback + */ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) { return this[kFlows].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); }; + +/** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * @param {import('types').ElementBrokerMessage} [message] + * @returns {import('types').Api} + */ Activity.prototype.getApi = function getApi(message) { const execution = this[kExec].get('execution'); if (execution && !execution.completed) return execution.getApi(message); return (0, _Api.ActivityApi)(this.broker, message || this[kStateMessage]); }; + +/** + * Look up another activity in the same context. + * @param {string} elementId + * @returns {import('types').Activity | undefined} + */ Activity.prototype.getActivityById = function getActivityById(elementId) { return this.context.getActivityById(elementId); }; diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index cc7854f5..f2ba54eb 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -38,8 +38,7 @@ function LinkEventDefinition(activity, eventDefinition) { ...this.reference } }), { - type: 'shake', - delegate: true + type: 'shake' }); }, { noAck: true, diff --git a/package.json b/package.json index 48a79b36..21cb04bc 100644 --- a/package.json +++ b/package.json @@ -85,13 +85,15 @@ "@babel/preset-env": "^7.24.4", "@babel/register": "^7.23.7", "@bonniernews/hot-bev": "^0.4.0", - "@types/node": "^18.19.63", + "@types/bpmn-moddle": "^10.0.0", + "@types/node": "^20.19.40", "bpmn-moddle": "^9.0.1", "c8": "^10.1.1", "camunda-bpmn-moddle": "^7.0.1", "chai": "^6.2.1", "chronokinesis": "^8.0.0", "debug": "^4.3.4", + "dts-buddy": "^0.7.0", "eslint": "^9.0.0", "globals": "^17.0.0", "mocha": "^11.0.1", diff --git a/src/Api.js b/src/Api.js index d47f9ae3..ca9abda9 100644 --- a/src/Api.js +++ b/src/Api.js @@ -1,22 +1,54 @@ import { cloneMessage } from './messageHelper.js'; import { getUniqueId } from './shared.js'; +/** + * Build an activity-scoped Api wrapper. Routing keys are published under `activity.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ export function ActivityApi(broker, apiMessage, environment) { return new Api('activity', broker, apiMessage, environment); } +/** + * Build a definition-scoped Api wrapper. Routing keys are published under `definition.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ export function DefinitionApi(broker, apiMessage, environment) { return new Api('definition', broker, apiMessage, environment); } +/** + * Build a process-scoped Api wrapper. Routing keys are published under `process.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ export function ProcessApi(broker, apiMessage, environment) { return new Api('process', broker, apiMessage, environment); } +/** + * Build a flow-scoped Api wrapper. Routing keys are published under `flow.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ export function FlowApi(broker, apiMessage, environment) { return new Api('flow', broker, apiMessage, environment); } +/** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param {string} pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param {any} broker + * @param {import('types').ElementBrokerMessage} sourceMessage Cloned to back the api + * @param {import('types').Environment} [environment] Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing + */ export function Api(pfx, broker, sourceMessage, environment) { if (!sourceMessage) throw new Error('Api requires message'); @@ -36,26 +68,50 @@ export function Api(pfx, broker, sourceMessage, environment) { this.messagePrefix = pfx; } +/** + * Send a cancel api message. + * @param {import('types').signalMessage} [message] + * @param {any} [options] + */ Api.prototype.cancel = function cancel(message, options) { this.sendApiMessage('cancel', { message }, options); }; +/** + * Send a discard api message. + */ Api.prototype.discard = function discard() { this.sendApiMessage('discard'); }; +/** + * Send an error api message that fails the activity. + * @param {Error} error + */ Api.prototype.fail = function fail(error) { this.sendApiMessage('error', { error }); }; +/** + * Send a signal api message. + * @param {import('types').signalMessage} [message] + * @param {any} [options] + */ Api.prototype.signal = function signal(message, options) { this.sendApiMessage('signal', { message }, options); }; +/** + * Send a stop api message. + */ Api.prototype.stop = function stop() { this.sendApiMessage('stop'); }; +/** + * Resolve an expression with the api message as scope and the broker owner as context. + * @param {string} expression + */ Api.prototype.resolveExpression = function resolveExpression(expression) { return this.environment.resolveExpression( expression, @@ -68,6 +124,12 @@ Api.prototype.resolveExpression = function resolveExpression(expression) { ); }; +/** + * Publish a custom api message to the broker. + * @param {string} action Routing key suffix, e.g. `signal`, `cancel` + * @param {import('types').signalMessage} [content] Merged into the message content + * @param {any} [options] + */ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) { const correlationId = options?.correlationId || getUniqueId(`${this.id || this.messagePrefix}_signal`); let key = `${this.messagePrefix}.${action}`; @@ -75,12 +137,20 @@ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) this.broker.publish('api', key, this.createMessage(content), { ...options, correlationId, type: action }); }; +/** + * List currently postponed activities, falling back to a sub-process execution when applicable. + * @param {import('types').filterPostponed} [filterFn] + */ Api.prototype.getPostponed = function getPostponed(...args) { if (this.owner.getPostponed) return this.owner.getPostponed(...args); if (this.owner.isSubProcess && this.owner.execution) return this.owner.execution.getPostponed(...args); return []; }; +/** + * Build a message body by merging the given content onto the source content. + * @param {Record} [content] + */ Api.prototype.createMessage = function createMessage(content) { return { ...this.content, diff --git a/src/Context.js b/src/Context.js index 265f2d1e..d134ee51 100644 --- a/src/Context.js +++ b/src/Context.js @@ -5,11 +5,22 @@ import { getUniqueId } from './shared.js'; const kOwner = Symbol.for('owner'); const kActivated = Symbol.for('activated'); +/** + * Build a runtime Context from a parsed BPMN definition. + * @param {import('moddle-context-serializer').SerializableContext} definitionContext + * @param {import('types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted + */ export default function Context(definitionContext, environment) { environment = environment ? environment.clone() : new Environment(); return new ContextInstance(definitionContext, environment); } +/** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param {import('moddle-context-serializer').SerializableContext} definitionContext + * @param {import('types').Environment} environment + * @param {import('types').Process | import('types').Activity} [owner] Process or sub-process activity that owns this context + */ function ContextInstance(definitionContext, environment, owner) { const { id = 'Def', name, type = 'context' } = definitionContext; const sid = getUniqueId(id); @@ -38,6 +49,10 @@ Object.defineProperty(ContextInstance.prototype, 'owner', { }, }); +/** + * Get or create the activity instance for the given id. + * @param {string} activityId + */ ContextInstance.prototype.getActivityById = function getActivityById(activityId) { const activityInstance = this.refs.get('activityRefs').get(activityId); if (activityInstance) return activityInstance; @@ -46,6 +61,10 @@ ContextInstance.prototype.getActivityById = function getActivityById(activityId) return this.upsertActivity(activity); }; +/** + * Return the cached activity instance, instantiating it the first time it is referenced. + * @param {import('moddle-context-serializer').SerializableElement} activityDef + */ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) { let activityInstance = this.refs.get('activityRefs').get(activityDef.id); if (activityInstance) return activityInstance; @@ -56,6 +75,10 @@ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) return activityInstance; }; +/** + * Get or create the sequence flow instance for the given id. + * @param {string} sequenceFlowId + */ ContextInstance.prototype.getSequenceFlowById = function getSequenceFlowById(sequenceFlowId) { const flowInstance = this.refs.get('sequenceFlowRefs').get(sequenceFlowId); if (flowInstance) return flowInstance; @@ -65,30 +88,54 @@ ContextInstance.prototype.getSequenceFlowById = function getSequenceFlowById(seq return this.upsertSequenceFlow(flowDef); }; +/** + * @param {string} activityId + */ ContextInstance.prototype.getInboundSequenceFlows = function getInboundSequenceFlows(activityId) { return (this.definitionContext.getInboundSequenceFlows(activityId) || []).map((flow) => this.upsertSequenceFlow(flow)); }; +/** + * @param {string} activityId + */ ContextInstance.prototype.getOutboundSequenceFlows = function getOutboundSequenceFlows(activityId) { return (this.definitionContext.getOutboundSequenceFlows(activityId) || []).map((flow) => this.upsertSequenceFlow(flow)); }; +/** + * @param {string} activityId + */ ContextInstance.prototype.getInboundAssociations = function getInboundAssociations(activityId) { return (this.definitionContext.getInboundAssociations(activityId) || []).map((association) => this.upsertAssociation(association)); }; +/** + * @param {string} activityId + */ ContextInstance.prototype.getOutboundAssociations = function getOutboundAssociations(activityId) { return (this.definitionContext.getOutboundAssociations(activityId) || []).map((association) => this.upsertAssociation(association)); }; +/** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getActivities = function getActivities(scopeId) { return (this.definitionContext.getActivities(scopeId) || []).map((activityDef) => this.upsertActivity(activityDef)); }; +/** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getSequenceFlows = function getSequenceFlows(scopeId) { return (this.definitionContext.getSequenceFlows(scopeId) || []).map((flow) => this.upsertSequenceFlow(flow)); }; +/** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * @param {import('moddle-context-serializer').SerializableElement} flowDefinition + */ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowDefinition) { const sequenceFlowRefs = this.refs.get('sequenceFlowRefs'); let flowInstance = sequenceFlowRefs.get(flowDefinition.id); @@ -100,10 +147,16 @@ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowD return flowInstance; }; +/** + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getAssociations = function getAssociations(scopeId) { return (this.definitionContext.getAssociations(scopeId) || []).map((association) => this.upsertAssociation(association)); }; +/** + * @param {import('moddle-context-serializer').SerializableElement} associationDefinition + */ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associationDefinition) { const associationRefs = this.refs.get('associationRefs'); let instance = associationRefs.get(associationDefinition.id); @@ -116,10 +169,19 @@ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associa return instance; }; +/** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * @param {import('types').Environment} [newEnvironment] + * @param {import('types').Process | import('types').Activity} [newOwner] + */ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner); }; +/** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * @param {string} processId + */ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const processRefs = this.refs.get('processRefs'); let bp = processRefs.get(processId); @@ -136,6 +198,10 @@ ContextInstance.prototype.getProcessById = function getProcessById(processId) { return bp; }; +/** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * @param {string} processId + */ ContextInstance.prototype.getNewProcessById = function getNewProcessById(processId) { if (!this.getProcessById(processId)) return null; const bpDef = this.definitionContext.getProcessById(processId); @@ -147,14 +213,24 @@ ContextInstance.prototype.getNewProcessById = function getNewProcessById(process return bp; }; +/** + * Get every process in the definition. + */ ContextInstance.prototype.getProcesses = function getProcesses() { return this.definitionContext.getProcesses().map(({ id: processId }) => this.getProcessById(processId)); }; +/** + * Get processes flagged executable in the definition. + */ ContextInstance.prototype.getExecutableProcesses = function getExecutableProcesses() { return this.definitionContext.getExecutableProcesses().map(({ id: processId }) => this.getProcessById(processId)); }; +/** + * Get message flows that originate from the given process id. + * @param {string} sourceId Source process id + */ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { const messageFlowRefs = this.refs.get('messageFlows'); @@ -176,6 +252,10 @@ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { return result; }; +/** + * Get or create a data object instance for the given reference id. + * @param {string} referenceId + */ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referenceId) { const dataObjectRefs = this.refs.get('dataObjectRefs'); let dataObject; @@ -190,6 +270,10 @@ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referen return dataObject; }; +/** + * Get or create a data store instance for the given reference id. + * @param {string} referenceId + */ ContextInstance.prototype.getDataStoreById = function getDataStoreById(referenceId) { const dataStoreRefs = this.refs.get('dataStoreRefs'); let dataStore; @@ -205,6 +289,11 @@ ContextInstance.prototype.getDataStoreById = function getDataStoreById(reference return dataStore; }; +/** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param {import('types').startActivityFilterOptions} [filterOptions] + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getStartActivities = function getStartActivities(filterOptions, scopeId) { const referenceId = filterOptions?.referenceId; const referenceType = filterOptions?.referenceType || 'unknown'; @@ -227,6 +316,11 @@ ContextInstance.prototype.getStartActivities = function getStartActivities(filte return result; }; +/** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * @param {import('types').ElementBase} activity + */ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { const io = new BpmnIO(activity, this); const extensions = this.extensionsMapper.get(activity); @@ -235,6 +329,10 @@ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { return extensions; }; +/** + * Resolve the parent process or sub-process activity that owns the given activity. + * @param {string} activityId + */ ContextInstance.prototype.getActivityParentById = function getActivityParentById(activityId) { const owner = this[kOwner]; if (owner) return owner; @@ -251,6 +349,7 @@ ExtensionsMapper.prototype.get = function get(activity) { return new Extensions(activity, this.context, this._getExtensions()); }; +/** @internal */ ExtensionsMapper.prototype._getExtensions = function getExtensions() { let extensions; if (!(extensions = this.context.environment.extensions)) return []; diff --git a/src/Environment.js b/src/Environment.js index b8656a56..6b989354 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -7,6 +7,11 @@ const kVariables = Symbol.for('variables'); const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', 'scripts', 'services', 'settings', 'timers', 'variables']); +/** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * @param {import('types').EnvironmentOptions} [options] + */ export default function Environment(options = {}) { this.options = validateOptions(options); @@ -41,6 +46,9 @@ Object.defineProperties(Environment.prototype, { }, }); +/** + * Snapshot environment state for recover. + */ Environment.prototype.getState = function getState() { return { settings: { ...this.settings }, @@ -49,6 +57,12 @@ Environment.prototype.getState = function getState() { }; }; +/** + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. + * @param {import('types').EnvironmentState} [state] + * @returns this + */ Environment.prototype.recover = function recover(state) { if (!state) return this; @@ -59,6 +73,11 @@ Environment.prototype.recover = function recover(state) { return this; }; +/** + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. + * @param {import('types').EnvironmentOptions} [overrideOptions] + */ Environment.prototype.clone = function clone(overrideOptions) { const services = this[kServices]; const newOptions = { @@ -79,6 +98,10 @@ Environment.prototype.clone = function clone(overrideOptions) { return new this.constructor(newOptions); }; +/** + * Merge variables into the environment. Non-objects are ignored. + * @param {Record} newVars + */ Environment.prototype.assignVariables = function assignVariables(newVars) { if (!newVars || typeof newVars !== 'object') return; @@ -88,6 +111,11 @@ Environment.prototype.assignVariables = function assignVariables(newVars) { }; }; +/** + * Merge settings into the environment. Non-objects are ignored. + * @param {import('types').EnvironmentSettings} newSettings + * @returns this + */ Environment.prototype.assignSettings = function assignSettings(newSettings) { if (!newSettings || typeof newSettings !== 'object') return this; @@ -99,18 +127,37 @@ Environment.prototype.assignSettings = function assignSettings(newSettings) { return this; }; +/** + * Resolve a registered script by language and identifier. + * @param {string} language + * @param {{ id: string, [x: string]: any }} identifier + */ Environment.prototype.getScript = function getScript(...args) { return this.scripts.getScript(...args); }; +/** + * Register a script for an activity, delegating to the configured scripts engine. + * @param {any} activity + */ Environment.prototype.registerScript = function registerScript(...args) { return this.scripts.register(...args); }; +/** + * Lookup a registered service by name. + * @param {string} serviceName + */ Environment.prototype.getServiceByName = function getServiceByName(serviceName) { return this[kServices][serviceName]; }; +/** + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param {string} expression + * @param {import('types').ElementBrokerMessage} [message] Element message merged onto the resolution scope + * @param {any} [expressionFnContext] + */ Environment.prototype.resolveExpression = function resolveExpression(expression, message, expressionFnContext) { const from = { environment: this, @@ -120,6 +167,11 @@ Environment.prototype.resolveExpression = function resolveExpression(expression, return this.expressions.resolveExpression(expression, from, expressionFnContext); }; +/** + * Register a service callable by name. + * @param {string} name + * @param {CallableFunction} fn + */ Environment.prototype.addService = function addService(name, fn) { this[kServices][name] = fn; }; diff --git a/src/EventBroker.js b/src/EventBroker.js index 111a9417..f1e88728 100644 --- a/src/EventBroker.js +++ b/src/EventBroker.js @@ -1,11 +1,19 @@ import { Broker } from 'smqp'; import { makeErrorFromMessage } from './error/Errors.js'; +/** + * Build the broker for an activity, including run/format/execution/api exchanges and queues. + * @param {import('types').Activity} activity + */ export function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); return executionBroker; } +/** + * Build the broker for a process, with an additional api-q bound to all api routing keys. + * @param {import('types').Process} owner + */ export function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); executionBroker.broker.assertQueue('api-q', { durable: false, autoDelete: false }); @@ -13,10 +21,19 @@ export function ProcessBroker(owner) { return executionBroker; } +/** + * Build the broker for a definition. Optionally registers a custom return-message handler. + * @param {import('types').Definition} owner + * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] + */ export function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); } +/** + * Build the broker for a message flow with a durable message exchange and message-q. + * @param {import('types').MessageFlow} owner + */ export function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { prefix: 'messageflow', autoDelete: false, durable: false }); const broker = eventBroker.broker; @@ -49,6 +66,12 @@ function ExecutionBroker(brokerOwner, prefix, onBrokerReturn) { return eventBroker; } +/** + * Owns an smqp Broker on behalf of the calling element and exposes prefixed event helpers. + * @param {any} brokerOwner Element that owns the broker, accessed as `broker.owner` + * @param {{ prefix: string, autoDelete?: boolean, durable?: boolean }} options + * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] Override for unrouted return messages + */ export function EventBroker(brokerOwner, options, onBrokerReturn) { this.options = options; this.eventPrefix = options.prefix; @@ -64,6 +87,13 @@ export function EventBroker(brokerOwner, options, onBrokerReturn) { this.emitFatal = this.emitFatal.bind(this); } +/** + * Subscribe to a prefixed event. Errors are unwrapped via `makeErrorFromMessage`, + * other events resolve to the owner's Api wrapper. + * @param {string} eventName Bare name (e.g. `enter`) or a full routing key + * @param {CallableFunction} callback + * @param {{ once?: boolean, [x: string]: any }} [eventOptions] + */ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { once: false }) { const key = this._getEventRoutingKey(eventName); @@ -76,10 +106,22 @@ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { onc } }; +/** + * Subscribe to the next occurrence of an event. + * @param {string} eventName + * @param {CallableFunction} callback + * @param {any} [eventOptions] + */ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { return this.on(eventName, callback, { ...eventOptions, once: true }); }; +/** + * Promise-style wait for an event. Rejects on a mandatory `*.error` message. + * @param {string} eventName + * @param {(routingKey: string, message: import('types').ElementBrokerMessage, owner: any) => boolean | undefined} [onMessage] + * Filter; the promise only resolves when it returns truthy + */ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { const key = this._getEventRoutingKey(eventName); @@ -109,14 +151,26 @@ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { }); }; +/** + * Publish a prefixed event message. + * @param {string} eventName + * @param {Record} [content] + * @param {any} [props] + */ EventBroker.prototype.emit = function emit(eventName, content, props) { this.broker.publish('event', `${this.eventPrefix}.${eventName}`, { ...content }, { type: eventName, ...props }); }; +/** + * Emit a mandatory error event. Surfaces via `on('error', ...)` or causes a return message to throw. + * @param {Error} error + * @param {Record} [content] + */ EventBroker.prototype.emitFatal = function emitFatal(error, content) { this.emit('error', { ...content, error }, { mandatory: true }); }; +/** @internal */ EventBroker.prototype._onBrokerReturnFn = function onBrokerReturnFn(message) { if (message.properties.type === 'error') { const err = makeErrorFromMessage(message); @@ -124,6 +178,7 @@ EventBroker.prototype._onBrokerReturnFn = function onBrokerReturnFn(message) { } }; +/** @internal */ EventBroker.prototype._getEventRoutingKey = function getEventRoutingKey(eventName) { if (eventName.indexOf('.') > -1) return eventName; diff --git a/src/MessageFormatter.js b/src/MessageFormatter.js index a5619f44..7061c313 100644 --- a/src/MessageFormatter.js +++ b/src/MessageFormatter.js @@ -9,7 +9,9 @@ const kExecution = Symbol.for('execution'); const EXEC_ROUTING_KEY = 'run._formatting.exec'; /** - * Message formatter used to enrich an element run message before continuing to the next run message + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. * @param {import('types').ElementBase} element */ export function Formatter(element) { @@ -21,9 +23,10 @@ export function Formatter(element) { } /** - * Format message + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. * @param {import('types').ElementBrokerMessage} message - * @param {CallableFunction} callback + * @param {(err: Error | null, content?: import('types').ElementMessageContent, formatted?: boolean) => void} callback */ Formatter.prototype.format = function format(message, callback) { const correlationId = (this._runId = getUniqueId(message.fields.routingKey)); @@ -48,6 +51,7 @@ Formatter.prototype.format = function format(message, callback) { }); }; +/** @internal */ Formatter.prototype._onMessage = function onMessage(routingKey, message) { const { formatKey, correlationId, pending, executeMessage } = this[kExecution]; const asyncFormatting = pending.size; @@ -87,6 +91,7 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { } }; +/** @internal */ Formatter.prototype._complete = function complete(message, isError) { const { runMessage, formatKey, callback, formatted, executeMessage } = this[kExecution]; this[kExecution] = null; @@ -104,6 +109,7 @@ Formatter.prototype._complete = function complete(message, isError) { return callback(null, runMessage.content, formatted); }; +/** @internal */ Formatter.prototype._enrich = function enrich(withContent) { const content = this[kExecution].runMessage.content; for (const key in withContent) { @@ -128,6 +134,7 @@ Formatter.prototype._enrich = function enrich(withContent) { } }; +/** @internal */ Formatter.prototype._popFormatStart = function popFormattingStart(pending, routingKey) { for (const msg of pending) { const { endRoutingKey, errorRoutingKey = '#.error' } = msg.content; @@ -144,6 +151,7 @@ Formatter.prototype._popFormatStart = function popFormattingStart(pending, routi return {}; }; +/** @internal */ Formatter.prototype._debug = function debug(msg) { this.logger.debug(`<${this.id}> ${msg}`); }; diff --git a/src/activity/Activity.js b/src/activity/Activity.js index facefdc8..c51af2e6 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -24,6 +24,12 @@ const kActivated = Symbol.for('activated'); export default Activity; +/** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param {import('types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution + * @param {import('moddle-context-serializer').SerializableElement} activityDef Parsed BPMN element definition + * @param {import('types').ContextInstance} context Per-execution registry and factory + */ function Activity(Behaviour, activityDef, context) { const { id, type = 'activity', name, behaviour = {} } = activityDef; const { attachedTo: attachedToRef, eventDefinitions } = behaviour; @@ -233,6 +239,7 @@ Object.defineProperties(Activity.prototype, { }, }, parentElement: { + /** Parent process or sub process reference */ get() { return this.context.getActivityParentById(this.id); }, @@ -244,12 +251,18 @@ Object.defineProperties(Activity.prototype, { }, }); +/** + * Subscribe to inbound flows and start consuming the inbound queue. + */ Activity.prototype.activate = function activate() { if (this[kActivated]) return; this[kActivated] = true; return this.addInboundListeners() && this._consumeInbound(); }; +/** + * Cancel inbound subscriptions and any pending run/format consumers. + */ Activity.prototype.deactivate = function deactivate() { this[kActivated] = false; const broker = this.broker; @@ -258,6 +271,10 @@ Activity.prototype.deactivate = function deactivate() { broker.cancel('_format-consumer'); }; +/** + * Initialise activity executionId and emit init event without starting the run. + * @param {Record} [initContent] Optional content merged into the init message + */ Activity.prototype.init = function init(initContent) { const id = this.id; const exec = this[kExec]; @@ -267,6 +284,11 @@ Activity.prototype.init = function init(initContent) { this._publishEvent('init', this._createMessage({ ...initContent, executionId })); }; +/** + * Start running the activity by publishing run.enter and run.start. + * @param {Record} [runContent] Optional content merged into the run message + * @throws {Error} if the activity is already running + */ Activity.prototype.run = function run(runContent) { const id = this.id; if (this.isRunning) throw new Error(`activity <${id}> is already running`); @@ -288,6 +310,10 @@ Activity.prototype.run = function run(runContent) { this._consumeRunQ(); }; +/** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ Activity.prototype.getState = function getState() { const status = this.status; const exec = this[kExec]; @@ -308,9 +334,15 @@ Activity.prototype.getState = function getState() { }; }; +/** + * Restore activity state captured by getState. Cannot be called while running. + * @param {import('types').ActivityState} [state] + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ Activity.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running activity <${this.id}>`); - if (!state) return; // TODO: return this + if (!state) return this; this.stopped = state.stopped; this.status = state.status; @@ -328,6 +360,10 @@ Activity.prototype.recover = function recover(state) { return this; }; +/** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ Activity.prototype.resume = function resume() { if (this[kConsuming]) { throw new Error(`cannot resume running activity <${this.id}>`); @@ -345,6 +381,10 @@ Activity.prototype.resume = function resume() { this._consumeRunQ(); }; +/** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param {Record} [discardContent] Optional content propagated with the discard + */ Activity.prototype.discard = function discard(discardContent) { if (!this.status) return this._runDiscard(discardContent); const execution = this[kExec].get('execution'); @@ -358,6 +398,10 @@ Activity.prototype.discard = function discard(discardContent) { this._consumeRunQ(); }; +/** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ Activity.prototype.addInboundListeners = function addInboundListeners() { const triggers = this[kFlows].inboundTriggers; if (triggers.length) { @@ -376,6 +420,9 @@ Activity.prototype.addInboundListeners = function addInboundListeners() { return triggers.length; }; +/** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ Activity.prototype.removeInboundListeners = function removeInboundListeners() { const triggerConsumerTag = `_inbound-${this.id}`; for (const trigger of this[kFlows].inboundTriggers) { @@ -383,11 +430,17 @@ Activity.prototype.removeInboundListeners = function removeInboundListeners() { } }; +/** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ Activity.prototype.stop = function stop() { if (!this[kConsuming]) return this.broker.cancel('_run-on-inbound'); return this.getApi(this[kStateMessage]).stop(); }; +/** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ Activity.prototype.next = function next() { if (!this.environment.settings.step) return; const stateMessage = this[kStateMessage]; @@ -399,24 +452,42 @@ Activity.prototype.next = function next() { return current; }; +/** + * Walk outbound flows to discover the activity graph from this point. + */ Activity.prototype.shake = function shake() { this._shakeOutbound({ content: this._createMessage() }); }; +/** + * Evaluate outbound sequence flows for the given source message. + * @param {import('types').ElementBrokerMessage} fromMessage Source run message + * @param {boolean} discardRestAtTake When true, take only the first matching flow and discard the rest + * @param {(err: Error, evaluationResult: any) => void} callback + */ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) { return this[kFlows].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); }; +/** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * @param {import('types').ElementBrokerMessage} [message] + */ Activity.prototype.getApi = function getApi(message) { const execution = this[kExec].get('execution'); if (execution && !execution.completed) return execution.getApi(message); return ActivityApi(this.broker, message || this[kStateMessage]); }; +/** + * Look up another activity in the same context. + * @param {string} elementId + */ Activity.prototype.getActivityById = function getActivityById(elementId) { return this.context.getActivityById(elementId); }; +/** @internal */ Activity.prototype._runDiscard = function runDiscard(discardContent) { const exec = this[kExec]; const executionId = exec.get('initExecutionId') || getUniqueId(this.id); @@ -432,6 +503,7 @@ Activity.prototype._runDiscard = function runDiscard(discardContent) { this._consumeRunQ(); }; +/** @internal */ Activity.prototype._discardRun = function discardRun() { const status = this.status; if (!status) return; @@ -465,6 +537,7 @@ Activity.prototype._discardRun = function discardRun() { this._consumeRunQ(); }; +/** @internal */ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { if (this[kFlags].isParallelGateway) { const message = cloneMessage(sourceMessage, { join: this.id }); @@ -478,6 +551,7 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { this._shakeOutbound(sourceMessage); }; +/** @internal */ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { const message = cloneMessage(sourceMessage); const sequence = (message.content.sequence = message.content.sequence || []); @@ -504,6 +578,7 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { for (const t of targets.values()) t.shake(message); }; +/** @internal */ Activity.prototype._consumeInbound = function consumeInbound() { if (!this[kActivated]) return; @@ -515,6 +590,7 @@ Activity.prototype._consumeInbound = function consumeInbound() { return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); }; +/** @internal */ Activity.prototype._onInbound = function onInbound(routingKey, message) { message.ack(); const broker = this.broker; @@ -542,6 +618,7 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { } }; +/** @internal */ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message) { const { fields, content, properties } = message; const inboundQ = this.broker.getQueue('inbound-q'); @@ -564,11 +641,13 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message } }; +/** @internal */ Activity.prototype._consumeRunQ = function consumeRunQ() { this[kConsumingRunQ] = true; this.broker.getQueue('run-q').assertConsumer(this[kMessageHandlers].onRunMessage, { exclusive: true, consumerTag: '_activity-run' }); }; +/** @internal */ Activity.prototype._pauseRunQ = function pauseRunQ() { if (!this[kConsumingRunQ]) return; @@ -576,6 +655,7 @@ Activity.prototype._pauseRunQ = function pauseRunQ() { this.broker.cancel('_activity-run'); }; +/** @internal */ Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, messageProperties) { switch (routingKey) { case 'run.execute.passthrough': @@ -601,6 +681,7 @@ Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, me }); }; +/** @internal */ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, message) { const isRedelivered = message.fields.redelivered; const content = cloneContent(message.content); @@ -741,6 +822,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, if (!step) message.ack(); }; +/** @internal */ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) { const executeMessage = this[kExecuteMessage]; const content = cloneContent({ @@ -786,12 +868,14 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, this._ackRunExecuteMessage(); }; +/** @internal */ Activity.prototype._ackRunExecuteMessage = function ackRunExecuteMessage() { if (this.environment.settings.step) return; const executeMessage = this[kExecuteMessage]; executeMessage.ack(); }; +/** @internal */ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOutbound) { const { content, properties } = message; const correlationId = properties.correlationId; @@ -818,6 +902,7 @@ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOut }); }; +/** @internal */ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) { const outboundSequenceFlows = this[kFlows].outboundSequenceFlows; if (!outboundSequenceFlows.length) return callback(null, []); @@ -848,6 +933,7 @@ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, c }); }; +/** @internal */ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) { if (outboundList.length === 1) { this._publishRunOutbound(outboundList[0], content, discardSequence); @@ -871,6 +957,7 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content return outboundList; }; +/** @internal */ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content, discardSequence) { const { id: flowId, action, result } = outboundFlow; @@ -892,6 +979,7 @@ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlo ); }; +/** @internal */ Activity.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); @@ -917,6 +1005,7 @@ Activity.prototype._onResumeMessage = function onResumeMessage(message) { return this.broker.publish('run', fields.routingKey, cloneContent(stateMessage.content), stateMessage.properties); }; +/** @internal */ Activity.prototype._publishEvent = function publishEvent(state, content, properties) { this.broker.publish('event', `activity.${state}`, cloneContent(content, { state }), { ...properties, @@ -925,6 +1014,7 @@ Activity.prototype._publishEvent = function publishEvent(state, content, propert }); }; +/** @internal */ Activity.prototype._onStop = function onStop(message) { const running = this[kConsuming]; @@ -945,6 +1035,7 @@ Activity.prototype._onStop = function onStop(message) { } }; +/** @internal */ Activity.prototype._consumeApi = function consumeApi() { const executionId = this[kExec].get('executionId'); if (!executionId) return; @@ -957,6 +1048,7 @@ Activity.prototype._consumeApi = function consumeApi() { }); }; +/** @internal */ Activity.prototype._onApiMessage = function onApiMessage(routingKey, message) { switch (message.properties.type) { case 'discard': { @@ -971,6 +1063,7 @@ Activity.prototype._onApiMessage = function onApiMessage(routingKey, message) { } }; +/** @internal */ Activity.prototype._createMessage = function createMessage(override) { const { name, status, parent } = this; @@ -990,10 +1083,12 @@ Activity.prototype._createMessage = function createMessage(override) { return result; }; +/** @internal */ Activity.prototype._getOutboundSequenceFlowById = function getOutboundSequenceFlowById(flowId) { return this[kFlows].outboundSequenceFlows.find((flow) => flow.id === flowId); }; +/** @internal */ Activity.prototype._deactivateRunConsumers = function _deactivateRunConsumers() { const broker = this.broker; broker.cancel('_activity-api'); diff --git a/src/activity/ActivityExecution.js b/src/activity/ActivityExecution.js index 451b9adf..0a17138f 100644 --- a/src/activity/ActivityExecution.js +++ b/src/activity/ActivityExecution.js @@ -9,6 +9,12 @@ const kPostponed = Symbol.for('postponed'); export default ActivityExecution; +/** + * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour + * and drives the execute message flow over the activity broker. + * @param {import('types').Activity} activity + * @param {import('types').ContextInstance} context + */ function ActivityExecution(activity, context) { this.activity = activity; this.context = context; @@ -30,6 +36,11 @@ Object.defineProperty(ActivityExecution.prototype, 'completed', { }, }); +/** + * Begin executing the activity behaviour. Resumes if the message is redelivered. + * @param {import('types').ElementBrokerMessage} executeMessage + * @throws {Error} when message or executionId is missing + */ ActivityExecution.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new Error('Execution requires message'); const executionId = executeMessage.content?.executionId; @@ -58,6 +69,9 @@ ActivityExecution.prototype.execute = function execute(executeMessage) { this.broker.publish('execution', 'execute.start', cloneContent(initMessage.content)); }; +/** + * Bind the execute queue and start consuming execute and api messages. + */ ActivityExecution.prototype.activate = function activate() { if (this[kCompleted]) return; @@ -82,6 +96,9 @@ ActivityExecution.prototype.activate = function activate() { }); }; +/** + * Cancel execute and api consumers and unbind the execute queue. + */ ActivityExecution.prototype.deactivate = function deactivate() { const broker = this.broker; broker.cancel('_activity-api-execution'); @@ -89,6 +106,9 @@ ActivityExecution.prototype.deactivate = function deactivate() { broker.unbindQueue('execute-q', 'execution', 'execute.#'); }; +/** + * Discard the running execution. + */ ActivityExecution.prototype.discard = function discard() { if (this[kCompleted]) return; const initMessage = this[kExecuteMessage]; @@ -96,6 +116,10 @@ ActivityExecution.prototype.discard = function discard() { this.getApi(initMessage).discard(); }; +/** + * Resolve an Api wrapper, preferring a behaviour-specific Api when the source exposes one. + * @param {import('types').ElementBrokerMessage} [apiMessage] + */ ActivityExecution.prototype.getApi = function getApi(apiMessage) { const self = this; if (!apiMessage) apiMessage = this[kExecuteMessage]; @@ -119,11 +143,18 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { return api; }; +/** + * Pass an execute message straight to the behaviour, executing first if no source is set up yet. + * @param {import('types').ElementBrokerMessage} executeMessage + */ ActivityExecution.prototype.passthrough = function passthrough(executeMessage) { if (!this.source) return this.execute(executeMessage); return this._sourceExecute(executeMessage); }; +/** + * List currently postponed executions as Api wrappers, including those from sub-process behaviours. + */ ActivityExecution.prototype.getPostponed = function getPostponed() { let apis = []; for (const msg of this[kPostponed]) { @@ -134,6 +165,9 @@ ActivityExecution.prototype.getPostponed = function getPostponed() { return apis; }; +/** + * Snapshot execution state, merging behaviour-specific state when the source provides it. + */ ActivityExecution.prototype.getState = function getState() { const result = { completed: this[kCompleted] }; const source = this.source; @@ -142,6 +176,11 @@ ActivityExecution.prototype.getState = function getState() { return { ...result, ...source.getState() }; }; +/** + * Restore execution state captured by getState. + * @param {import('types').ActivityExecutionState} [state] + * @returns this + */ ActivityExecution.prototype.recover = function recover(state) { this[kPostponed].clear(); @@ -156,12 +195,16 @@ ActivityExecution.prototype.recover = function recover(state) { return this; }; +/** + * Stop the execution via the activity api. + */ ActivityExecution.prototype.stop = function stop() { const executeMessage = this[kExecuteMessage]; if (!executeMessage) return; this.getApi(executeMessage).stop(); }; +/** @internal */ ActivityExecution.prototype._sourceExecute = function sourceExecute(executeMessage) { try { return this.source.execute(executeMessage); @@ -170,6 +213,7 @@ ActivityExecution.prototype._sourceExecute = function sourceExecute(executeMessa } }; +/** @internal */ ActivityExecution.prototype._onExecuteMessage = function onExecuteMessage(routingKey, message) { const { fields, content, properties } = message; const isRedelivered = fields.redelivered; @@ -216,6 +260,7 @@ ActivityExecution.prototype._onExecuteMessage = function onExecuteMessage(routin } }; +/** @internal */ ActivityExecution.prototype._onStateChangeMessage = function onStateChangeMessage(message) { const { ignoreIfExecuting, executionId } = message.content; const postponed = this[kPostponed]; @@ -242,6 +287,7 @@ ActivityExecution.prototype._onStateChangeMessage = function onStateChangeMessag } }; +/** @internal */ ActivityExecution.prototype._onExecutionCompleted = function onExecutionCompleted(message) { const postponedMsg = this._ackPostponed(message); if (!postponedMsg) return; @@ -274,6 +320,7 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete this._publishExecutionCompleted('completed', { ...postponedMsg.content, ...message.content }, message.properties.correlationId); }; +/** @internal */ ActivityExecution.prototype._onExecutionDiscarded = function onExecutionDiscarded(discardType, message) { const postponedMsg = this._ackPostponed(message); const { isRootScope, error } = message.content; @@ -303,6 +350,7 @@ ActivityExecution.prototype._onExecutionDiscarded = function onExecutionDiscarde this._publishExecutionCompleted(discardType, cloneContent(message.content), correlationId); }; +/** @internal */ ActivityExecution.prototype._publishExecutionCompleted = function publishExecutionCompleted( completionType, completeContent, @@ -321,6 +369,7 @@ ActivityExecution.prototype._publishExecutionCompleted = function publishExecuti ); }; +/** @internal */ ActivityExecution.prototype._ackPostponed = function ackPostponed(completeMessage) { const { executionId: eid } = completeMessage.content; @@ -334,6 +383,7 @@ ActivityExecution.prototype._ackPostponed = function ackPostponed(completeMessag } }; +/** @internal */ ActivityExecution.prototype._onParentApiMessage = function onParentApiMessage(routingKey, message) { switch (message.properties.type) { case 'error': @@ -346,6 +396,7 @@ ActivityExecution.prototype._onParentApiMessage = function onParentApiMessage(ro } }; +/** @internal */ ActivityExecution.prototype._onStop = function onStop(message) { const stoppedId = message?.content?.executionId; const running = this.getPostponed(); @@ -359,6 +410,7 @@ ActivityExecution.prototype._onStop = function onStop(message) { this.broker.cancel('_activity-api-execution'); }; +/** @internal */ ActivityExecution.prototype._debug = function debug(logMessage, executionId) { executionId = executionId || this.executionId; this.activity.logger.debug(`<${executionId} (${this.id})> ${logMessage}`); diff --git a/src/definition/Definition.js b/src/definition/Definition.js index 64553c04..00e4e11c 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -16,6 +16,12 @@ const kStopped = Symbol.for('stopped'); export default Definition; +/** + * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and + * mediates inter-process messaging. + * @param {import('types').ContextInstance} context + * @param {import('types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged + */ export function Definition(context, options) { if (!(this instanceof Definition)) return new Definition(context, options); if (!context) throw new Error('No context'); @@ -103,6 +109,14 @@ Object.defineProperties(Definition.prototype, { }, }); +/** + * Start running the definition. Accepts run options, a callback, or both. + * The callback fires once on leave, stop, or error. + * @param {Record | import('types').runCallback} [optionsOrCallback] + * @param {import('types').runCallback} [optionalCallback] + * @returns this + * @throws {Error} when already running and no callback is supplied + */ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { const [runOptions, callback] = getOptionsAndCallback(optionsOrCallback, optionalCallback); if (this.isRunning) { @@ -132,6 +146,12 @@ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { return this; }; +/** + * Resume after recover by republishing the last run message. The callback fires once on + * leave, stop, or error. + * @param {import('types').runCallback} [callback] + * @returns this + */ Definition.prototype.resume = function resume(callback) { if (this.isRunning) { const err = new Error('cannot resume running definition'); @@ -154,6 +174,9 @@ Definition.prototype.resume = function resume(callback) { return this; }; +/** + * Snapshot definition state for recover. + */ Definition.prototype.getState = function getState() { return this._createMessage({ status: this.status, @@ -165,6 +188,12 @@ Definition.prototype.getState = function getState() { }); }; +/** + * Restore definition state captured by getState. + * @param {import('types').DefinitionState} [state] + * @returns this + * @throws {Error} when called on a running definition + */ Definition.prototype.recover = function recover(state) { if (this.isRunning) throw new Error('cannot recover running definition'); if (!state) return this; @@ -189,6 +218,11 @@ Definition.prototype.recover = function recover(state) { return this; }; +/** + * Walk activity graphs to discover sequences. Limited to the activity's owning process + * when startId is given, otherwise all processes are shaken. + * @param {string} [startId] + */ Definition.prototype.shake = function shake(startId) { let result = {}; let bps; @@ -207,6 +241,7 @@ Definition.prototype.shake = function shake(startId) { return result; }; +/** @internal */ Definition.prototype._shakeProcess = function shakeProcess(shakeBp, startId) { let shovel; if (!shakeBp.isRunning) { @@ -229,28 +264,44 @@ Definition.prototype._shakeProcess = function shakeProcess(shakeBp, startId) { return shakeResult; }; +/** + * Get every process in the definition. + */ Definition.prototype.getProcesses = function getProcesses() { const execution = this.execution; if (execution) return execution.getProcesses(); return this.context.getProcesses(); }; +/** + * Get processes flagged executable in the definition. + */ Definition.prototype.getExecutableProcesses = function getExecutableProcesses() { const execution = this.execution; if (execution) return execution.getExecutableProcesses(); return this.context.getExecutableProcesses(); }; +/** + * Get processes that are currently running. + */ Definition.prototype.getRunningProcesses = function getRunningProcesses() { const execution = this.execution; if (!execution) return []; return execution.getRunningProcesses(); }; +/** + * @param {string} processId + */ Definition.prototype.getProcessById = function getProcessById(processId) { return this.getProcesses().find((p) => p.id === processId); }; +/** + * Find an activity by id across all processes in the definition. + * @param {string} childId + */ Definition.prototype.getActivityById = function getActivityById(childId) { const bps = this.getProcesses(); for (const bp of bps) { @@ -260,16 +311,29 @@ Definition.prototype.getActivityById = function getActivityById(childId) { return null; }; +/** + * Lookup any element (activity, flow, etc.) in the parsed definition by id. + * @param {string} elementId + */ Definition.prototype.getElementById = function getElementById(elementId) { return this.context.getActivityById(elementId); }; +/** + * List currently postponed activities as Api wrappers. + * @param {import('types').filterPostponed} [filterFn] + */ Definition.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; if (!execution) return []; return execution.getPostponed(...args); }; +/** + * Resolve a Definition Api wrapper, preferring the running execution if any. + * @param {import('types').ElementBrokerMessage} [message] + * @throws {Error} when the definition is not running and no message is given + */ Definition.prototype.getApi = function getApi(message) { const execution = this.execution; if (execution) return execution.getApi(message); @@ -278,14 +342,27 @@ Definition.prototype.getApi = function getApi(message) { return DefinitionApi(this.broker, message); }; +/** + * Send a delegated signal to the running definition. + * @param {import('types').signalMessage} [message] + */ Definition.prototype.signal = function signal(message) { return this.getApi().signal(message, { delegate: true }); }; +/** + * Cancel a running activity inside the definition by delegated api message. + * @param {import('types').signalMessage} [message] + */ Definition.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { delegate: true }); }; +/** + * Deliver a message to a referenced element. Resolves the message reference when the + * target element exposes a `resolve` method (e.g. message-, signal-, escalation events). + * @param {{ id?: string, [x: string]: any }} message + */ Definition.prototype.sendMessage = function sendMessage(message) { const messageContent = { message }; let messageType = 'message'; @@ -299,11 +376,15 @@ Definition.prototype.sendMessage = function sendMessage(message) { return this.getApi().sendApiMessage(messageType, messageContent, { delegate: true }); }; +/** + * Stop the definition if running. + */ Definition.prototype.stop = function stop() { if (!this.isRunning) return; this.getApi().stop(); }; +/** @internal */ Definition.prototype._activateRunConsumers = function activateRunConsumers() { this[kConsuming] = true; const broker = this.broker; @@ -318,6 +399,7 @@ Definition.prototype._activateRunConsumers = function activateRunConsumers() { }); }; +/** @internal */ Definition.prototype._deactivateRunConsumers = function deactivateRunConsumers() { const broker = this.broker; broker.cancel('_definition-api'); @@ -326,6 +408,7 @@ Definition.prototype._deactivateRunConsumers = function deactivateRunConsumers() this[kConsuming] = false; }; +/** @internal */ Definition.prototype._createMessage = function createMessage(override) { return { id: this.id, @@ -336,6 +419,7 @@ Definition.prototype._createMessage = function createMessage(override) { }; }; +/** @internal */ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) { const { content, fields } = message; if (routingKey === 'run.resume') { @@ -430,6 +514,7 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) message.ack(); }; +/** @internal */ Definition.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); @@ -451,6 +536,7 @@ Definition.prototype._onResumeMessage = function onResumeMessage(message) { return this.broker.publish('run', stateMessage.fields.routingKey, cloneContent(stateMessage.content), stateMessage.properties); }; +/** @internal */ Definition.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) { const { content, properties } = message; const messageType = properties.type; @@ -476,6 +562,7 @@ Definition.prototype._onExecutionMessage = function onExecutionMessage(routingKe executeMessage.ack(); }; +/** @internal */ Definition.prototype._onApiMessage = function onApiMessage(routingKey, message) { if (message.properties.type === 'stop') { const execution = this.execution; @@ -485,6 +572,7 @@ Definition.prototype._onApiMessage = function onApiMessage(routingKey, message) } }; +/** @internal */ Definition.prototype._publishEvent = function publishEvent(action, content, msgOpts) { const execution = this.execution; this.broker.publish('event', `definition.${action}`, execution ? execution._createMessage(content) : cloneContent(content), { @@ -493,12 +581,14 @@ Definition.prototype._publishEvent = function publishEvent(action, content, msgO }); }; +/** @internal */ Definition.prototype._onStop = function onStop() { this[kStopped] = true; this._deactivateRunConsumers(); return this._publishEvent('stop', this._createMessage()); }; +/** @internal */ Definition.prototype._onBrokerReturnFn = function onBrokerReturn(message) { if (message.properties.type === 'error') { this._deactivateRunConsumers(); @@ -507,6 +597,7 @@ Definition.prototype._onBrokerReturnFn = function onBrokerReturn(message) { } }; +/** @internal */ Definition.prototype._reset = function reset() { this[kExec].delete('executionId'); this._deactivateRunConsumers(); @@ -514,6 +605,7 @@ Definition.prototype._reset = function reset() { this.broker.purgeQueue('execution-q'); }; +/** @internal */ Definition.prototype._debug = function debug(msg) { this.logger.debug(`<${this.id}> ${msg}`); }; diff --git a/src/definition/DefinitionExecution.js b/src/definition/DefinitionExecution.js index ed6cc178..93df105f 100644 --- a/src/definition/DefinitionExecution.js +++ b/src/definition/DefinitionExecution.js @@ -12,6 +12,12 @@ const kProcesses = Symbol.for('processes'); const kStatus = Symbol.for('status'); const kStopped = Symbol.for('stopped'); +/** + * Drives the execution of a Definition. Activates executable processes, routes inter-process + * delegate messages and call activity hand-offs, and rolls completion up to the Definition. + * @param {import('types').Definition} definition + * @param {import('types').ContextInstance} context + */ export default function DefinitionExecution(definition, context) { const broker = definition.broker; @@ -23,7 +29,9 @@ export default function DefinitionExecution(definition, context) { this.context = context; const processes = context.getProcesses(); + /** @type {Set} */ const ids = new Set(); + /** @type {Set} */ const executable = new Set(); for (const bp of processes) { bp.environment.assignVariables(environment.variables); @@ -33,10 +41,13 @@ export default function DefinitionExecution(definition, context) { } this[kProcesses] = { + /** @type {import('../process/Process.js').Process[]} */ processes, ids, executable, + /** @type {Set} */ running: new Set(), + /** @type {Set} */ postponed: new Set(), }; @@ -118,6 +129,12 @@ Object.defineProperties(DefinitionExecution.prototype, { }, }); +/** + * Activate executable processes and start the definition execution. Resumes if the message + * is redelivered. When `content.processId` is set, only that process is started. + * @param {import('types').ElementBrokerMessage} executeMessage + * @throws {Error} when message or executionId is missing + */ DefinitionExecution.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new Error('Definition execution requires message'); const content = executeMessage.content; @@ -156,6 +173,9 @@ DefinitionExecution.prototype.execute = function execute(executeMessage) { return true; }; +/** + * Resume after recover by reactivating running processes. + */ DefinitionExecution.prototype.resume = function resume() { this._debug(`resume ${this[kStatus]} definition execution`); @@ -174,6 +194,11 @@ DefinitionExecution.prototype.resume = function resume() { for (const bp of running) bp.resume(); }; +/** + * Restore execution state captured by getState. Reinstates running processes from the snapshot. + * @param {import('types').DefinitionExecutionState} [state] + * @returns this + */ DefinitionExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; @@ -206,10 +231,16 @@ DefinitionExecution.prototype.recover = function recover(state) { return this; }; +/** + * Stop the running execution via the api. + */ DefinitionExecution.prototype.stop = function stop() { this.getApi().stop(); }; +/** + * Get every process in the definition (running first, then any non-running by id). + */ DefinitionExecution.prototype.getProcesses = function getProcesses() { const { running, processes } = this[kProcesses]; const result = [...running]; @@ -219,28 +250,47 @@ DefinitionExecution.prototype.getProcesses = function getProcesses() { return result; }; +/** + * @param {string} processId + */ DefinitionExecution.prototype.getProcessById = function getProcessById(processId) { return this.getProcesses().find((bp) => bp.id === processId); }; +/** + * Get every process matching the given id (call activities can spawn duplicates). + * @param {string} processId + */ DefinitionExecution.prototype.getProcessesById = function getProcessesById(processId) { return this.getProcesses().filter((bp) => bp.id === processId); }; +/** + * @param {string} processExecutionId + */ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExecutionId(processExecutionId) { for (const bp of this[kProcesses].running) { if (bp.executionId === processExecutionId) return bp; } }; +/** + * Get processes that have an executionId, i.e. are currently running. + */ DefinitionExecution.prototype.getRunningProcesses = function getRunningProcesses() { return [...this[kProcesses].running].filter((bp) => bp.executionId); }; +/** + * Get processes flagged executable in the definition. + */ DefinitionExecution.prototype.getExecutableProcesses = function getExecutableProcesses() { return [...this[kProcesses].executable]; }; +/** + * Snapshot execution state for recover. + */ DefinitionExecution.prototype.getState = function getState() { const processes = []; for (const bp of this[kProcesses].running) { @@ -256,6 +306,10 @@ DefinitionExecution.prototype.getState = function getState() { }; }; +/** + * Resolve a Definition Api or, when the message belongs to a child process, its process Api. + * @param {import('types').ElementBrokerMessage} [apiMessage] + */ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { if (!apiMessage) apiMessage = this[kExecuteMessage] || { content: this._createMessage() }; @@ -280,6 +334,10 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { return api; }; +/** + * List currently postponed activities across every running process. + * @param {import('types').filterPostponed} [filterFn] + */ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { let result = []; for (const bp of this[kProcesses].running) { @@ -288,6 +346,7 @@ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { return result; }; +/** @internal */ DefinitionExecution.prototype._start = function start() { const { ids, executable, postponed } = this[kProcesses]; if (!ids.size) { @@ -310,6 +369,7 @@ DefinitionExecution.prototype._start = function start() { }); }; +/** @internal */ DefinitionExecution.prototype._activate = function activate(processList) { this.broker.subscribeTmp('api', '#', this[kMessageHandlers].onApiMessage, { noAck: true, @@ -319,6 +379,7 @@ DefinitionExecution.prototype._activate = function activate(processList) { this[kActivated] = true; }; +/** @internal */ DefinitionExecution.prototype._activateProcess = function activateProcess(bp) { const handlers = this[kMessageHandlers]; const broker = bp.broker; @@ -350,6 +411,7 @@ DefinitionExecution.prototype._activateProcess = function activateProcess(bp) { }); }; +/** @internal */ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, originalMessage) { const message = cloneMessage(originalMessage); const content = message.content; @@ -368,6 +430,7 @@ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, this[kProcessesQ].queueMessage(message.fields, cloneContent(content), message.properties); }; +/** @internal */ DefinitionExecution.prototype._deactivate = function deactivate() { this.broker.cancel('_definition-api-consumer'); this.broker.cancel(`_definition-activity-${this.executionId}`); @@ -375,6 +438,7 @@ DefinitionExecution.prototype._deactivate = function deactivate() { this[kActivated] = false; }; +/** @internal */ DefinitionExecution.prototype._deactivateProcess = function deactivateProcess(bp) { bp.broker.cancel('_definition-outbound-message-consumer'); bp.broker.cancel('_definition-activity-consumer'); @@ -383,6 +447,7 @@ DefinitionExecution.prototype._deactivateProcess = function deactivateProcess(bp bp.broker.cancel('_definition-call-cancel-consumer'); }; +/** @internal */ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(routingKey, message) { const content = message.content; const isRedelivered = message.fields.redelivered; @@ -454,6 +519,7 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout } }; +/** @internal */ DefinitionExecution.prototype._stateChangeMessage = function stateChangeMessage(message, postponeMessage) { let previousMsg; const postponed = this[kProcesses].postponed; @@ -469,6 +535,7 @@ DefinitionExecution.prototype._stateChangeMessage = function stateChangeMessage( if (postponeMessage) postponed.add(message); }; +/** @internal */ DefinitionExecution.prototype._onProcessCompleted = function onProcessCompleted(message) { this._stateChangeMessage(message, false); if (message.fields.redelivered) return message.ack(); @@ -487,6 +554,7 @@ DefinitionExecution.prototype._onProcessCompleted = function onProcessCompleted( } }; +/** @internal */ DefinitionExecution.prototype._onStopped = function onStopped(message) { const running = this[kProcesses].running; this._debug(`stop definition execution (stop process executions ${running.size})`); @@ -505,6 +573,7 @@ DefinitionExecution.prototype._onStopped = function onStopped(message) { ); }; +/** @internal */ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, message) { const messageType = message.properties.type; const delegate = message.properties.delegate; @@ -527,6 +596,7 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, } }; +/** @internal */ DefinitionExecution.prototype._startProcessesByMessage = function startProcessesByMessage(reference) { const { processes: bps, running } = this[kProcesses]; if (bps.length < 2) return; @@ -556,6 +626,7 @@ DefinitionExecution.prototype._startProcessesByMessage = function startProcesses } }; +/** @internal */ DefinitionExecution.prototype._onMessageOutbound = function onMessageOutbound(routingKey, message) { const content = message.content; const { target, source } = content; @@ -589,6 +660,7 @@ DefinitionExecution.prototype._onMessageOutbound = function onMessageOutbound(ro targetProcess.sendMessage(message); }; +/** @internal */ DefinitionExecution.prototype._onCallActivity = function onCallActivity(routingKey, message) { const content = message.content; const { calledElement, id: fromId, executionId: fromExecutionId, name: fromName, parent: fromParent } = content; @@ -620,6 +692,7 @@ DefinitionExecution.prototype._onCallActivity = function onCallActivity(routingK targetProcess.run({ inbound: [cloneContent(content)] }); }; +/** @internal */ DefinitionExecution.prototype._onCancelCallActivity = function onCancelCallActivity(routingKey, message) { const { calledElement, id: fromId, executionId: fromExecutionId, parent: fromParent } = message.content; if (!calledElement) return; @@ -644,6 +717,7 @@ DefinitionExecution.prototype._onCancelCallActivity = function onCancelCallActiv } }; +/** @internal */ DefinitionExecution.prototype._onDelegateMessage = function onDelegateMessage(routingKey, executeMessage) { const content = executeMessage.content; const messageType = executeMessage.properties.type; @@ -681,12 +755,14 @@ DefinitionExecution.prototype._onDelegateMessage = function onDelegateMessage(ro ); }; +/** @internal */ DefinitionExecution.prototype._removeProcessByExecutionId = function removeProcessByExecutionId(processExecutionId) { const bp = this.getProcessByExecutionId(processExecutionId); if (bp) this[kProcesses].running.delete(bp); return bp; }; +/** @internal */ DefinitionExecution.prototype._complete = function complete(completionType, content, options) { this._deactivate(); const stateMessage = this[kExecuteMessage]; @@ -709,6 +785,7 @@ DefinitionExecution.prototype._complete = function complete(completionType, cont ); }; +/** @internal */ DefinitionExecution.prototype._createMessage = function createMessage(content) { return { id: this.id, @@ -719,6 +796,7 @@ DefinitionExecution.prototype._createMessage = function createMessage(content) { }; }; +/** @internal */ DefinitionExecution.prototype._getProcessApi = function getProcessApi(message) { const content = message.content; let api = this._getProcessApiByExecutionId(content.executionId, message); @@ -737,12 +815,14 @@ DefinitionExecution.prototype._getProcessApi = function getProcessApi(message) { } }; +/** @internal */ DefinitionExecution.prototype._getProcessApiByExecutionId = function getProcessApiByExecutionId(parentExecutionId, message) { const processInstance = this.getProcessByExecutionId(parentExecutionId); if (!processInstance) return; return processInstance.getApi(message); }; +/** @internal */ DefinitionExecution.prototype._debug = function debug(logMessage) { this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; diff --git a/src/process/Process.js b/src/process/Process.js index c9c6f71d..44982107 100644 --- a/src/process/Process.js +++ b/src/process/Process.js @@ -18,6 +18,12 @@ const kStopped = Symbol.for('stopped'); export default Process; +/** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * @param {import('moddle-context-serializer').SerializableElement} processDef + * @param {import('types').ContextInstance} context + */ export function Process(processDef, context) { const { id, type = 'process', name, parent, behaviour = {} } = processDef; this.id = id; @@ -110,6 +116,10 @@ Object.defineProperties(Process.prototype, { }, }); +/** + * Allocate an executionId and emit init event without starting the run. + * @param {string} [useAsExecutionId] Override for the generated execution id + */ Process.prototype.init = function init(useAsExecutionId) { const initExecutionId = useAsExecutionId || getUniqueId(this.id); this[kExec].set('initExecutionId', initExecutionId); @@ -118,6 +128,11 @@ Process.prototype.init = function init(useAsExecutionId) { this._publishEvent('init', this._createMessage({ executionId: initExecutionId })); }; +/** + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param {Record} [runContent] Optional content merged into the run message + * @throws {Error} when the process is already running + */ Process.prototype.run = function run(runContent) { if (this.isRunning) throw new Error(`process <${this.id}> is already running`); @@ -136,6 +151,11 @@ Process.prototype.run = function run(runContent) { this._activateRunConsumers(); }; +/** + * Resume after recover by republishing the last run message. + * @returns this + * @throws {Error} when called on a running process + */ Process.prototype.resume = function resume() { if (this.isRunning) throw new Error(`cannot resume running process <${this.id}>`); if (!this.status) return this; @@ -148,6 +168,9 @@ Process.prototype.resume = function resume() { return this; }; +/** + * Snapshot process state for recover. + */ Process.prototype.getState = function getState() { return { id: this.id, @@ -162,6 +185,12 @@ Process.prototype.getState = function getState() { }; }; +/** + * Restore process state captured by getState. + * @param {import('types').ProcessState} [state] + * @returns this + * @throws {Error} when called on a running process + */ Process.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running process <${this.id}>`); if (!state) return this; @@ -182,30 +211,50 @@ Process.prototype.recover = function recover(state) { return this; }; +/** + * Walk activity graph from the given start id, or every start activity when omitted. + * @param {string} [startId] + */ Process.prototype.shake = function shake(startId) { if (this.isRunning) return this.execution.shake(startId); return new ProcessExecution(this, this.context).shake(startId); }; +/** + * Stop the process if running. + */ Process.prototype.stop = function stop() { if (!this.isRunning) return; this.getApi().stop(); }; +/** + * Resolve a Process Api wrapper, preferring the running execution if any. + * @param {import('types').ElementBrokerMessage} [message] + */ Process.prototype.getApi = function getApi(message) { const execution = this.execution; if (execution) return execution.getApi(message); return ProcessApi(this.broker, message || this[kStateMessage]); }; +/** + * Send a delegated signal to the running process. + * @param {import('types').signalMessage} [message] + */ Process.prototype.signal = function signal(message) { return this.getApi().signal(message, { delegate: true }); }; +/** + * Cancel a running activity inside the process by delegated api message. + * @param {import('types').signalMessage} [message] + */ Process.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { delegate: true }); }; +/** @internal */ Process.prototype._activateRunConsumers = function activateRunConsumers() { this[kConsuming] = true; const broker = this.broker; @@ -214,6 +263,7 @@ Process.prototype._activateRunConsumers = function activateRunConsumers() { broker.getQueue('run-q').assertConsumer(onRunMessage, { exclusive: true, consumerTag: '_process-run' }); }; +/** @internal */ Process.prototype._deactivateRunConsumers = function deactivateRunConsumers() { const broker = this.broker; broker.cancel('_process-api'); @@ -222,6 +272,7 @@ Process.prototype._deactivateRunConsumers = function deactivateRunConsumers() { this[kConsuming] = false; }; +/** @internal */ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { const { content, fields } = message; @@ -315,6 +366,7 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { message.ack(); }; +/** @internal */ Process.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); @@ -337,6 +389,7 @@ Process.prototype._onResumeMessage = function onResumeMessage(message) { return this.broker.publish('run', stateMessage.fields.routingKey, cloneContent(stateMessage.content), stateMessage.properties); }; +/** @internal */ Process.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) { const content = message.content; const messageType = message.properties.type; @@ -364,11 +417,17 @@ Process.prototype._onExecutionMessage = function onExecutionMessage(routingKey, executeMessage.ack(); }; +/** @internal */ Process.prototype._publishEvent = function publishEvent(state, content) { const eventContent = this._createMessage({ ...content, state }); this.broker.publish('event', `process.${state}`, eventContent, { type: state, mandatory: state === 'error' }); }; +/** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. + * @param {import('types').ElementBrokerMessage} message + */ Process.prototype.sendMessage = function sendMessage(message) { const messageContent = message?.content; if (!messageContent) return; @@ -388,40 +447,61 @@ Process.prototype.sendMessage = function sendMessage(message) { this.getApi().sendApiMessage(message.properties.type || 'message', cloneContent(messageContent), { delegate: true }); }; +/** + * @param {string} childId + */ Process.prototype.getActivityById = function getActivityById(childId) { const execution = this.execution; if (execution) return execution.getActivityById(childId); return this.context.getActivityById(childId); }; +/** + * Get every activity in the process scope. + */ Process.prototype.getActivities = function getActivities() { const execution = this.execution; if (execution) return execution.getActivities(); return this.context.getActivities(this.id); }; +/** + * Get start activities, optionally filtered by referenced event definition. + * @param {import('types').startActivityFilterOptions} [filterOptions] + */ Process.prototype.getStartActivities = function getStartActivities(filterOptions) { return this.context.getStartActivities(filterOptions, this.id); }; +/** + * Get sequence flows in the process scope. + */ Process.prototype.getSequenceFlows = function getSequenceFlows() { const execution = this.execution; if (execution) return execution.getSequenceFlows(); return this.context.getSequenceFlows(); }; +/** + * @param {string} laneId + */ Process.prototype.getLaneById = function getLaneById(laneId) { const lanes = this[kLanes]; if (!lanes) return; return lanes.find((lane) => lane.id === laneId); }; +/** + * List currently postponed activities as Api wrappers. + * @param {import('types').filterPostponed} [filterFn] + */ Process.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; if (!execution) return []; return execution.getPostponed(...args); }; +/** @internal */ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { const messageType = message.properties.type; @@ -434,12 +514,14 @@ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { } }; +/** @internal */ Process.prototype._onStop = function onStop() { this[kStopped] = true; this._deactivateRunConsumers(); return this._publishEvent('stop'); }; +/** @internal */ Process.prototype._createMessage = function createMessage(override) { return { id: this.id, @@ -451,6 +533,7 @@ Process.prototype._createMessage = function createMessage(override) { }; }; +/** @internal */ Process.prototype._debug = function debug(msg) { this.logger.debug(`<${this.id}> ${msg}`); }; diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index b52d793f..b57f0507 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -16,6 +16,12 @@ const kStatus = Symbol.for('status'); const kStopped = Symbol.for('stopped'); const kTracker = Symbol.for('activity tracker'); +/** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * @param {import('types').Process | import('types').Activity} parentActivity + * @param {import('types').ContextInstance} context + */ function ProcessExecution(parentActivity, context) { const { id, type, broker, isSubProcess, isTransaction } = parentActivity; @@ -92,6 +98,11 @@ Object.defineProperties(ProcessExecution.prototype, { }, }); +/** + * Activate children and start the process execution. Resumes if the message is redelivered. + * @param {import('types').ElementBrokerMessage} executeMessage + * @throws {Error} when message or executionId is missing + */ ProcessExecution.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new Error('Process execution requires message'); if (!executeMessage.content || !executeMessage.content.executionId) throw new Error('Process execution requires execution id'); @@ -118,6 +129,10 @@ ProcessExecution.prototype.execute = function execute(executeMessage) { return true; }; +/** + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. + */ ProcessExecution.prototype.resume = function resume() { this._debug(`resume process execution at ${this.status}`); @@ -167,6 +182,9 @@ ProcessExecution.prototype.resume = function resume() { if (!postponed.size && status === 'executing') return this._complete('completed'); }; +/** + * Snapshot execution state including children, flows, message flows, and associations. + */ ProcessExecution.prototype.getState = function getState() { const { children, flows, outboundMessageFlows, associations } = this[kElements]; @@ -195,6 +213,11 @@ ProcessExecution.prototype.getState = function getState() { }; }; +/** + * Restore execution state captured by getState. + * @param {import('types').ProcessExecutionState} [state] + * @returns this + */ ProcessExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; @@ -241,14 +264,25 @@ ProcessExecution.prototype.recover = function recover(state) { return this; }; +/** + * Walk activity graph from the given start id, or every start activity when omitted. + * @param {string} [fromId] + */ ProcessExecution.prototype.shake = function shake(fromId) { return Object.fromEntries(this._shakeElements(fromId).sequences); }; +/** + * Stop the running process execution via the api. + */ ProcessExecution.prototype.stop = function stop() { this.getApi().stop(); }; +/** + * List currently postponed children as Api wrappers. + * @param {import('types').filterPostponed} [filterFn] + */ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { const result = []; for (const msg of this[kElements].postponed) { @@ -260,6 +294,9 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { return result; }; +/** + * Queue a discard message that propagates to all running children. + */ ProcessExecution.prototype.discard = function discard() { this[kStatus] = 'discard'; return this[kActivityQ].queueMessage( @@ -273,6 +310,9 @@ ProcessExecution.prototype.discard = function discard() { ); }; +/** + * Queue a cancel message that propagates to all running children. + */ ProcessExecution.prototype.cancel = function discard() { return this[kActivityQ].queueMessage( { routingKey: 'execution.cancel' }, @@ -285,22 +325,38 @@ ProcessExecution.prototype.cancel = function discard() { ); }; +/** + * Get child activities in the process scope. + */ ProcessExecution.prototype.getActivities = function getActivities() { return this[kElements].children.slice(); }; +/** + * @param {string} activityId + */ ProcessExecution.prototype.getActivityById = function getActivityById(activityId) { return this[kElements].children.find((child) => child.id === activityId); }; +/** + * Get sequence flows in the process scope. + */ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() { return this[kElements].flows.slice(); }; +/** + * Get associations in the process scope. + */ ProcessExecution.prototype.getAssociations = function getAssociations() { return this[kElements].associations.slice(); }; +/** + * Resolve a process or child Api for the given message. + * @param {import('types').ElementBrokerMessage} [message] + */ ProcessExecution.prototype.getApi = function getApi(message) { if (!message) return ProcessApi(this.broker, this[kExecuteMessage]); @@ -326,6 +382,7 @@ ProcessExecution.prototype.getApi = function getApi(message) { return api; }; +/** @internal */ ProcessExecution.prototype._start = function start() { if (!this[kElements].children.length) { return this._complete('completed'); @@ -364,6 +421,7 @@ ProcessExecution.prototype._start = function start() { }); }; +/** @internal */ ProcessExecution.prototype._activate = function activate() { const { onApiMessage, onMessageFlowEvent, onActivityEvent } = this[kMessageHandlers]; @@ -436,6 +494,7 @@ ProcessExecution.prototype._activate = function activate() { this[kActivated] = true; }; +/** @internal */ ProcessExecution.prototype._deactivate = function deactivate() { const broker = this.broker; const executionId = this.executionId; @@ -466,6 +525,7 @@ ProcessExecution.prototype._deactivate = function deactivate() { this[kActivated] = false; }; +/** @internal */ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { let executing = true; const id = this.id; @@ -546,6 +606,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { return result; }; +/** @internal */ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) { const eventType = message.properties.type; let delegate = true; @@ -569,10 +630,12 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) return delegate; }; +/** @internal */ ProcessExecution.prototype._onMessageFlowEvent = function onMessageFlowEvent(routingKey, message) { this.broker.publish('message', routingKey, cloneContent(message.content), message.properties); }; +/** @internal */ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { const { fields, content, properties } = message; @@ -609,6 +672,7 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe this[kActivityQ].queueMessage(message.fields, cloneContent(content), { persistent: true, ...message.properties }); }; +/** @internal */ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, message) { if (message.fields.redelivered && message.properties.persistent === false) return message.ack(); @@ -693,12 +757,14 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, } }; +/** @internal */ ProcessExecution.prototype._stateChangeMessage = function stateChangeMessage(message, postponeMessage) { const previousMsg = this._popPostponed(message.content); if (previousMsg) previousMsg.ack(); if (postponeMessage) this[kElements].postponed.add(message); }; +/** @internal */ ProcessExecution.prototype._popPostponed = function popPostponed(byContent) { const { postponed, detachedActivities } = this[kElements]; @@ -732,6 +798,7 @@ ProcessExecution.prototype._popPostponed = function popPostponed(byContent) { return postponedMsg; }; +/** @internal */ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message) { this._stateChangeMessage(message, false); if (message.fields.redelivered) return message.ack(); @@ -782,6 +849,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message } }; +/** @internal */ ProcessExecution.prototype._stopExecution = function stopExecution(message) { const postponedCount = this.postponedCount; this._debug(`stop process execution (stop child executions ${postponedCount})`); @@ -801,6 +869,7 @@ ProcessExecution.prototype._stopExecution = function stopExecution(message) { ); }; +/** @internal */ ProcessExecution.prototype._onDiscard = function onDiscard() { this._deactivate(); const postponed = this[kElements].postponed; @@ -821,6 +890,7 @@ ProcessExecution.prototype._onDiscard = function onDiscard() { return this._complete('discard'); }; +/** @internal */ ProcessExecution.prototype._onCancel = function onCancel() { const postponed = this[kElements].postponed; const running = new Set(postponed); @@ -853,6 +923,7 @@ ProcessExecution.prototype._onCancel = function onCancel() { } }; +/** @internal */ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, message) { if (message.properties.delegate) { return this._delegateApiMessage(routingKey, message); @@ -877,6 +948,7 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes } }; +/** @internal */ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(routingKey, message, continueOnConsumed) { const correlationId = message.properties.correlationId || getUniqueId(this.executionId); this._debug(`delegate api ${routingKey} message to children, with correlationId <${correlationId}>`); @@ -905,6 +977,7 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou return broker.cancel(`_ct-delegate-${correlationId}`); }; +/** @internal */ ProcessExecution.prototype._complete = function complete(completionType, content) { this._deactivate(); this[kCompleted] = true; @@ -938,6 +1011,7 @@ ProcessExecution.prototype._complete = function complete(completionType, content ); }; +/** @internal */ ProcessExecution.prototype._terminate = function terminate(message) { this[kStatus] = 'terminated'; this._debug('terminating process execution'); @@ -960,22 +1034,27 @@ ProcessExecution.prototype._terminate = function terminate(message) { this[kActivityQ].purge(); }; +/** @internal */ ProcessExecution.prototype._getFlowById = function getFlowById(flowId) { return this[kElements].flows.find((f) => f.id === flowId); }; +/** @internal */ ProcessExecution.prototype._getAssociationById = function getAssociationById(associationId) { return this[kElements].associations.find((a) => a.id === associationId); }; +/** @internal */ ProcessExecution.prototype._getMessageFlowById = function getMessageFlowById(flowId) { return this[kElements].outboundMessageFlows.find((f) => f.id === flowId); }; +/** @internal */ ProcessExecution.prototype._getChildById = function getChildById(childId) { return this.getActivityById(childId) || this._getFlowById(childId); }; +/** @internal */ ProcessExecution.prototype._getChildApi = function getChildApi(message) { const content = message.content; @@ -995,6 +1074,7 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { } }; +/** @internal */ ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { if (message.fields.routingKey !== 'activity.shake.end') return; let seq; @@ -1006,6 +1086,7 @@ ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { } }; +/** @internal */ ProcessExecution.prototype._debug = function debugMessage(logMessage) { this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index 804a2112..73a31027 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -1988,6 +1988,21 @@ describe('Activity', () => { }); describe('recover()', () => { + it('returns activity when called without state', () => { + const activity = getActivity(undefined, SignalTaskBehaviour); + expect(activity.recover()).to.equal(activity); + }); + + it('returns activity when called with state', () => { + const activity = getActivity(undefined, SignalTaskBehaviour); + activity.run(); + activity.stop(); + const state = activity.getState(); + + const recovered = getActivity(undefined, SignalTaskBehaviour); + expect(recovered.recover(state)).to.equal(recovered); + }); + it('recovers stopped activity without state', () => { const activity = getActivity(undefined, SignalTaskBehaviour); activity.run(); diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts new file mode 100644 index 00000000..7a462107 --- /dev/null +++ b/types/interfaces.d.ts @@ -0,0 +1,355 @@ +import { Broker, BrokerState, Consumer, MessageEnvelope, MessageFields, MessageProperties } from 'smqp'; + +export declare interface ElementBroker extends Broker { + get owner(): T; +} + +export declare type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; +}; + +export declare interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; +} + +export declare interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; +} + +export declare interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; +} + +export declare const enum TimerType { + TimeCycle = 'timeCycle', + TimeDuration = 'timeDuration', + TimeDate = 'timeDate', +} + +export declare type parsedTimer = { + /** Expires at date time */ + expireAt?: Date; + /** Repeat number of times */ + repeat?: number; + /** Delay in milliseconds */ + delay?: number; +}; + +export declare interface ICondition { + /** Condition type */ + get type(): string; + [x: string]: any; + execute(message: ElementBrokerMessage, callback: CallableFunction): void; +} + +export declare interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; +} + +export declare interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; +} + +export declare type Extension = (activity: any, context: any) => IExtension; +export declare interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; +} + +export declare interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; +} + +export declare interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; +} + +export declare interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; +} + +export declare type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; +}; + +export declare type filterPostponed = (elementApi: any) => boolean; + +export declare const enum DefinitionRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + End = 'end', + Discarded = 'discarded', +} + +export declare const enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', +} + +/** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ +export declare const enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', +} + +/** + * Activity run status + */ +export declare const enum ActivityRunStatus { + /** Run entered, triggered by taken inbound flow */ + Entered = 'entered', + /** Run started */ + Started = 'started', + /** Executing activity behaviour */ + Executing = 'executing', + /** Activity behaviour execution completed successfully */ + Executed = 'executed', + /** Run end, take outbound flows */ + End = 'end', + /** Entering discard run, triggered by discarded inbound flow */ + Discard = 'discard', + /** Run was discarded, discard outbound flows */ + Discarded = 'discarded', + /** Activity behaviour execution failed, discard run */ + Error = 'error', + /** Formatting next run message */ + Formatting = 'formatting', +} + +export declare interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; +} + +export declare interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; +} + +export declare type completedCounters = { completed: number; discarded: number }; + +export declare interface ActivityExecutionState { + completed: boolean; + [x: string]: any; +} + +export declare interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; +} + +export declare interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; +} + +export declare interface MessageFlowState extends ElementState { + counters: { messages: number }; +} + +export declare interface AssociationState extends ElementState { + counters: { take: number; discard: number }; +} + +export declare interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; +} + +export declare interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; +} + +export declare interface DefinitionExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + processes: ProcessState[]; +} + +export declare interface DefinitionState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: DefinitionExecutionState; +} + +export declare type runCallback = (err: Error, definitionApi: any) => void; + +export declare interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; +} + +export declare type LoggerFactory = (scope: string) => ILogger; + +export declare interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; +} + +export declare type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; +export declare type wrappedClearTimeout = (ref: any) => void; + +export declare interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; +} + +export declare interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; +} + +export declare interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; +} + +export declare interface TimersOptions { + /** Defaults to builtin setTimeout */ + setTimeout?: typeof setTimeout; + /** Defaults to builtin clearTimeout */ + clearTimeout?: typeof clearTimeout; + [x: string]: any; +} + +export declare interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; +} + +export declare interface Script { + execute(executionContext: any, callback: CallableFunction): void; +} + +/** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ + +export { Consumer, MessageFields, MessageProperties }; diff --git a/types/types.d.ts b/types/types.d.ts index 3dd12495..f74e217c 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1,42 +1,56 @@ import { Broker } from 'smqp'; -import { BrokerState } from 'smqp/types/Broker'; -import { Consumer } from 'smqp/types/Queue'; -import { MessageMessage, MessageFields, MessageProperties } from 'smqp/types/Message'; import { SerializableContext, SerializableElement } from 'moddle-context-serializer'; -declare interface ElementBroker extends Broker { - get owner(): T; -} - -declare type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; -}; - -declare interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; -} - -declare interface ElementBrokerMessage extends MessageMessage { - content: ElementMessageContent; -} - -declare class EventDefinition { +import { + ElementBroker, + ElementBrokerMessage, + ElementMessageContent, + ElementParent, + ElementState, + ActivityState, + ActivityExecutionState, + IActivityBehaviour, + IExtension, + IExpressions, + IScripts, + ITimers, + ILogger, + ICondition, + ISequenceFlowCondition, + ActivityRunStatus, + ActivityStatus, + DefinitionRunStatus, + ProcessRunStatus, + TimerType, + parsedTimer, + EnvironmentSettings, + EnvironmentOptions, + EnvironmentState, + startActivityFilterOptions, + filterPostponed, + runCallback, + completedCounters, + signalMessage, + ProcessExecutionState, + ProcessState, + DefinitionExecutionState, + DefinitionState, + SequenceFlowState, + MessageFlowState, + AssociationState, + MessageFlowReference, + LoggerFactory, + Timer, + RegisteredTimer, + TimersOptions, + Script, + wrappedSetTimeout, + wrappedClearTimeout, +} from './interfaces.js'; + +export * from './interfaces.js'; + +export declare class EventDefinition { constructor(activity: Activity, eventDefinitionElement: SerializableElement, context?: ContextInstance, index?: number); get id(): string; get type(): string; @@ -54,22 +68,7 @@ declare class EventDefinition { execute(executeMessage: ElementBrokerMessage): void; } -declare const enum TimerType { - TimeCycle = 'timeCycle', - TimeDuration = 'timeDuration', - TimeDate = 'timeDate', -} - -type parsedTimer = { - /** Expires at date time */ - expireAt?: Date; - /** Repeat number of times */ - repeat?: number; - /** Delay in milliseconds */ - delay?: number; -}; - -declare class TimerEventDefinition extends EventDefinition { +export declare class TimerEventDefinition extends EventDefinition { /** * Parse timer type * @param timerType type of timer @@ -78,14 +77,7 @@ declare class TimerEventDefinition extends EventDefinition { parse(timerType: TimerType, timerValue: string): parsedTimer; } -declare interface ICondition { - /** Condition type */ - get type(): string; - [x: string]: any; - execute(message: ElementBrokerMessage, callback: CallableFunction): void; -} - -declare class ConditionalEventDefinition extends EventDefinition { +export declare class ConditionalEventDefinition extends EventDefinition { /** * Evaluate condition * @param message @@ -105,7 +97,7 @@ declare class ConditionalEventDefinition extends EventDefinition { getCondition(index: number): ICondition | null; } -declare abstract class ElementBase { +export declare abstract class ElementBase { get id(): string; get type(): string; get name(): string; @@ -117,145 +109,17 @@ declare abstract class ElementBase { get logger(): ILogger; } -declare abstract class Element extends ElementBase { +export declare abstract class Element extends ElementBase { get broker(): ElementBroker; stop(): void; resume(): void; getApi(message?: ElementBrokerMessage): Api; - on(eventName: string, callback: CallableFunction, options?: any): Consumer; - once(eventName: string, callback: CallableFunction, options?: any): Consumer; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; waitFor(eventName: string, options?: any): Promise>; } -declare interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; -} - -declare type Extension = (activity: ElementBase, context: ContextInstance) => IExtension; -declare interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; -} - -declare interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; -} - -declare interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; -} - -declare interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; -} - -declare type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; -}; - -type filterPostponed = (elementApi: Api) => boolean; - -declare const enum DefinitionRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - End = 'end', - Discarded = 'discarded', -} - -declare const enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', -} - -/** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ -declare const enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', - /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc - */ - Wait = 'wait', -} - -/** - * Activity run status - */ -declare const enum ActivityRunStatus { - /** Run entered, triggered by taken inbound flow */ - Entered = 'entered', - /** Run started */ - Started = 'started', - /** Executing activity behaviour */ - Executing = 'executing', - /** Activity behaviour execution completed successfully */ - Executed = 'executed', - /** Run end, take outbound flows */ - End = 'end', - /** Entering discard run, triggered by discarded inbound flow */ - Discard = 'discard', - /** Run was discarded, discard outbound flows */ - Discarded = 'discarded', - /** Activity behaviour execution failed, discard run */ - Error = 'error', - /** Formatting next run message */ - Formatting = 'formatting', -} - -declare interface DefinitionExecution { +export declare interface DefinitionExecution { get id(): string; get type(): string; get broker(): Broker; @@ -279,25 +143,16 @@ declare interface DefinitionExecution { getPostponed(filterFn?: filterPostponed): Api[]; } -declare interface ActivityExecution { +export declare interface ActivityExecution { get completed(): boolean; get executionId(): string; get source(): IActivityBehaviour; execute(executeMessage: ElementBrokerMessage): void; } -declare interface IActivityBehaviour { - id: string; - type: string; - activity: Activity; - environment: Environment; - new (activity: Activity, context: ContextInstance): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; -} - -declare function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; +export declare function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; -declare interface Api extends ElementBrokerMessage { +export declare interface Api extends ElementBrokerMessage { get id(): string; get type(): string; get name(): string; @@ -323,11 +178,11 @@ interface ExecutionScope { /** Calling element type */ type: string; /** Execution message fields */ - fields: MessageFields; + fields: any; /** Execution message content */ content: ElementMessageContent; /** Execution message properties */ - properties: MessageProperties; + properties: any; environment: Environment; /** Calling element logger instance */ logger?: ILogger; @@ -340,11 +195,7 @@ interface ExecutionScope { ActivityError: ActivityError; } -declare interface Script { - execute(executionContext: ExecutionScope, callback: CallableFunction): void; -} - -declare abstract class MessageElement { +export declare abstract class MessageElement { get id(): string; get type(): string; get name(): string; @@ -358,7 +209,7 @@ declare abstract class MessageElement { }; } -declare class Environment { +export declare class Environment { constructor(options?: EnvironmentOptions); options: Record; expressions: IExpressions; @@ -383,8 +234,8 @@ declare class Environment { addService(name: string, fn: CallableFunction): void; } -declare function Context(definitionContext: SerializableContext, environment?: Environment): ContextInstance; -declare class ContextInstance { +export declare function Context(definitionContext: SerializableContext, environment?: Environment): ContextInstance; +export declare class ContextInstance { constructor(definitionContext: SerializableContext, environment?: Environment); get id(): string; get name(): string; @@ -416,85 +267,7 @@ declare class ContextInstance { loadExtensions(activity: ElementBase): IExtension; } -declare interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; -} - -declare interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; -} - -declare type completedCounters = { completed: number; discarded: number }; - -declare interface ActivityExecutionState { - completed: boolean; - [x: string]: any; -} - -declare interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; -} - -declare interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; -} - -declare interface MessageFlowState extends ElementState { - counters: { messages: number }; -} - -declare interface AssociationState extends ElementState { - counters: { take: number; discard: number }; -} - -declare interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; -} - -declare interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; -} - -declare interface DefinitionExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - processes: ProcessState[]; -} - -declare interface DefinitionState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: DefinitionExecutionState; -} - -declare type runCallback = (err: Error, definitionApi: Api) => void; -declare class Definition extends Element { +export declare class Definition extends Element { constructor(context: ContextInstance, options?: EnvironmentOptions); get counters(): completedCounters; get execution(): DefinitionExecution; @@ -526,7 +299,7 @@ declare class Definition extends Element { sendMessage(message: any): void; } -declare class Process extends Element { +export declare class Process extends Element { constructor(processDef: SerializableElement, context: ContextInstance); get isExecutable(): boolean; get counters(): completedCounters; @@ -554,7 +327,7 @@ declare class Process extends Element { getPostponed(filterFn: filterPostponed): Api[]; } -declare interface ProcessExecution { +export declare interface ProcessExecution { get isSubProcess(): boolean; get broker(): Broker; get environment(): Environment; @@ -574,25 +347,14 @@ declare interface ProcessExecution { getApi(message?: ElementBrokerMessage): Api; } -declare class Lane extends ElementBase { +export declare class Lane extends ElementBase { constructor(process: Process, laneDefinition: SerializableElement); /** Process broker */ get broker(): Broker; get process(): Process; } -declare interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; -} - -declare class SequenceFlow extends Element { +export declare class SequenceFlow extends Element { constructor(flowDef: SerializableElement, context: ContextInstance); get sourceId(): string; get targetId(): string; @@ -614,13 +376,7 @@ declare class SequenceFlow extends Element { getState(): SequenceFlowState | undefined; } -declare interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; -} - -declare class MessageFlow extends Element { +export declare class MessageFlow extends Element { constructor(flowDef: SerializableElement, context: ContextInstance); get source(): MessageFlowReference; get target(): MessageFlowReference; @@ -630,7 +386,7 @@ declare class MessageFlow extends Element { getState(): MessageFlowState | undefined; } -declare class Association extends Element { +export declare class Association extends Element { constructor(associationDef: SerializableElement, context: ContextInstance); get sourceId(): string; get targetId(): string; @@ -641,56 +397,7 @@ declare class Association extends Element { getState(): AssociationState | undefined; } -declare type LoggerFactory = (scope: string) => ILogger; - -declare interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; -} - -declare type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; -declare type wrappedClearTimeout = (ref: any) => void; - -declare interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; -} - -declare interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; -} - -declare interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; -} - -declare interface TimersOptions { - /** Defaults to builtin setTimeout */ - setTimeout?: typeof setTimeout; - /** Defaults to builtin clearTimeout */ - clearTimeout?: typeof clearTimeout; - [x: string]: any; -} - -declare class Timers implements ITimers { +export declare class Timers implements ITimers { options: TimersOptions; constructor(options?: TimersOptions); get executing(): Timer[]; @@ -699,19 +406,14 @@ declare class Timers implements ITimers { register(owner?: any): RegisteredTimer; } -declare interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; -} - -declare class MessageFormatter { +export declare class MessageFormatter { id: string; broker: Broker; logger: ILogger; format(message: MessageElement, callback: CallableFunction): void; } -declare class Activity extends Element { +export declare class Activity extends Element { constructor(behaviour: IActivityBehaviour, activityDef: SerializableElement, context: ContextInstance); get Behaviour(): IActivityBehaviour; get stopped(): boolean; @@ -752,7 +454,7 @@ declare class Activity extends Element { getState(): ActivityState | undefined; } -declare class ActivityError extends Error { +export declare class ActivityError extends Error { type: string; description: string; /** Activity that threw error */ @@ -760,12 +462,5 @@ declare class ActivityError extends Error { /** Original error */ inner?: Error; code?: string; - constructor(description: string, sourceMessage: MessageMessage, inner?: Error); + constructor(description: string, sourceMessage: any, inner?: Error); } - -/** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ From bb76a3fe3f896e8b7f324f40ea4cc4a5fdbadcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 10 May 2026 11:39:53 +0200 Subject: [PATCH 11/31] gather constants --- .prettierignore | 2 + CHANGELOG.md | 3 +- dist/Api.js | 83 + dist/Context.js | 154 +- dist/Environment.js | 96 +- dist/EventBroker.js | 66 + dist/MessageFormatter.js | 47 +- dist/Timers.js | 21 +- dist/activity/Activity.js | 341 +- dist/activity/ActivityExecution.js | 151 +- dist/constants.js | 21 + dist/definition/Definition.js | 244 +- dist/definition/DefinitionExecution.js | 306 +- .../eventDefinitions/CancelEventDefinition.js | 21 +- .../CompensateEventDefinition.js | 65 +- .../ConditionalEventDefinition.js | 13 +- dist/eventDefinitions/ErrorEventDefinition.js | 57 +- .../EscalationEventDefinition.js | 44 +- .../EventDefinitionExecution.js | 33 +- dist/eventDefinitions/LinkEventDefinition.js | 7 +- .../MessageEventDefinition.js | 50 +- .../eventDefinitions/SignalEventDefinition.js | 52 +- dist/eventDefinitions/TimerEventDefinition.js | 48 +- dist/events/BoundaryEvent.js | 61 +- dist/events/EndEvent.js | 7 +- dist/events/IntermediateCatchEvent.js | 7 +- dist/events/IntermediateThrowEvent.js | 7 +- dist/events/StartEvent.js | 19 +- dist/flows/Association.js | 55 +- dist/flows/MessageFlow.js | 59 +- dist/flows/SequenceFlow.js | 80 +- dist/gateways/EventBasedGateway.js | 26 +- dist/gateways/ParallelGateway.js | 28 +- dist/io/InputOutputSpecification.js | 9 +- dist/io/Properties.js | 20 +- dist/process/Lane.js | 16 +- dist/process/Process.js | 255 +- dist/process/ProcessExecution.js | 363 +- dist/tasks/ReceiveTask.js | 36 +- dist/tasks/SubProcess.js | 31 +- package.json | 16 +- scripts/build-types.js | 27 + src/Context.js | 29 +- src/Environment.js | 36 +- src/MessageFormatter.js | 27 +- src/Timers.js | 21 +- src/activity/Activity.js | 256 +- src/activity/ActivityExecution.js | 80 +- src/constants.js | 15 + src/definition/Definition.js | 128 +- src/definition/DefinitionExecution.js | 184 +- src/eventDefinitions/CancelEventDefinition.js | 22 +- .../CompensateEventDefinition.js | 63 +- .../ConditionalEventDefinition.js | 14 +- src/eventDefinitions/ErrorEventDefinition.js | 57 +- .../EscalationEventDefinition.js | 44 +- .../EventDefinitionExecution.js | 33 +- src/eventDefinitions/LinkEventDefinition.js | 8 +- .../MessageEventDefinition.js | 51 +- src/eventDefinitions/SignalEventDefinition.js | 53 +- src/eventDefinitions/TimerEventDefinition.js | 47 +- src/events/BoundaryEvent.js | 60 +- src/events/EndEvent.js | 8 +- src/events/IntermediateCatchEvent.js | 8 +- src/events/IntermediateThrowEvent.js | 8 +- src/events/StartEvent.js | 20 +- src/flows/Association.js | 49 +- src/flows/MessageFlow.js | 49 +- src/flows/SequenceFlow.js | 70 +- src/gateways/EventBasedGateway.js | 26 +- src/gateways/ParallelGateway.js | 28 +- src/io/InputOutputSpecification.js | 10 +- src/io/Properties.js | 19 +- src/process/Lane.js | 14 +- src/process/Process.js | 151 +- src/process/ProcessExecution.js | 229 +- src/tasks/ReceiveTask.js | 35 +- src/tasks/SubProcess.js | 30 +- test/bpmn-elements-test.js | 2 +- test/feature/BoundaryEvent-feature.js | 2 +- test/feature/issues/engine-issues-feature.js | 2 +- test/feature/issues/issue-31-feature.js | 2 +- test/feature/issues/issue-32-feature.js | 2 +- test/feature/issues/issue-39-feature.js | 2 +- test/feature/issues/issue-42-feature.js | 2 +- test/feature/issues/stack-overflow-feature.js | 2 +- test/feature/shake-feature.js | 4 +- test/feature/signal-feature.js | 6 +- test/feature/stop-and-resume-feature.js | 1 + test/feature/swim-lanes-feature.js | 2 +- test/helpers/testHelpers.js | 2 +- test/io/InputOutputSpecification-test.js | 8 +- test/process/Process-test.js | 4 +- test/tasks/UserTask-test.js | 5 +- tsconfig.json | 14 +- tsconfig.tests.json | 10 + types/augmentations.d.ts | 90 + types/index.d.ts | 6817 ++++++++++++++++- types/index.d.ts.map | 267 + types/types.d.ts | 44 +- 100 files changed, 10530 insertions(+), 1789 deletions(-) create mode 100644 dist/constants.js mode change 100755 => 100644 dist/tasks/ReceiveTask.js create mode 100644 scripts/build-types.js create mode 100644 src/constants.js mode change 100755 => 100644 src/tasks/ReceiveTask.js create mode 100644 tsconfig.tests.json create mode 100644 types/augmentations.d.ts create mode 100644 types/index.d.ts.map diff --git a/.prettierignore b/.prettierignore index 287b609e..a0d59bf3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,3 +4,5 @@ coverage/ tmp/ test/resources/*.bpmn *.bpmn +types/index.d.ts +types/index.d.ts.map diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b333459..9c0ddc74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ ### Types -- start migrating runtime types to JSDoc, covering `Activity`, `ActivityExecution`, `Context`, `Process`, `ProcessExecution`, `Definition`, `DefinitionExecution`, `Environment`, `Api`, `EventBroker`, and `MessageFormatter` +- bundle `types/index.d.ts` with [dts-buddy](https://github.com/Rich-Harris/dts-buddy); types are generated from JSDoc and source-mapped to `src/*.js` +- migrate runtime types to JSDoc, covering `Activity`, `ActivityExecution`, `Context`, `Process`, `ProcessExecution`, `Definition`, `DefinitionExecution`, `Environment`, `Api`, `EventBroker`, `MessageFormatter`, `SequenceFlow`, `MessageFlow`, `Association`, and `Lane` - separate hand-written contracts into `types/interfaces.d.ts` - update `smqp` type imports for `smqp@12` diff --git a/dist/Api.js b/dist/Api.js index 47092f8e..5a5ad2fa 100644 --- a/dist/Api.js +++ b/dist/Api.js @@ -10,18 +10,54 @@ exports.FlowApi = FlowApi; exports.ProcessApi = ProcessApi; var _messageHelper = require("./messageHelper.js"); var _shared = require("./shared.js"); +/** + * Build an activity-scoped Api wrapper. Routing keys are published under `activity.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ function ActivityApi(broker, apiMessage, environment) { return new Api('activity', broker, apiMessage, environment); } + +/** + * Build a definition-scoped Api wrapper. Routing keys are published under `definition.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ function DefinitionApi(broker, apiMessage, environment) { return new Api('definition', broker, apiMessage, environment); } + +/** + * Build a process-scoped Api wrapper. Routing keys are published under `process.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ function ProcessApi(broker, apiMessage, environment) { return new Api('process', broker, apiMessage, environment); } + +/** + * Build a flow-scoped Api wrapper. Routing keys are published under `flow.*`. + * @param {any} broker + * @param {import('types').ElementBrokerMessage} apiMessage + * @param {import('types').Environment} [environment] + */ function FlowApi(broker, apiMessage, environment) { return new Api('flow', broker, apiMessage, environment); } + +/** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param {string} pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param {any} broker + * @param {import('types').ElementBrokerMessage} sourceMessage Cloned to back the api + * @param {import('types').Environment} [environment] Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing + */ function Api(pfx, broker, sourceMessage, environment) { if (!sourceMessage) throw new Error('Api requires message'); const apiMessage = (0, _messageHelper.cloneMessage)(sourceMessage); @@ -43,27 +79,57 @@ function Api(pfx, broker, sourceMessage, environment) { this.owner = broker.owner; this.messagePrefix = pfx; } + +/** + * Send a cancel api message. + * @param {import('types').signalMessage} [message] + * @param {any} [options] + */ Api.prototype.cancel = function cancel(message, options) { this.sendApiMessage('cancel', { message }, options); }; + +/** + * Send a discard api message. + */ Api.prototype.discard = function discard() { this.sendApiMessage('discard'); }; + +/** + * Send an error api message that fails the activity. + * @param {Error} error + */ Api.prototype.fail = function fail(error) { this.sendApiMessage('error', { error }); }; + +/** + * Send a signal api message. + * @param {import('types').signalMessage} [message] + * @param {any} [options] + */ Api.prototype.signal = function signal(message, options) { this.sendApiMessage('signal', { message }, options); }; + +/** + * Send a stop api message. + */ Api.prototype.stop = function stop() { this.sendApiMessage('stop'); }; + +/** + * Resolve an expression with the api message as scope and the broker owner as context. + * @param {string} expression + */ Api.prototype.resolveExpression = function resolveExpression(expression) { return this.environment.resolveExpression(expression, { fields: this.fields, @@ -71,6 +137,13 @@ Api.prototype.resolveExpression = function resolveExpression(expression) { properties: this.messageProperties }, this.owner); }; + +/** + * Publish a custom api message to the broker. + * @param {string} action Routing key suffix, e.g. `signal`, `cancel` + * @param {import('types').signalMessage} [content] Merged into the message content + * @param {any} [options] + */ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) { const correlationId = options?.correlationId || (0, _shared.getUniqueId)(`${this.id || this.messagePrefix}_signal`); let key = `${this.messagePrefix}.${action}`; @@ -81,11 +154,21 @@ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) type: action }); }; + +/** + * List currently postponed activities, falling back to a sub-process execution when applicable. + * @param {import('types').filterPostponed} [filterFn] + */ Api.prototype.getPostponed = function getPostponed(...args) { if (this.owner.getPostponed) return this.owner.getPostponed(...args); if (this.owner.isSubProcess && this.owner.execution) return this.owner.execution.getPostponed(...args); return []; }; + +/** + * Build a message body by merging the given content onto the source content. + * @param {Record} [content] + */ Api.prototype.createMessage = function createMessage(content) { return { ...this.content, diff --git a/dist/Context.js b/dist/Context.js index c1fc25c6..72a34db8 100644 --- a/dist/Context.js +++ b/dist/Context.js @@ -7,13 +7,26 @@ exports.default = Context; var _BpmnIO = _interopRequireDefault(require("./io/BpmnIO.js")); var _Environment = _interopRequireDefault(require("./Environment.js")); var _shared = require("./shared.js"); +var _constants = require("./constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kOwner = Symbol.for('owner'); -const kActivated = Symbol.for('activated'); +const K_OWNER = Symbol.for('owner'); + +/** + * Build a runtime Context from a parsed BPMN definition. + * @param {import('moddle-context-serializer').SerializableContext} definitionContext + * @param {import('types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted + */ function Context(definitionContext, environment) { environment = environment ? environment.clone() : new _Environment.default(); return new ContextInstance(definitionContext, environment); } + +/** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param {import('moddle-context-serializer').SerializableContext} definitionContext + * @param {import('types').Environment} environment + * @param {import('types').Process | import('types').Activity} [owner] Process or sub-process activity that owns this context + */ function ContextInstance(definitionContext, environment, owner) { const { id = 'Def', @@ -29,13 +42,20 @@ function ContextInstance(definitionContext, environment, owner) { this.environment = environment; this.extensionsMapper = new ExtensionsMapper(this); this.refs = new Map([['activityRefs', new Map()], ['sequenceFlowRefs', new Map()], ['processRefs', new Map()], ['messageFlows', new Set()], ['associationRefs', new Map()], ['dataObjectRefs', new Map()], ['dataStoreRefs', new Map()]]); - this[kOwner] = owner; + /** @private */ + this[K_OWNER] = owner; } Object.defineProperty(ContextInstance.prototype, 'owner', { + /** @returns {import('types').Process | import('types').Activity | undefined} Process or sub-process activity that owns this context */ get() { - return this[kOwner]; + return this[K_OWNER]; } }); + +/** + * Get or create the activity instance for the given id. + * @param {string} activityId + */ ContextInstance.prototype.getActivityById = function getActivityById(activityId) { const activityInstance = this.refs.get('activityRefs').get(activityId); if (activityInstance) return activityInstance; @@ -43,6 +63,11 @@ ContextInstance.prototype.getActivityById = function getActivityById(activityId) if (!activity) return null; return this.upsertActivity(activity); }; + +/** + * Return the cached activity instance, instantiating it the first time it is referenced. + * @param {import('moddle-context-serializer').SerializableElement} activityDef + */ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) { let activityInstance = this.refs.get('activityRefs').get(activityDef.id); if (activityInstance) return activityInstance; @@ -50,6 +75,11 @@ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) this.refs.get('activityRefs').set(activityDef.id, activityInstance); return activityInstance; }; + +/** + * Get or create the sequence flow instance for the given id. + * @param {string} sequenceFlowId + */ ContextInstance.prototype.getSequenceFlowById = function getSequenceFlowById(sequenceFlowId) { const flowInstance = this.refs.get('sequenceFlowRefs').get(sequenceFlowId); if (flowInstance) return flowInstance; @@ -57,24 +87,55 @@ ContextInstance.prototype.getSequenceFlowById = function getSequenceFlowById(seq if (!flowDef) return null; return this.upsertSequenceFlow(flowDef); }; + +/** + * @param {string} activityId + */ ContextInstance.prototype.getInboundSequenceFlows = function getInboundSequenceFlows(activityId) { return (this.definitionContext.getInboundSequenceFlows(activityId) || []).map(flow => this.upsertSequenceFlow(flow)); }; + +/** + * @param {string} activityId + */ ContextInstance.prototype.getOutboundSequenceFlows = function getOutboundSequenceFlows(activityId) { return (this.definitionContext.getOutboundSequenceFlows(activityId) || []).map(flow => this.upsertSequenceFlow(flow)); }; + +/** + * @param {string} activityId + */ ContextInstance.prototype.getInboundAssociations = function getInboundAssociations(activityId) { return (this.definitionContext.getInboundAssociations(activityId) || []).map(association => this.upsertAssociation(association)); }; + +/** + * @param {string} activityId + */ ContextInstance.prototype.getOutboundAssociations = function getOutboundAssociations(activityId) { return (this.definitionContext.getOutboundAssociations(activityId) || []).map(association => this.upsertAssociation(association)); }; + +/** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getActivities = function getActivities(scopeId) { return (this.definitionContext.getActivities(scopeId) || []).map(activityDef => this.upsertActivity(activityDef)); }; + +/** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getSequenceFlows = function getSequenceFlows(scopeId) { return (this.definitionContext.getSequenceFlows(scopeId) || []).map(flow => this.upsertSequenceFlow(flow)); }; + +/** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * @param {import('moddle-context-serializer').SerializableElement} flowDefinition + */ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowDefinition) { const sequenceFlowRefs = this.refs.get('sequenceFlowRefs'); let flowInstance = sequenceFlowRefs.get(flowDefinition.id); @@ -83,9 +144,17 @@ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowD sequenceFlowRefs.set(flowDefinition.id, flowInstance); return flowInstance; }; + +/** + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getAssociations = function getAssociations(scopeId) { return (this.definitionContext.getAssociations(scopeId) || []).map(association => this.upsertAssociation(association)); }; + +/** + * @param {import('moddle-context-serializer').SerializableElement} associationDefinition + */ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associationDefinition) { const associationRefs = this.refs.get('associationRefs'); let instance = associationRefs.get(associationDefinition.id); @@ -94,9 +163,20 @@ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associa associationRefs.set(associationDefinition.id, instance); return instance; }; + +/** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * @param {import('types').Environment} [newEnvironment] + * @param {import('types').Process | import('types').Activity} [newOwner] + */ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner); }; + +/** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * @param {string} processId + */ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const processRefs = this.refs.get('processRefs'); let bp = processRefs.get(processId); @@ -106,27 +186,45 @@ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const bpContext = this.clone(this.environment.clone()); bp = new processDefinition.Behaviour(processDefinition, bpContext); processRefs.set(processId, bp); - bpContext[kOwner] = bp; + bpContext[K_OWNER] = bp; return bp; }; + +/** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * @param {string} processId + */ ContextInstance.prototype.getNewProcessById = function getNewProcessById(processId) { if (!this.getProcessById(processId)) return null; const bpDef = this.definitionContext.getProcessById(processId); const bpContext = this.clone(this.environment.clone()); const bp = new bpDef.Behaviour(bpDef, bpContext); - bpContext[kOwner] = bp; + bpContext[K_OWNER] = bp; return bp; }; + +/** + * Get every process in the definition. + */ ContextInstance.prototype.getProcesses = function getProcesses() { return this.definitionContext.getProcesses().map(({ id: processId }) => this.getProcessById(processId)); }; + +/** + * Get processes flagged executable in the definition. + */ ContextInstance.prototype.getExecutableProcesses = function getExecutableProcesses() { return this.definitionContext.getExecutableProcesses().map(({ id: processId }) => this.getProcessById(processId)); }; + +/** + * Get message flows that originate from the given process id. + * @param {string} sourceId Source process id + */ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { const messageFlowRefs = this.refs.get('messageFlows'); const result = []; @@ -144,6 +242,11 @@ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { } return result; }; + +/** + * Get or create a data object instance for the given reference id. + * @param {string} referenceId + */ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referenceId) { const dataObjectRefs = this.refs.get('dataObjectRefs'); let dataObject; @@ -154,6 +257,11 @@ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referen dataObjectRefs.set(dataObjectDef.id, dataObject); return dataObject; }; + +/** + * Get or create a data store instance for the given reference id. + * @param {string} referenceId + */ ContextInstance.prototype.getDataStoreById = function getDataStoreById(referenceId) { const dataStoreRefs = this.refs.get('dataStoreRefs'); let dataStore; @@ -164,6 +272,12 @@ ContextInstance.prototype.getDataStoreById = function getDataStoreById(reference dataStoreRefs.set(dataStoreDef.id, dataStore); return dataStore; }; + +/** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param {import('types').startActivityFilterOptions} [filterOptions] + * @param {string} [scopeId] Process or sub-process id + */ ContextInstance.prototype.getStartActivities = function getStartActivities(filterOptions, scopeId) { const referenceId = filterOptions?.referenceId; const referenceType = filterOptions?.referenceType || 'unknown'; @@ -183,6 +297,12 @@ ContextInstance.prototype.getStartActivities = function getStartActivities(filte } return result; }; + +/** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * @param {import('types').ElementBase} activity + */ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { const io = new _BpmnIO.default(activity, this); const extensions = this.extensionsMapper.get(activity); @@ -190,8 +310,13 @@ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { if (!extensions.extensions.length) return; return extensions; }; + +/** + * Resolve the parent process or sub-process activity that owns the given activity. + * @param {string} activityId + */ ContextInstance.prototype.getActivityParentById = function getActivityParentById(activityId) { - const owner = this[kOwner]; + const owner = this[K_OWNER]; if (owner) return owner; const activity = this.getActivityById(activityId); const parentId = activity.parent.id; @@ -203,6 +328,8 @@ function ExtensionsMapper(context) { ExtensionsMapper.prototype.get = function get(activity) { return new Extensions(activity, this.context, this._getExtensions()); }; + +/** @internal */ ExtensionsMapper.prototype._getExtensions = function getExtensions() { let extensions; if (!(extensions = this.context.environment.extensions)) return []; @@ -214,7 +341,8 @@ function Extensions(activity, context, extensions) { const extension = Extension(activity, context); if (extension) result.push(extension); } - this[kActivated] = false; + /** @private */ + this[_constants.K_ACTIVATED] = false; } Object.defineProperty(Extensions.prototype, 'count', { get() { @@ -222,12 +350,14 @@ Object.defineProperty(Extensions.prototype, 'count', { } }); Extensions.prototype.activate = function activate(message) { - if (this[kActivated]) return; - this[kActivated] = true; + if (this[_constants.K_ACTIVATED]) return; + /** @private */ + this[_constants.K_ACTIVATED] = true; for (const extension of this.extensions) extension.activate(message); }; Extensions.prototype.deactivate = function deactivate(message) { - if (!this[kActivated]) return; - this[kActivated] = false; + if (!this[_constants.K_ACTIVATED]) return; + /** @private */ + this[_constants.K_ACTIVATED] = false; for (const extension of this.extensions) extension.deactivate(message); }; \ No newline at end of file diff --git a/dist/Environment.js b/dist/Environment.js index fb87034a..89431e30 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -8,9 +8,15 @@ var _Expressions = _interopRequireDefault(require("./Expressions.js")); var _Scripts = require("./Scripts.js"); var _Timers = require("./Timers.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kServices = Symbol.for('services'); -const kVariables = Symbol.for('variables'); +const K_SERVICES = Symbol.for('services'); +const K_VARIABLES = Symbol.for('variables'); const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', 'scripts', 'services', 'settings', 'timers', 'variables']); + +/** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * @param {import('types').EnvironmentOptions} [options] + */ function Environment(options = {}) { this.options = validateOptions(options); this.expressions = options.expressions || (0, _Expressions.default)(); @@ -23,21 +29,23 @@ function Environment(options = {}) { ...options.settings }; this.Logger = options.Logger || DummyLogger; - this[kServices] = options.services || {}; - this[kVariables] = options.variables || {}; + /** @private */ + this[K_SERVICES] = options.services || {}; + /** @private */ + this[K_VARIABLES] = options.variables || {}; } Object.defineProperties(Environment.prototype, { variables: { get() { - return this[kVariables]; + return this[K_VARIABLES]; } }, services: { get() { - return this[kServices]; + return this[K_SERVICES]; }, set(value) { - const services = this[kServices]; + const services = this[K_SERVICES]; for (const name in services) { if (!(name in value)) delete services[name]; } @@ -45,34 +53,51 @@ Object.defineProperties(Environment.prototype, { } } }); + +/** + * Snapshot environment state for recover. + */ Environment.prototype.getState = function getState() { return { settings: { ...this.settings }, variables: { - ...this[kVariables] + ...this[K_VARIABLES] }, output: { ...this.output } }; }; + +/** + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. + * @param {import('types').EnvironmentState} [state] + * @returns {this} + */ Environment.prototype.recover = function recover(state) { if (!state) return this; if (state.settings) Object.assign(this.settings, state.settings); - if (state.variables) Object.assign(this[kVariables], state.variables); + if (state.variables) Object.assign(this[K_VARIABLES], state.variables); if (state.output) Object.assign(this.output, state.output); return this; }; + +/** + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. + * @param {import('types').EnvironmentOptions} [overrideOptions] + */ Environment.prototype.clone = function clone(overrideOptions) { - const services = this[kServices]; + const services = this[K_SERVICES]; const newOptions = { settings: { ...this.settings }, variables: { - ...this[kVariables] + ...this[K_VARIABLES] }, Logger: this.Logger, extensions: this.extensions, @@ -89,13 +114,26 @@ Environment.prototype.clone = function clone(overrideOptions) { }; return new this.constructor(newOptions); }; + +/** + * Merge variables into the environment. Non-objects are ignored. + * @param {Record} newVars + */ Environment.prototype.assignVariables = function assignVariables(newVars) { if (!newVars || typeof newVars !== 'object') return; - this[kVariables] = { + + /** @private */ + this[K_VARIABLES] = { ...this.variables, ...newVars }; }; + +/** + * Merge settings into the environment. Non-objects are ignored. + * @param {import('types').EnvironmentSettings} newSettings + * @returns {this} + */ Environment.prototype.assignSettings = function assignSettings(newSettings) { if (!newSettings || typeof newSettings !== 'object') return this; this.settings = { @@ -104,15 +142,38 @@ Environment.prototype.assignSettings = function assignSettings(newSettings) { }; return this; }; + +/** + * Resolve a registered script by language and identifier. + * @param {string} language + * @param {{ id: string, [x: string]: any }} identifier + */ Environment.prototype.getScript = function getScript(...args) { return this.scripts.getScript(...args); }; + +/** + * Register a script for an activity, delegating to the configured scripts engine. + * @param {any} activity + */ Environment.prototype.registerScript = function registerScript(...args) { return this.scripts.register(...args); }; + +/** + * Lookup a registered service by name. + * @param {string} serviceName + */ Environment.prototype.getServiceByName = function getServiceByName(serviceName) { - return this[kServices][serviceName]; + return this[K_SERVICES][serviceName]; }; + +/** + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param {string} expression + * @param {import('types').ElementBrokerMessage} [message] Element message merged onto the resolution scope + * @param {any} [expressionFnContext] + */ Environment.prototype.resolveExpression = function resolveExpression(expression, message, expressionFnContext) { const from = { environment: this, @@ -120,8 +181,15 @@ Environment.prototype.resolveExpression = function resolveExpression(expression, }; return this.expressions.resolveExpression(expression, from, expressionFnContext); }; + +/** + * Register a service callable by name. + * @param {string} name + * @param {CallableFunction} fn + */ Environment.prototype.addService = function addService(name, fn) { - this[kServices][name] = fn; + /** @private */ + this[K_SERVICES][name] = fn; }; function validateOptions(input) { const options = {}; diff --git a/dist/EventBroker.js b/dist/EventBroker.js index db924c1d..2d29f5de 100644 --- a/dist/EventBroker.js +++ b/dist/EventBroker.js @@ -10,10 +10,19 @@ exports.MessageFlowBroker = MessageFlowBroker; exports.ProcessBroker = ProcessBroker; var _smqp = require("smqp"); var _Errors = require("./error/Errors.js"); +/** + * Build the broker for an activity, including run/format/execution/api exchanges and queues. + * @param {import('types').Activity} activity + */ function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); return executionBroker; } + +/** + * Build the broker for a process, with an additional api-q bound to all api routing keys. + * @param {import('types').Process} owner + */ function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); executionBroker.broker.assertQueue('api-q', { @@ -23,9 +32,20 @@ function ProcessBroker(owner) { executionBroker.broker.bindQueue('api-q', 'api', '#'); return executionBroker; } + +/** + * Build the broker for a definition. Optionally registers a custom return-message handler. + * @param {import('types').Definition} owner + * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] + */ function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); } + +/** + * Build the broker for a message flow with a durable message exchange and message-q. + * @param {import('types').MessageFlow} owner + */ function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { prefix: 'messageflow', @@ -85,6 +105,13 @@ function ExecutionBroker(brokerOwner, prefix, onBrokerReturn) { broker.bindQueue(executionQ.name, 'execution', 'execution.#'); return eventBroker; } + +/** + * Owns an smqp Broker on behalf of the calling element and exposes prefixed event helpers. + * @param {any} brokerOwner Element that owns the broker, accessed as `broker.owner` + * @param {{ prefix: string, autoDelete?: boolean, durable?: boolean }} options + * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] Override for unrouted return messages + */ function EventBroker(brokerOwner, options, onBrokerReturn) { this.options = options; this.eventPrefix = options.prefix; @@ -97,6 +124,14 @@ function EventBroker(brokerOwner, options, onBrokerReturn) { this.emit = this.emit.bind(this); this.emitFatal = this.emitFatal.bind(this); } + +/** + * Subscribe to a prefixed event. Errors are unwrapped via `makeErrorFromMessage`, + * other events resolve to the owner's Api wrapper. + * @param {string} eventName Bare name (e.g. `enter`) or a full routing key + * @param {CallableFunction} callback + * @param {{ once?: boolean, [x: string]: any }} [eventOptions] + */ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { once: false }) { @@ -111,12 +146,26 @@ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { callback(owner.getApi(message)); } }; + +/** + * Subscribe to the next occurrence of an event. + * @param {string} eventName + * @param {CallableFunction} callback + * @param {any} [eventOptions] + */ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { return this.on(eventName, callback, { ...eventOptions, once: true }); }; + +/** + * Promise-style wait for an event. Rejects on a mandatory `*.error` message. + * @param {string} eventName + * @param {(routingKey: string, message: import('types').ElementBrokerMessage, owner: any) => boolean | undefined} [onMessage] + * Filter; the promise only resolves when it returns truthy + */ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { const key = this._getEventRoutingKey(eventName); return new Promise((resolve, reject) => { @@ -142,6 +191,13 @@ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { } }); }; + +/** + * Publish a prefixed event message. + * @param {string} eventName + * @param {Record} [content] + * @param {any} [props] + */ EventBroker.prototype.emit = function emit(eventName, content, props) { this.broker.publish('event', `${this.eventPrefix}.${eventName}`, { ...content @@ -150,6 +206,12 @@ EventBroker.prototype.emit = function emit(eventName, content, props) { ...props }); }; + +/** + * Emit a mandatory error event. Surfaces via `on('error', ...)` or causes a return message to throw. + * @param {Error} error + * @param {Record} [content] + */ EventBroker.prototype.emitFatal = function emitFatal(error, content) { this.emit('error', { ...content, @@ -158,12 +220,16 @@ EventBroker.prototype.emitFatal = function emitFatal(error, content) { mandatory: true }); }; + +/** @internal */ EventBroker.prototype._onBrokerReturnFn = function onBrokerReturnFn(message) { if (message.properties.type === 'error') { const err = (0, _Errors.makeErrorFromMessage)(message); throw err; } }; + +/** @internal */ EventBroker.prototype._getEventRoutingKey = function getEventRoutingKey(eventName) { if (eventName.indexOf('.') > -1) return eventName; switch (eventName) { diff --git a/dist/MessageFormatter.js b/dist/MessageFormatter.js index f98dbba9..0776413a 100644 --- a/dist/MessageFormatter.js +++ b/dist/MessageFormatter.js @@ -8,12 +8,14 @@ var _messageHelper = require("./messageHelper.js"); var _shared = require("./shared.js"); var _Errors = require("./error/Errors.js"); var _smqp = require("smqp"); -const kOnMessage = Symbol.for('onMessage'); -const kExecution = Symbol.for('execution'); +var _constants = require("./constants.js"); +const K_ON_MESSAGE = Symbol.for('onMessage'); const EXEC_ROUTING_KEY = 'run._formatting.exec'; /** - * Message formatter used to enrich an element run message before continuing to the next run message + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. * @param {import('types').ElementBase} element */ function Formatter(element) { @@ -25,13 +27,15 @@ function Formatter(element) { this.id = id; this.broker = broker; this.logger = logger; - this[kOnMessage] = this._onMessage.bind(this); + /** @private */ + this[K_ON_MESSAGE] = this._onMessage.bind(this); } /** - * Format message + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. * @param {import('types').ElementBrokerMessage} message - * @param {CallableFunction} callback + * @param {(err: Error | null, content?: import('types').ElementMessageContent, formatted?: boolean) => void} callback */ Formatter.prototype.format = function format(message, callback) { const correlationId = this._runId = (0, _shared.getUniqueId)(message.fields.routingKey); @@ -41,7 +45,9 @@ Formatter.prototype.format = function format(message, callback) { correlationId, persistent: false }); - this[kExecution] = { + + /** @private */ + this[_constants.K_EXECUTION] = { correlationId, formatKey: message.fields.routingKey, runMessage: (0, _messageHelper.cloneMessage)(message), @@ -50,18 +56,20 @@ Formatter.prototype.format = function format(message, callback) { formatted: false, executeMessage: null }; - broker.consume('format-run-q', this[kOnMessage], { + broker.consume('format-run-q', this[K_ON_MESSAGE], { consumerTag, prefetch: 100 }); }; + +/** @internal */ Formatter.prototype._onMessage = function onMessage(routingKey, message) { const { formatKey, correlationId, pending, executeMessage - } = this[kExecution]; + } = this[_constants.K_EXECUTION]; const asyncFormatting = pending.size; if (routingKey === EXEC_ROUTING_KEY) { if (message.properties.correlationId !== correlationId) return message.ack(); @@ -69,7 +77,8 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { if (!asyncFormatting) { return this._complete(message); } - this[kExecution].executeMessage = message; + /** @private */ + this[_constants.K_EXECUTION].executeMessage = message; } else { message.ack(); const endRoutingKey = message.content?.endRoutingKey; @@ -91,6 +100,8 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { } } }; + +/** @internal */ Formatter.prototype._complete = function complete(message, isError) { const { runMessage, @@ -98,8 +109,9 @@ Formatter.prototype._complete = function complete(message, isError) { callback, formatted, executeMessage - } = this[kExecution]; - this[kExecution] = null; + } = this[_constants.K_EXECUTION]; + /** @private */ + this[_constants.K_EXECUTION] = null; if (executeMessage) executeMessage.ack(); this.broker.cancel(message.fields.consumerTag); if (isError) { @@ -110,8 +122,10 @@ Formatter.prototype._complete = function complete(message, isError) { } return callback(null, runMessage.content, formatted); }; + +/** @internal */ Formatter.prototype._enrich = function enrich(withContent) { - const content = this[kExecution].runMessage.content; + const content = this[_constants.K_EXECUTION].runMessage.content; for (const key in withContent) { switch (key) { case 'id': @@ -129,11 +143,14 @@ Formatter.prototype._enrich = function enrich(withContent) { default: { content[key] = withContent[key]; - this[kExecution].formatted = true; + /** @private */ + this[_constants.K_EXECUTION].formatted = true; } } } }; + +/** @internal */ Formatter.prototype._popFormatStart = function popFormattingStart(pending, routingKey) { for (const msg of pending) { const { @@ -156,6 +173,8 @@ Formatter.prototype._popFormatStart = function popFormattingStart(pending, routi } return {}; }; + +/** @internal */ Formatter.prototype._debug = function debug(msg) { this.logger.debug(`<${this.id}> ${msg}`); }; \ No newline at end of file diff --git a/dist/Timers.js b/dist/Timers.js index 1594a47a..aaab99a6 100644 --- a/dist/Timers.js +++ b/dist/Timers.js @@ -4,8 +4,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Timers = Timers; -const kExecuting = Symbol.for('executing'); -const kTimerApi = Symbol.for('timers api'); +const K_EXECUTING = Symbol.for('executing'); +const K_TIMER_API = Symbol.for('timers api'); const MAX_DELAY = 2147483647; function Timers(options) { this.count = 0; @@ -14,13 +14,14 @@ function Timers(options) { clearTimeout, ...options }; - this[kExecuting] = new Set(); + /** @private */ + this[K_EXECUTING] = new Set(); this.setTimeout = this.setTimeout.bind(this); this.clearTimeout = this.clearTimeout.bind(this); } Object.defineProperty(Timers.prototype, 'executing', { get() { - return [...this[kExecuting]]; + return [...this[K_EXECUTING]]; } }); Timers.prototype.register = function register(owner) { @@ -30,14 +31,14 @@ Timers.prototype.setTimeout = function wrappedSetTimeout(callback, delay, ...arg return this._setTimeout(null, callback, delay, ...args); }; Timers.prototype.clearTimeout = function wrappedClearTimeout(ref) { - if (this[kExecuting].delete(ref)) { + if (this[K_EXECUTING].delete(ref)) { ref.timerRef = this.options.clearTimeout(ref.timerRef); return; } return this.options.clearTimeout(ref); }; Timers.prototype._setTimeout = function setTimeout(owner, callback, delay, ...args) { - const executing = this[kExecuting]; + const executing = this[K_EXECUTING]; const ref = this._getReference(owner, callback, delay, args); executing.add(ref); if (delay < MAX_DELAY) { @@ -53,17 +54,19 @@ Timers.prototype._getReference = function getReference(owner, callback, delay, a return new Timer(owner, `timer_${this.count++}`, callback, delay, args); }; function RegisteredTimers(timersApi, owner) { - this[kTimerApi] = timersApi; + /** @private */ + this[K_TIMER_API] = timersApi; this.owner = owner; this.setTimeout = this.setTimeout.bind(this); this.clearTimeout = this.clearTimeout.bind(this); } RegisteredTimers.prototype.setTimeout = function registeredSetTimeout(callback, delay, ...args) { - const timersApi = this[kTimerApi]; + const timersApi = this[K_TIMER_API]; return timersApi._setTimeout(this.owner, callback, delay, ...args); }; RegisteredTimers.prototype.clearTimeout = function registeredClearTimeout(ref) { - this[kTimerApi].clearTimeout(ref); + /** @private */ + this[K_TIMER_API].clearTimeout(ref); }; function Timer(owner, timerId, callback, delay, args) { this.callback = callback; diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index d93e95b1..28868cbb 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.Activity = Activity; exports.default = void 0; var _ActivityExecution = _interopRequireDefault(require("./ActivityExecution.js")); var _shared = require("../shared.js"); @@ -12,21 +13,15 @@ var _MessageFormatter = require("../MessageFormatter.js"); var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); var _outboundEvaluator = require("./outbound-evaluator.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kActivityDef = Symbol.for('activityDefinition'); -const kConsuming = Symbol.for('consuming'); -const kConsumingRunQ = Symbol.for('run queue consumer'); -const kCounters = Symbol.for('counters'); -const kEventDefinitions = Symbol.for('eventDefinitions'); -const kExec = Symbol.for('exec'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kExtensions = Symbol.for('extensions'); -const kFlags = Symbol.for('flags'); -const kFlows = Symbol.for('flows'); -const kFormatter = Symbol.for('formatter'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kStateMessage = Symbol.for('stateMessage'); -const kActivated = Symbol.for('activated'); +const K_ACTIVITY_DEF = Symbol.for('activityDefinition'); +const K_CONSUMING_RUN_Q = Symbol.for('run queue consumer'); +const K_EVENT_DEFINITIONS = Symbol.for('eventDefinitions'); +const K_EXEC = Symbol.for('exec'); +const K_FLAGS = Symbol.for('flags'); +const K_FLOWS = Symbol.for('flows'); +const K_FORMATTER = Symbol.for('formatter'); var _default = exports.default = Activity; /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. @@ -45,7 +40,9 @@ function Activity(Behaviour, activityDef, context) { attachedTo: attachedToRef, eventDefinitions } = behaviour; - this[kActivityDef] = activityDef; + + /** @private */ + this[K_ACTIVITY_DEF] = activityDef; this.id = id; this.type = type; this.name = name; @@ -58,7 +55,8 @@ function Activity(Behaviour, activityDef, context) { this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; - this[kCounters] = { + /** @private */ + this[_constants.K_COUNTERS] = { taken: 0, discarded: 0 }; @@ -95,14 +93,18 @@ function Activity(Behaviour, activityDef, context) { sourceId }) => sourceId)); const isParallelJoin = activityDef.isParallelGateway && inboundSourceIds.size > 1; - this[kFlows] = { + + /** @private */ + this[K_FLOWS] = { inboundSequenceFlows, inboundAssociations, inboundTriggers, outboundSequenceFlows, outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows) }; - this[kFlags] = { + + /** @private */ + this[K_FLAGS] = { isEnd: !outboundSequenceFlows.length, isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, @@ -116,173 +118,157 @@ function Activity(Behaviour, activityDef, context) { isCatching: activityDef.isCatching, lane: activityDef.lane?.id }; - this[kExec] = new Map(); - this[kMessageHandlers] = { + /** @private */ + this[K_EXEC] = new Map(); + + /** @private */ + this[_constants.K_MESSAGE_HANDLERS] = { onInbound: this._onInbound.bind(this), onRunMessage: this._onRunMessage.bind(this), onApiMessage: this._onApiMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this) }; - this[kEventDefinitions] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); - this[kExtensions] = context.loadExtensions(this); - this[kConsuming] = false; - this[kConsumingRunQ] = undefined; + + /** @private */ + this[K_EVENT_DEFINITIONS] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); + /** @private */ + this[_constants.K_EXTENSIONS] = context.loadExtensions(this); + /** @private */ + this[_constants.K_CONSUMING] = false; + /** @private */ + this[K_CONSUMING_RUN_Q] = undefined; } Object.defineProperties(Activity.prototype, { counters: { - /** @returns {{ taken: number, discarded: number }} */ get() { return { - ...this[kCounters] + ...this[_constants.K_COUNTERS] }; } }, execution: { - /** @returns {import('types').ActivityExecution | undefined} */ get() { - return this[kExec].get('execution'); + return this[K_EXEC].get('execution'); } }, executionId: { - /** @returns {string | undefined} */ get() { - return this[kExec].get('executionId'); + return this[K_EXEC].get('executionId'); } }, extensions: { - /** @returns {import('types').IExtension} */ get() { - return this[kExtensions]; + return this[_constants.K_EXTENSIONS]; } }, bpmnIo: { - /** @returns {import('types').IExtension | undefined} */ get() { - const extensions = this[kExtensions]; + const extensions = this[_constants.K_EXTENSIONS]; return extensions?.extensions.find(e => e.type === 'bpmnio'); } }, formatter: { - /** @returns {import('types').MessageFormatter} */ get() { - let formatter = this[kFormatter]; + let formatter = this[K_FORMATTER]; if (formatter) return formatter; - formatter = this[kFormatter] = new _MessageFormatter.Formatter(this); + formatter = this[K_FORMATTER] = new _MessageFormatter.Formatter(this); return formatter; } }, isRunning: { - /** @returns {boolean} */ get() { - if (!this[kConsuming]) return false; + if (!this[_constants.K_CONSUMING]) return false; return !!this.status; } }, outbound: { - /** @returns {import('types').SequenceFlow[]} */ get() { - return this[kFlows].outboundSequenceFlows; + return this[K_FLOWS].outboundSequenceFlows; } }, inbound: { - /** @returns {import('types').SequenceFlow[]} */ get() { - return this[kFlows].inboundSequenceFlows; + return this[K_FLOWS].inboundSequenceFlows; } }, isEnd: { - /** @returns {boolean} */ get() { - return this[kFlags].isEnd; + return this[K_FLAGS].isEnd; } }, isStart: { - /** @returns {boolean} */ get() { - return this[kFlags].isStart; + return this[K_FLAGS].isStart; } }, isSubProcess: { - /** @returns {boolean} */ get() { - return this[kFlags].isSubProcess; + return this[K_FLAGS].isSubProcess; } }, isTransaction: { - /** @returns {boolean} */ get() { - return this[kFlags].isTransaction; + return this[K_FLAGS].isTransaction; } }, isMultiInstance: { - /** @returns {boolean} */ get() { - return this[kFlags].isMultiInstance; + return this[K_FLAGS].isMultiInstance; } }, isThrowing: { - /** @returns {boolean} */ get() { - return this[kFlags].isThrowing; + return this[K_FLAGS].isThrowing; } }, isCatching: { - /** @returns {boolean} */ get() { - return this[kFlags].isCatching; + return this[K_FLAGS].isCatching; } }, isForCompensation: { - /** @returns {boolean} */ get() { - return this[kFlags].isForCompensation; + return this[K_FLAGS].isForCompensation; } }, isParallelJoin: { - /** @returns {boolean} */ get() { - return this[kFlags].isParallelJoin; + return this[K_FLAGS].isParallelJoin; } }, triggeredByEvent: { - /** @returns {boolean} */ get() { - return this[kActivityDef].triggeredByEvent; + return this[K_ACTIVITY_DEF].triggeredByEvent; } }, attachedTo: { - /** @returns {import('types').Activity | null} */ get() { - const attachedToId = this[kFlags].attachedTo; + const attachedToId = this[K_FLAGS].attachedTo; if (!attachedToId) return null; return this.getActivityById(attachedToId); } }, lane: { - /** @returns {import('types').Lane | undefined} */ get() { - const laneId = this[kFlags].lane; + const laneId = this[K_FLAGS].lane; if (!laneId) return undefined; const parent = this.parentElement; return parent.getLaneById && parent.getLaneById(laneId); } }, eventDefinitions: { - /** @returns {import('types').EventDefinition[]} */ get() { - return this[kEventDefinitions]; + return this[K_EVENT_DEFINITIONS]; } }, parentElement: { - /** @returns {import('types').Process | import('types').Activity} Parent process or sub process reference */ get() { return this.context.getActivityParentById(this.id); } }, initialized: { - /** @returns {boolean} */ get() { - return !!this[kExec]?.get('initExecutionId'); + return !!this[K_EXEC]?.get('initExecutionId'); } } }); @@ -291,8 +277,9 @@ Object.defineProperties(Activity.prototype, { * Subscribe to inbound flows and start consuming the inbound queue. */ Activity.prototype.activate = function activate() { - if (this[kActivated]) return; - this[kActivated] = true; + if (this[_constants.K_ACTIVATED]) return; + /** @private */ + this[_constants.K_ACTIVATED] = true; return this.addInboundListeners() && this._consumeInbound(); }; @@ -300,7 +287,8 @@ Activity.prototype.activate = function activate() { * Cancel inbound subscriptions and any pending run/format consumers. */ Activity.prototype.deactivate = function deactivate() { - this[kActivated] = false; + /** @private */ + this[_constants.K_ACTIVATED] = false; const broker = this.broker; this.removeInboundListeners(); broker.cancel('_run-on-inbound'); @@ -313,7 +301,7 @@ Activity.prototype.deactivate = function deactivate() { */ Activity.prototype.init = function init(initContent) { const id = this.id; - const exec = this[kExec]; + const exec = this[K_EXEC]; const executionId = exec.has('initExecutionId') ? exec.get('initExecutionId') : (0, _shared.getUniqueId)(id); exec.set('initExecutionId', executionId); this.logger.debug(`<${id}> initialized with executionId <${executionId}>`); @@ -331,7 +319,7 @@ Activity.prototype.init = function init(initContent) { Activity.prototype.run = function run(runContent) { const id = this.id; if (this.isRunning) throw new Error(`activity <${id}> is already running`); - const exec = this[kExec]; + const exec = this[K_EXEC]; const executionId = exec.get('initExecutionId') || (0, _shared.getUniqueId)(id); exec.set('executionId', executionId); exec.delete('initExecutionId'); @@ -343,18 +331,19 @@ Activity.prototype.run = function run(runContent) { const broker = this.broker; broker.publish('run', 'run.enter', content); broker.publish('run', 'run.start', (0, _messageHelper.cloneContent)(content)); - this[kConsuming] = true; + + /** @private */ + this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; /** * Snapshot activity state for recover. * Returns undefined when nothing is running and `disableTrackState` is set. - * @returns {import('types').ActivityState | undefined} */ Activity.prototype.getState = function getState() { const status = this.status; - const exec = this[kExec]; + const exec = this[K_EXEC]; const execution = exec.get('execution'); const executionId = exec.get('executionId'); const brokerState = this.broker.getState(true); @@ -378,19 +367,20 @@ Activity.prototype.getState = function getState() { /** * Restore activity state captured by getState. Cannot be called while running. * @param {import('types').ActivityState} [state] - * @returns {Activity | undefined} this when state was applied + * @returns {this} this when state was applied * @throws {Error} when activity is currently running */ Activity.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running activity <${this.id}>`); - if (!state) return; // TODO: return this - + if (!state) return this; this.stopped = state.stopped; this.status = state.status; - const exec = this[kExec]; + const exec = this[K_EXEC]; exec.set('executionId', state.executionId); - this[kCounters] = { - ...this[kCounters], + + /** @private */ + this[_constants.K_COUNTERS] = { + ...this[_constants.K_COUNTERS], ...state.counters }; if (state.execution) { @@ -405,7 +395,7 @@ Activity.prototype.recover = function recover(state) { * @throws {Error} when called on a running activity */ Activity.prototype.resume = function resume() { - if (this[kConsuming]) { + if (this[_constants.K_CONSUMING]) { throw new Error(`cannot resume running activity <${this.id}>`); } if (!this.status) return this.activate(); @@ -415,7 +405,9 @@ Activity.prototype.resume = function resume() { this.broker.publish('run', 'run.resume', content, { persistent: false }); - this[kConsuming] = true; + + /** @private */ + this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; @@ -425,22 +417,23 @@ Activity.prototype.resume = function resume() { */ Activity.prototype.discard = function discard(discardContent) { if (!this.status) return this._runDiscard(discardContent); - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (execution && !execution.completed) return execution.discard(); this._deactivateRunConsumers(); const broker = this.broker; broker.getQueue('run-q').purge(); - broker.publish('run', 'run.discard', (0, _messageHelper.cloneContent)(this[kStateMessage].content)); - this[kConsuming] = true; + broker.publish('run', 'run.discard', (0, _messageHelper.cloneContent)(this[_constants.K_STATE_MESSAGE].content)); + /** @private */ + this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; /** * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns {number} count of subscribed triggers + * @returns count of subscribed triggers */ Activity.prototype.addInboundListeners = function addInboundListeners() { - const triggers = this[kFlows].inboundTriggers; + const triggers = this[K_FLOWS].inboundTriggers; if (triggers.length) { const onInboundEvent = this._onInboundEvent.bind(this); const triggerConsumerTag = `_inbound-${this.id}`; @@ -471,7 +464,7 @@ Activity.prototype.addInboundListeners = function addInboundListeners() { */ Activity.prototype.removeInboundListeners = function removeInboundListeners() { const triggerConsumerTag = `_inbound-${this.id}`; - for (const trigger of this[kFlows].inboundTriggers) { + for (const trigger of this[K_FLOWS].inboundTriggers) { trigger.broker.cancel(triggerConsumerTag); } }; @@ -480,17 +473,16 @@ Activity.prototype.removeInboundListeners = function removeInboundListeners() { * Stop the activity. If not currently running, just cancels the inbound consumer. */ Activity.prototype.stop = function stop() { - if (!this[kConsuming]) return this.broker.cancel('_run-on-inbound'); - return this.getApi(this[kStateMessage]).stop(); + if (!this[_constants.K_CONSUMING]) return this.broker.cancel('_run-on-inbound'); + return this.getApi(this[_constants.K_STATE_MESSAGE]).stop(); }; /** * Advance one run-step when the environment runs in step mode. No-op otherwise. - * @returns {import('types').ElementBrokerMessage | false | undefined} */ Activity.prototype.next = function next() { if (!this.environment.settings.step) return; - const stateMessage = this[kStateMessage]; + const stateMessage = this[_constants.K_STATE_MESSAGE]; if (!stateMessage) return; if (this.status === 'executing') return false; if (this.status === 'formatting') return false; @@ -515,30 +507,30 @@ Activity.prototype.shake = function shake() { * @param {(err: Error, evaluationResult: any) => void} callback */ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) { - return this[kFlows].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); + return this[K_FLOWS].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); }; /** * Resolve an Api wrapper for the activity, preferring the running execution if any. * @param {import('types').ElementBrokerMessage} [message] - * @returns {import('types').Api} */ Activity.prototype.getApi = function getApi(message) { - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (execution && !execution.completed) return execution.getApi(message); - return (0, _Api.ActivityApi)(this.broker, message || this[kStateMessage]); + return (0, _Api.ActivityApi)(this.broker, message || this[_constants.K_STATE_MESSAGE]); }; /** * Look up another activity in the same context. * @param {string} elementId - * @returns {import('types').Activity | undefined} */ Activity.prototype.getActivityById = function getActivityById(elementId) { return this.context.getActivityById(elementId); }; + +/** @internal */ Activity.prototype._runDiscard = function runDiscard(discardContent) { - const exec = this[kExec]; + const exec = this[K_EXEC]; const executionId = exec.get('initExecutionId') || (0, _shared.getUniqueId)(this.id); exec.set('executionId', executionId); exec.delete('initExecutionId'); @@ -548,13 +540,17 @@ Activity.prototype._runDiscard = function runDiscard(discardContent) { executionId }); this.broker.publish('run', 'run.discard', content); - this[kConsuming] = true; + + /** @private */ + this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; + +/** @internal */ Activity.prototype._discardRun = function discardRun() { const status = this.status; if (!status) return; - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (execution && !execution.completed) return; let discardRoutingKey = 'run.discard'; switch (status) { @@ -570,18 +566,21 @@ Activity.prototype._discardRun = function discardRun() { return; } this._deactivateRunConsumers(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[_constants.K_STATE_MESSAGE]; if (this.extensions) this.extensions.deactivate((0, _messageHelper.cloneMessage)(stateMessage)); const broker = this.broker; broker.getQueue('run-q').purge(); broker.publish('run', discardRoutingKey, (0, _messageHelper.cloneContent)(stateMessage.content), { correlationId: stateMessage.properties.correlationId }); - this[kConsuming] = true; + /** @private */ + this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; + +/** @internal */ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { - if (this[kFlags].isParallelGateway) { + if (this[K_FLAGS].isParallelGateway) { const message = (0, _messageHelper.cloneMessage)(sourceMessage, { join: this.id }); @@ -596,6 +595,8 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { } this._shakeOutbound(sourceMessage); }; + +/** @internal */ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { const message = (0, _messageHelper.cloneMessage)(sourceMessage); const sequence = message.content.sequence = message.content.sequence || []; @@ -610,14 +611,14 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { persistent: false, type: 'shake' }); - if (this[kFlags].isEnd) { + if (this[K_FLAGS].isEnd) { return this.broker.publish('event', 'activity.shake.end', (0, _messageHelper.cloneContent)(message.content), { persistent: false, type: 'shake' }); } const targets = new Map(); - for (const outboundFlow of this[kFlows].outboundSequenceFlows) { + for (const outboundFlow of this[K_FLOWS].outboundSequenceFlows) { const prevTarget = targets.get(outboundFlow.targetId); if (!prevTarget) { targets.set(outboundFlow.targetId, outboundFlow); @@ -625,15 +626,19 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { } for (const t of targets.values()) t.shake(message); }; + +/** @internal */ Activity.prototype._consumeInbound = function consumeInbound() { - if (!this[kActivated]) return; - if (this.status || !this[kFlows].inboundTriggers.length) return; + if (!this[_constants.K_ACTIVATED]) return; + if (this.status || !this[K_FLOWS].inboundTriggers.length) return; const inboundQ = this.broker.getQueue('inbound-q'); - const onInbound = this[kMessageHandlers].onInbound; + const onInbound = this[_constants.K_MESSAGE_HANDLERS].onInbound; return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); }; + +/** @internal */ Activity.prototype._onInbound = function onInbound(routingKey, message) { message.ack(); const broker = this.broker; @@ -658,10 +663,12 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { inbound, discardSequence }; - return this[kFlags].isParallelGateway ? this.run(context) : this._runDiscard(context); + return this[K_FLAGS].isParallelGateway ? this.run(context) : this._runDiscard(context); } } }; + +/** @internal */ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message) { const { fields, @@ -673,7 +680,7 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message case 'activity.enter': case 'activity.discard': { - if (content.id === this[kFlags].attachedTo) { + if (content.id === this[K_FLAGS].attachedTo) { inboundQ.queueMessage(fields, (0, _messageHelper.cloneContent)(content), properties); } break; @@ -687,18 +694,27 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message return inboundQ.queueMessage(fields, (0, _messageHelper.cloneContent)(content), properties); } }; + +/** @internal */ Activity.prototype._consumeRunQ = function consumeRunQ() { - this[kConsumingRunQ] = true; - this.broker.getQueue('run-q').assertConsumer(this[kMessageHandlers].onRunMessage, { + /** @private */ + this[K_CONSUMING_RUN_Q] = true; + this.broker.getQueue('run-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onRunMessage, { exclusive: true, consumerTag: '_activity-run' }); }; + +/** @internal */ Activity.prototype._pauseRunQ = function pauseRunQ() { - if (!this[kConsumingRunQ]) return; - this[kConsumingRunQ] = false; + if (!this[K_CONSUMING_RUN_Q]) return; + + /** @private */ + this[K_CONSUMING_RUN_Q] = false; this.broker.cancel('_activity-run'); }; + +/** @internal */ Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, messageProperties) { switch (routingKey) { case 'run.execute.passthrough': @@ -722,20 +738,24 @@ Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, me this._continueRunMessage(routingKey, message, messageProperties); }); }; + +/** @internal */ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, message) { const isRedelivered = message.fields.redelivered; const content = (0, _messageHelper.cloneContent)(message.content); const correlationId = message.properties.correlationId; const id = this.id; const step = this.environment.settings.step; - this[kStateMessage] = message; + /** @private */ + this[_constants.K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this.logger.debug(`<${id}> enter`, isRedelivered ? 'redelivered' : ''); this.status = 'entered'; if (!isRedelivered) { - this[kExec].delete('execution'); + /** @private */ + this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate((0, _messageHelper.cloneMessage)(message)); this._publishEvent('enter', content, { correlationId @@ -747,7 +767,8 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, { this.logger.debug(`<${id}> discard`, isRedelivered ? 'redelivered' : ''); this.status = 'discard'; - this[kExec].delete('execution'); + /** @private */ + this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate((0, _messageHelper.cloneMessage)(message)); if (!isRedelivered) { this.broker.publish('run', 'run.discarded', content, { @@ -773,25 +794,27 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, } case 'run.execute.passthrough': { - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (!isRedelivered && execution) { if (execution.completed) return message.ack(); - this[kExecuteMessage] = message; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = message; return execution.passthrough(message); } } case 'run.execute': { this.status = 'executing'; - this[kExecuteMessage] = message; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = message; if (isRedelivered && this.extensions) this.extensions.activate((0, _messageHelper.cloneMessage)(message)); - const exec = this[kExec]; + const exec = this[K_EXEC]; let execution = exec.get('execution'); if (!execution) { execution = new _ActivityExecution.default(this, this.context); exec.set('execution', execution); } - this.broker.getQueue('execution-q').assertConsumer(this[kMessageHandlers].onExecutionMessage, { + this.broker.getQueue('execution-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, consumerTag: '_activity-execution' }); @@ -801,7 +824,9 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, { this.logger.debug(`<${id}> end`, isRedelivered ? 'redelivered' : ''); if (isRedelivered) break; - this[kCounters].taken++; + + /** @private */ + this[_constants.K_COUNTERS].taken++; this.status = 'end'; return this._doRunLeave(message, false, () => { this._publishEvent('end', content, { @@ -823,7 +848,8 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, case 'run.discarded': { this.logger.debug(`<${content.executionId} (${id})> discarded`); - this[kCounters].discarded++; + /** @private */ + this[_constants.K_COUNTERS].discarded++; this.status = 'discarded'; content.outbound = undefined; if (!isRedelivered) { @@ -866,8 +892,10 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, } if (!step) message.ack(); }; + +/** @internal */ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) { - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; const content = (0, _messageHelper.cloneContent)({ ...executeMessage.content, ...message.content, @@ -924,11 +952,15 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message.ack(); this._ackRunExecuteMessage(); }; + +/** @internal */ Activity.prototype._ackRunExecuteMessage = function ackRunExecuteMessage() { if (this.environment.settings.step) return; - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; executeMessage.ack(); }; + +/** @internal */ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOutbound) { const { content, @@ -960,12 +992,14 @@ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOut onOutbound(); }); }; + +/** @internal */ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) { - const outboundSequenceFlows = this[kFlows].outboundSequenceFlows; + const outboundSequenceFlows = this[K_FLOWS].outboundSequenceFlows; if (!outboundSequenceFlows.length) return callback(null, []); const fromContent = fromMessage.content; let discardSequence = fromContent.discardSequence; - if (isDiscarded && !discardSequence && this[kFlags].attachedTo && fromContent.inbound?.[0]) { + if (isDiscarded && !discardSequence && this[K_FLAGS].attachedTo && fromContent.inbound?.[0]) { discardSequence = [fromContent.inbound[0].id]; } let outboundFlows; @@ -986,6 +1020,8 @@ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, c return callback(null, outbound); }); }; + +/** @internal */ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) { if (outboundList.length === 1) { this._publishRunOutbound(outboundList[0], content, discardSequence); @@ -1005,6 +1041,8 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content } return outboundList; }; + +/** @internal */ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content, discardSequence) { const { id: flowId, @@ -1025,9 +1063,11 @@ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlo } })); }; + +/** @internal */ Activity.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[_constants.K_STATE_MESSAGE]; const fields = stateMessage.fields; if (!fields.redelivered) return; switch (fields.routingKey) { @@ -1044,6 +1084,8 @@ Activity.prototype._onResumeMessage = function onResumeMessage(message) { this.logger.debug(`<${this.id}> resume from ${message.content.status}`); return this.broker.publish('run', fields.routingKey, (0, _messageHelper.cloneContent)(stateMessage.content), stateMessage.properties); }; + +/** @internal */ Activity.prototype._publishEvent = function publishEvent(state, content, properties) { this.broker.publish('event', `activity.${state}`, (0, _messageHelper.cloneContent)(content, { state @@ -1053,10 +1095,14 @@ Activity.prototype._publishEvent = function publishEvent(state, content, propert mandatory: state === 'error' }); }; + +/** @internal */ Activity.prototype._onStop = function onStop(message) { - const running = this[kConsuming]; + const running = this[_constants.K_CONSUMING]; this.stopped = true; - this[kConsuming] = false; + + /** @private */ + this[_constants.K_CONSUMING] = false; const broker = this.broker; this._pauseRunQ(); broker.cancel('_activity-api'); @@ -1070,17 +1116,21 @@ Activity.prototype._onStop = function onStop(message) { }); } }; + +/** @internal */ Activity.prototype._consumeApi = function consumeApi() { - const executionId = this[kExec].get('executionId'); + const executionId = this[K_EXEC].get('executionId'); if (!executionId) return; const broker = this.broker; broker.cancel('_activity-api'); - broker.subscribeTmp('api', `activity.*.${executionId}`, this[kMessageHandlers].onApiMessage, { + broker.subscribeTmp('api', `activity.*.${executionId}`, this[_constants.K_MESSAGE_HANDLERS].onApiMessage, { noAck: true, consumerTag: '_activity-api', priority: 100 }); }; + +/** @internal */ Activity.prototype._onApiMessage = function onApiMessage(routingKey, message) { switch (message.properties.type) { case 'discard': @@ -1097,6 +1147,8 @@ Activity.prototype._onApiMessage = function onApiMessage(routingKey, message) { } } }; + +/** @internal */ Activity.prototype._createMessage = function createMessage(override) { const { name, @@ -1117,18 +1169,23 @@ Activity.prototype._createMessage = function createMessage(override) { parent: (0, _messageHelper.cloneParent)(parent) }) }; - for (const [flag, value] of Object.entries(this[kFlags])) { + for (const [flag, value] of Object.entries(this[K_FLAGS])) { if (value) result[flag] = value; } return result; }; + +/** @internal */ Activity.prototype._getOutboundSequenceFlowById = function getOutboundSequenceFlowById(flowId) { - return this[kFlows].outboundSequenceFlows.find(flow => flow.id === flowId); + return this[K_FLOWS].outboundSequenceFlows.find(flow => flow.id === flowId); }; + +/** @internal */ Activity.prototype._deactivateRunConsumers = function _deactivateRunConsumers() { const broker = this.broker; broker.cancel('_activity-api'); this._pauseRunQ(); broker.cancel('_activity-execution'); - this[kConsuming] = false; + /** @private */ + this[_constants.K_CONSUMING] = false; }; \ No newline at end of file diff --git a/dist/activity/ActivityExecution.js b/dist/activity/ActivityExecution.js index 44f29f97..b95fbc87 100644 --- a/dist/activity/ActivityExecution.js +++ b/dist/activity/ActivityExecution.js @@ -6,45 +6,62 @@ Object.defineProperty(exports, "__esModule", { exports.default = void 0; var _Api = require("../Api.js"); var _messageHelper = require("../messageHelper.js"); -const kCompleted = Symbol.for('completed'); -const kExecuteQ = Symbol.for('executeQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kPostponed = Symbol.for('postponed'); +var _constants = require("../constants.js"); +const K_EXECUTE_Q = Symbol.for('executeQ'); +const K_POSTPONED = Symbol.for('postponed'); var _default = exports.default = ActivityExecution; +/** + * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour + * and drives the execute message flow over the activity broker. + * @param {import('types').Activity} activity + * @param {import('types').ContextInstance} context + */ function ActivityExecution(activity, context) { this.activity = activity; this.context = context; this.id = activity.id; this.broker = activity.broker; - this[kPostponed] = new Set(); - this[kCompleted] = false; - this[kExecuteQ] = this.broker.assertQueue('execute-q', { + /** @private */ + this[K_POSTPONED] = new Set(); + /** @private */ + this[_constants.K_COMPLETED] = false; + /** @private */ + this[K_EXECUTE_Q] = this.broker.assertQueue('execute-q', { durable: true, autoDelete: false }); - this[kMessageHandlers] = { + + /** @private */ + this[_constants.K_MESSAGE_HANDLERS] = { onParentApiMessage: this._onParentApiMessage.bind(this), onExecuteMessage: this._onExecuteMessage.bind(this) }; } Object.defineProperty(ActivityExecution.prototype, 'completed', { + /** @returns {boolean} */ get() { - return this[kCompleted]; + return this[_constants.K_COMPLETED]; } }); + +/** + * Begin executing the activity behaviour. Resumes if the message is redelivered. + * @param {import('types').ElementBrokerMessage} executeMessage + * @throws {Error} when message or executionId is missing + */ ActivityExecution.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new Error('Execution requires message'); const executionId = executeMessage.content?.executionId; if (!executionId) throw new Error('Execution requires execution id'); this.executionId = executionId; - const initMessage = this[kExecuteMessage] = (0, _messageHelper.cloneMessage)(executeMessage, { + const initMessage = this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage, { executionId, state: 'start', isRootScope: true }); if (executeMessage.fields.redelivered) { - this[kPostponed].clear(); + /** @private */ + this[K_POSTPONED].clear(); this._debug('resume execution'); if (!this.source) this.source = new this.activity.Behaviour(this.activity, this.context); this.activate(); @@ -57,8 +74,12 @@ ActivityExecution.prototype.execute = function execute(executeMessage) { this.source = new this.activity.Behaviour(this.activity, this.context); this.broker.publish('execution', 'execute.start', (0, _messageHelper.cloneContent)(initMessage.content)); }; + +/** + * Bind the execute queue and start consuming execute and api messages. + */ ActivityExecution.prototype.activate = function activate() { - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; const broker = this.broker; const batchSize = this.activity.environment.settings.batchSize || 50; broker.bindQueue('execute-q', 'execution', 'execute.#', { @@ -67,35 +88,49 @@ ActivityExecution.prototype.activate = function activate() { const { onExecuteMessage, onParentApiMessage - } = this[kMessageHandlers]; - this[kExecuteQ].assertConsumer(onExecuteMessage, { + } = this[_constants.K_MESSAGE_HANDLERS]; + /** @private */ + this[K_EXECUTE_Q].assertConsumer(onExecuteMessage, { exclusive: true, prefetch: batchSize * 2, priority: 100, consumerTag: '_activity-execute' }); - if (this[kCompleted]) return this.deactivate(); + if (this[_constants.K_COMPLETED]) return this.deactivate(); broker.subscribeTmp('api', `activity.*.${this.executionId}`, onParentApiMessage, { noAck: true, consumerTag: '_activity-api-execution', priority: 200 }); }; + +/** + * Cancel execute and api consumers and unbind the execute queue. + */ ActivityExecution.prototype.deactivate = function deactivate() { const broker = this.broker; broker.cancel('_activity-api-execution'); broker.cancel('_activity-execute'); broker.unbindQueue('execute-q', 'execution', 'execute.#'); }; + +/** + * Discard the running execution. + */ ActivityExecution.prototype.discard = function discard() { - if (this[kCompleted]) return; - const initMessage = this[kExecuteMessage]; + if (this[_constants.K_COMPLETED]) return; + const initMessage = this[_constants.K_EXECUTE_MESSAGE]; if (!initMessage) return this.activity.logger.warn(`<${this.id}> is not executing`); this.getApi(initMessage).discard(); }; + +/** + * Resolve an Api wrapper, preferring a behaviour-specific Api when the source exposes one. + * @param {import('types').ElementBrokerMessage} [apiMessage] + */ ActivityExecution.prototype.getApi = function getApi(apiMessage) { const self = this; - if (!apiMessage) apiMessage = this[kExecuteMessage]; + if (!apiMessage) apiMessage = this[_constants.K_EXECUTE_MESSAGE]; if (self.source.getApi) { const sourceApi = self.source.getApi(apiMessage); if (sourceApi) return sourceApi; @@ -103,7 +138,7 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { const api = (0, _Api.ActivityApi)(self.broker, apiMessage); api.getExecuting = function getExecuting() { const result = []; - for (const msg of self[kPostponed]) { + for (const msg of self[K_POSTPONED]) { if (msg.content.executionId === apiMessage.content.executionId) continue; result.push(self.getApi(msg)); } @@ -111,22 +146,35 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { }; return api; }; + +/** + * Pass an execute message straight to the behaviour, executing first if no source is set up yet. + * @param {import('types').ElementBrokerMessage} executeMessage + */ ActivityExecution.prototype.passthrough = function passthrough(executeMessage) { if (!this.source) return this.execute(executeMessage); return this._sourceExecute(executeMessage); }; + +/** + * List currently postponed executions as Api wrappers, including those from sub-process behaviours. + */ ActivityExecution.prototype.getPostponed = function getPostponed() { let apis = []; - for (const msg of this[kPostponed]) { + for (const msg of this[K_POSTPONED]) { apis.push(this.getApi(msg)); } if (!this.activity.isSubProcess || !this.source) return apis; apis = apis.concat(this.source.getPostponed()); return apis; }; + +/** + * Snapshot execution state, merging behaviour-specific state when the source provides it. + */ ActivityExecution.prototype.getState = function getState() { const result = { - completed: this[kCompleted] + completed: this[_constants.K_COMPLETED] }; const source = this.source; if (!source || !source.getState) return result; @@ -135,21 +183,34 @@ ActivityExecution.prototype.getState = function getState() { ...source.getState() }; }; + +/** + * Restore execution state captured by getState. + * @param {import('types').ActivityExecutionState} [state] + * @returns {this} + */ ActivityExecution.prototype.recover = function recover(state) { - this[kPostponed].clear(); + /** @private */ + this[K_POSTPONED].clear(); if (!state) return this; - if ('completed' in state) this[kCompleted] = state.completed; + if ('completed' in state) this[_constants.K_COMPLETED] = state.completed; const source = this.source = new this.activity.Behaviour(this.activity, this.context); if (source.recover) { source.recover(state); } return this; }; + +/** + * Stop the execution via the activity api. + */ ActivityExecution.prototype.stop = function stop() { - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; if (!executeMessage) return; this.getApi(executeMessage).stop(); }; + +/** @internal */ ActivityExecution.prototype._sourceExecute = function sourceExecute(executeMessage) { try { return this.source.execute(executeMessage); @@ -159,6 +220,8 @@ ActivityExecution.prototype._sourceExecute = function sourceExecute(executeMessa })); } }; + +/** @internal */ ActivityExecution.prototype._onExecuteMessage = function onExecuteMessage(routingKey, message) { const { fields, @@ -170,7 +233,7 @@ ActivityExecution.prototype._onExecuteMessage = function onExecuteMessage(routin switch (routingKey) { case 'execute.resume.execution': { - if (!this[kPostponed].size) return this.broker.publish('execution', 'execute.start', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content)); + if (!this[K_POSTPONED].size) return this.broker.publish('execution', 'execute.start', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); break; } case 'execute.cancel': @@ -212,12 +275,14 @@ ActivityExecution.prototype._onExecuteMessage = function onExecuteMessage(routin } } }; + +/** @internal */ ActivityExecution.prototype._onStateChangeMessage = function onStateChangeMessage(message) { const { ignoreIfExecuting, executionId } = message.content; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; let previousMsg; for (const msg of postponed) { if (msg.content.executionId === executionId) previousMsg = msg; @@ -236,10 +301,12 @@ ActivityExecution.prototype._onStateChangeMessage = function onStateChangeMessag return true; } }; + +/** @internal */ ActivityExecution.prototype._onExecutionCompleted = function onExecutionCompleted(message) { const postponedMsg = this._ackPostponed(message); if (!postponedMsg) return; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; const { executionId, keep, @@ -257,7 +324,8 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete return; } this._debug('completed execution', executionId); - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; message.ack(true); this.deactivate(); const subApis = this.getPostponed(); @@ -268,6 +336,8 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete ...message.content }, message.properties.correlationId); }; + +/** @internal */ ActivityExecution.prototype._onExecutionDiscarded = function onExecutionDiscarded(discardType, message) { const postponedMsg = this._ackPostponed(message); const { @@ -275,7 +345,7 @@ ActivityExecution.prototype._onExecutionDiscarded = function onExecutionDiscarde error } = message.content; if (!isRootScope && !postponedMsg) return; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; const correlationId = message.properties.correlationId; if (!error && !isRootScope) { message.ack(); @@ -296,8 +366,11 @@ ActivityExecution.prototype._onExecutionDiscarded = function onExecutionDiscarde for (const api of subApis) api.discard(); this._publishExecutionCompleted(discardType, (0, _messageHelper.cloneContent)(message.content), correlationId); }; + +/** @internal */ ActivityExecution.prototype._publishExecutionCompleted = function publishExecutionCompleted(completionType, completeContent, correlationId) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this.broker.publish('execution', `execution.${completionType}`, { ...completeContent, state: completionType @@ -306,11 +379,13 @@ ActivityExecution.prototype._publishExecutionCompleted = function publishExecuti correlationId }); }; + +/** @internal */ ActivityExecution.prototype._ackPostponed = function ackPostponed(completeMessage) { const { executionId: eid } = completeMessage.content; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; for (const msg of postponed) { if (msg.content.executionId === eid) { postponed.delete(msg); @@ -319,24 +394,28 @@ ActivityExecution.prototype._ackPostponed = function ackPostponed(completeMessag } } }; + +/** @internal */ ActivityExecution.prototype._onParentApiMessage = function onParentApiMessage(routingKey, message) { switch (message.properties.type) { case 'error': - return this[kExecuteQ].queueMessage({ + return this[K_EXECUTE_Q].queueMessage({ routingKey: 'execute.error' }, { error: message.content.error }); case 'discard': - return this[kExecuteQ].queueMessage({ + return this[K_EXECUTE_Q].queueMessage({ routingKey: 'execute.discard' - }, (0, _messageHelper.cloneContent)(this[kExecuteMessage].content)); + }, (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); case 'stop': { return this._onStop(message); } } }; + +/** @internal */ ActivityExecution.prototype._onStop = function onStop(message) { const stoppedId = message?.content?.executionId; const running = this.getPostponed(); @@ -348,6 +427,8 @@ ActivityExecution.prototype._onStop = function onStop(message) { this.broker.cancel('_activity-execute'); this.broker.cancel('_activity-api-execution'); }; + +/** @internal */ ActivityExecution.prototype._debug = function debug(logMessage, executionId) { executionId = executionId || this.executionId; this.activity.logger.debug(`<${executionId} (${this.id})> ${logMessage}`); diff --git a/dist/constants.js b/dist/constants.js new file mode 100644 index 00000000..473f17ec --- /dev/null +++ b/dist/constants.js @@ -0,0 +1,21 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.K_TARGETS = exports.K_STOPPED = exports.K_STATUS = exports.K_STATE_MESSAGE = exports.K_REFERENCE_INFO = exports.K_REFERENCE_ELEMENT = exports.K_MESSAGE_Q = exports.K_MESSAGE_HANDLERS = exports.K_EXTENSIONS = exports.K_EXECUTION = exports.K_EXECUTE_MESSAGE = exports.K_COUNTERS = exports.K_CONSUMING = exports.K_COMPLETED = exports.K_ACTIVATED = void 0; +const K_ACTIVATED = exports.K_ACTIVATED = Symbol.for('activated'); +const K_COMPLETED = exports.K_COMPLETED = Symbol.for('completed'); +const K_CONSUMING = exports.K_CONSUMING = Symbol.for('consuming'); +const K_COUNTERS = exports.K_COUNTERS = Symbol.for('counters'); +const K_EXECUTE_MESSAGE = exports.K_EXECUTE_MESSAGE = Symbol.for('executeMessage'); +const K_EXECUTION = exports.K_EXECUTION = Symbol.for('execution'); +const K_EXTENSIONS = exports.K_EXTENSIONS = Symbol.for('extensions'); +const K_MESSAGE_HANDLERS = exports.K_MESSAGE_HANDLERS = Symbol.for('messageHandlers'); +const K_MESSAGE_Q = exports.K_MESSAGE_Q = Symbol.for('messageQ'); +const K_REFERENCE_ELEMENT = exports.K_REFERENCE_ELEMENT = Symbol.for('referenceElement'); +const K_REFERENCE_INFO = exports.K_REFERENCE_INFO = Symbol.for('referenceInfo'); +const K_STATE_MESSAGE = exports.K_STATE_MESSAGE = Symbol.for('stateMessage'); +const K_STATUS = exports.K_STATUS = Symbol.for('status'); +const K_STOPPED = exports.K_STOPPED = Symbol.for('stopped'); +const K_TARGETS = exports.K_TARGETS = Symbol.for('targets'); \ No newline at end of file diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index 2e79879e..4fca34f5 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -11,16 +11,15 @@ var _EventBroker = require("../EventBroker.js"); var _shared = require("../shared.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kConsuming = Symbol.for('consuming'); -const kCounters = Symbol.for('counters'); -const kExec = Symbol.for('execution'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kStateMessage = Symbol.for('stateMessage'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); var _default = exports.default = Definition; +/** + * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and + * mediates inter-process messaging. + * @param {import('types').ContextInstance} context + * @param {import('types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged + */ function Definition(context, options) { if (!(this instanceof Definition)) return new Definition(context, options); if (!context) throw new Error('No context'); @@ -40,14 +39,20 @@ function Definition(context, options) { environment = this.environment = context.environment; this.context = context; } - this[kCounters] = { + + /** @private */ + this[_constants.K_COUNTERS] = { completed: 0, discarded: 0 }; - this[kStopped] = false; - this[kExec] = new Map(); + + /** @private */ + this[_constants.K_STOPPED] = false; + /** @private */ + this[_constants.K_EXECUTION] = new Map(); const onBrokerReturn = this._onBrokerReturnFn.bind(this); - this[kMessageHandlers] = { + /** @private */ + this[_constants.K_MESSAGE_HANDLERS] = { onBrokerReturn, onApiMessage: this._onApiMessage.bind(this), onRunMessage: this._onRunMessage.bind(this), @@ -73,43 +78,52 @@ Object.defineProperties(Definition.prototype, { counters: { get() { return { - ...this[kCounters] + ...this[_constants.K_COUNTERS] }; } }, execution: { get() { - return this[kExec].get('execution'); + return this[_constants.K_EXECUTION].get('execution'); } }, executionId: { get() { - return this[kExec].get('executionId'); + return this[_constants.K_EXECUTION].get('executionId'); } }, isRunning: { get() { - if (!this[kConsuming]) return false; + if (!this[_constants.K_CONSUMING]) return false; return !!this.status; } }, status: { get() { - return this[kStatus]; + return this[_constants.K_STATUS]; } }, stopped: { get() { - return this[kStopped]; + return this[_constants.K_STOPPED]; } }, activityStatus: { get() { - const execution = this[kExec].get('execution'); + const execution = this[_constants.K_EXECUTION].get('execution'); return execution?.activityStatus || 'idle'; } } }); + +/** + * Start running the definition. Accepts run options, a callback, or both. + * The callback fires once on leave, stop, or error. + * @param {Record | import('types').runCallback} [optionsOrCallback] + * @param {import('types').runCallback} [optionalCallback] + * @returns {this} + * @throws {Error} when already running and no callback is supplied + */ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { const [runOptions, callback] = (0, _shared.getOptionsAndCallback)(optionsOrCallback, optionalCallback); if (this.isRunning) { @@ -120,7 +134,7 @@ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { if (callback) { addConsumerCallbacks(this, callback); } - const exec = this[kExec]; + const exec = this[_constants.K_EXECUTION]; const executionId = (0, _shared.getUniqueId)(this.id); exec.set('executionId', executionId); const content = this._createMessage({ @@ -134,13 +148,22 @@ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { this._activateRunConsumers(); return this; }; + +/** + * Resume after recover by republishing the last run message. The callback fires once on + * leave, stop, or error. + * @param {import('types').runCallback} [callback] + * @returns {this} + */ Definition.prototype.resume = function resume(callback) { if (this.isRunning) { const err = new Error('cannot resume running definition'); if (callback) return callback(err); throw err; } - this[kStopped] = false; + + /** @private */ + this[_constants.K_STOPPED] = false; if (!this.status) return this; if (callback) { addConsumerCallbacks(this, callback); @@ -153,6 +176,10 @@ Definition.prototype.resume = function resume(callback) { this._activateRunConsumers(); return this; }; + +/** + * Snapshot definition state for recover. + */ Definition.prototype.getState = function getState() { return this._createMessage({ status: this.status, @@ -163,16 +190,27 @@ Definition.prototype.getState = function getState() { broker: this.broker.getState(true) }); }; + +/** + * Restore definition state captured by getState. + * @param {import('types').DefinitionState} [state] + * @returns {this} + * @throws {Error} when called on a running definition + */ Definition.prototype.recover = function recover(state) { if (this.isRunning) throw new Error('cannot recover running definition'); if (!state) return this; - this[kStopped] = !!state.stopped; - this[kStatus] = state.status; - const exec = this[kExec]; + + /** @private */ + this[_constants.K_STOPPED] = !!state.stopped; + /** @private */ + this[_constants.K_STATUS] = state.status; + const exec = this[_constants.K_EXECUTION]; exec.set('executionId', state.executionId); if (state.counters) { - this[kCounters] = { - ...this[kCounters], + /** @private */ + this[_constants.K_COUNTERS] = { + ...this[_constants.K_COUNTERS], ...state.counters }; } @@ -183,6 +221,12 @@ Definition.prototype.recover = function recover(state) { this.broker.recover(state.broker); return this; }; + +/** + * Walk activity graphs to discover sequences. Limited to the activity's owning process + * when startId is given, otherwise all processes are shaken. + * @param {string} [startId] + */ Definition.prototype.shake = function shake(startId) { let result = {}; let bps; @@ -201,6 +245,8 @@ Definition.prototype.shake = function shake(startId) { }); return result; }; + +/** @internal */ Definition.prototype._shakeProcess = function shakeProcess(shakeBp, startId) { let shovel; if (!shakeBp.isRunning) { @@ -216,24 +262,45 @@ Definition.prototype._shakeProcess = function shakeProcess(shakeBp, startId) { if (shovel) shakeBp.broker.closeShovel('shaker'); return shakeResult; }; + +/** + * Get every process in the definition. + */ Definition.prototype.getProcesses = function getProcesses() { const execution = this.execution; if (execution) return execution.getProcesses(); return this.context.getProcesses(); }; + +/** + * Get processes flagged executable in the definition. + */ Definition.prototype.getExecutableProcesses = function getExecutableProcesses() { const execution = this.execution; if (execution) return execution.getExecutableProcesses(); return this.context.getExecutableProcesses(); }; + +/** + * Get processes that are currently running. + */ Definition.prototype.getRunningProcesses = function getRunningProcesses() { const execution = this.execution; if (!execution) return []; return execution.getRunningProcesses(); }; + +/** + * @param {string} processId + */ Definition.prototype.getProcessById = function getProcessById(processId) { return this.getProcesses().find(p => p.id === processId); }; + +/** + * Find an activity by id across all processes in the definition. + * @param {string} childId + */ Definition.prototype.getActivityById = function getActivityById(childId) { const bps = this.getProcesses(); for (const bp of bps) { @@ -242,31 +309,63 @@ Definition.prototype.getActivityById = function getActivityById(childId) { } return null; }; + +/** + * Lookup any element (activity, flow, etc.) in the parsed definition by id. + * @param {string} elementId + */ Definition.prototype.getElementById = function getElementById(elementId) { return this.context.getActivityById(elementId); }; + +/** + * List currently postponed activities as Api wrappers. + * @param {import('types').filterPostponed} [filterFn] + */ Definition.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; if (!execution) return []; return execution.getPostponed(...args); }; + +/** + * Resolve a Definition Api wrapper, preferring the running execution if any. + * @param {import('types').ElementBrokerMessage} [message] + * @throws {Error} when the definition is not running and no message is given + */ Definition.prototype.getApi = function getApi(message) { const execution = this.execution; if (execution) return execution.getApi(message); - message = message || this[kStateMessage]; + message = message || this[_constants.K_STATE_MESSAGE]; if (!message) throw new Error('Definition is not running'); return (0, _Api.DefinitionApi)(this.broker, message); }; + +/** + * Send a delegated signal to the running definition. + * @param {import('types').signalMessage} [message] + */ Definition.prototype.signal = function signal(message) { return this.getApi().signal(message, { delegate: true }); }; + +/** + * Cancel a running activity inside the definition by delegated api message. + * @param {import('types').signalMessage} [message] + */ Definition.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { delegate: true }); }; + +/** + * Deliver a message to a referenced element. Resolves the message reference when the + * target element exposes a `resolve` method (e.g. message-, signal-, escalation events). + * @param {{ id?: string, [x: string]: any }} message + */ Definition.prototype.sendMessage = function sendMessage(message) { const messageContent = { message @@ -287,17 +386,24 @@ Definition.prototype.sendMessage = function sendMessage(message) { delegate: true }); }; + +/** + * Stop the definition if running. + */ Definition.prototype.stop = function stop() { if (!this.isRunning) return; this.getApi().stop(); }; + +/** @internal */ Definition.prototype._activateRunConsumers = function activateRunConsumers() { - this[kConsuming] = true; + /** @private */ + this[_constants.K_CONSUMING] = true; const broker = this.broker; const { onApiMessage, onRunMessage - } = this[kMessageHandlers]; + } = this[_constants.K_MESSAGE_HANDLERS]; broker.subscribeTmp('api', `definition.*.${this.executionId}`, onApiMessage, { noAck: true, consumerTag: '_definition-api' @@ -307,13 +413,18 @@ Definition.prototype._activateRunConsumers = function activateRunConsumers() { consumerTag: '_definition-run' }); }; + +/** @internal */ Definition.prototype._deactivateRunConsumers = function deactivateRunConsumers() { const broker = this.broker; broker.cancel('_definition-api'); broker.cancel('_definition-run'); broker.cancel('_definition-execution'); - this[kConsuming] = false; + /** @private */ + this[_constants.K_CONSUMING] = false; }; + +/** @internal */ Definition.prototype._createMessage = function createMessage(override) { return { id: this.id, @@ -323,6 +434,8 @@ Definition.prototype._createMessage = function createMessage(override) { ...override }; }; + +/** @internal */ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) { const { content, @@ -331,13 +444,16 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) if (routingKey === 'run.resume') { return this._onResumeMessage(message); } - const exec = this[kExec]; - this[kStateMessage] = message; + const exec = this[_constants.K_EXECUTION]; + /** @private */ + this[_constants.K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this.logger.debug(`<${this.executionId} (${this.id})> enter`); - this[kStatus] = 'entered'; + + /** @private */ + this[_constants.K_STATUS] = 'entered'; if (fields.redelivered) break; exec.delete('execution'); this._publishEvent('enter', content); @@ -346,20 +462,23 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) case 'run.start': { this.logger.debug(`<${this.executionId} (${this.id})> start`); - this[kStatus] = 'start'; + /** @private */ + this[_constants.K_STATUS] = 'start'; this._publishEvent('start', content); break; } case 'run.execute': { - this[kStatus] = 'executing'; + /** @private */ + this[_constants.K_STATUS] = 'executing'; const executeMessage = (0, _messageHelper.cloneMessage)(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - this[kExecuteMessage] = message; - this.broker.getQueue('execution-q').assertConsumer(this[kMessageHandlers].onExecutionMessage, { + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = message; + this.broker.getQueue('execution-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, consumerTag: '_definition-execution' }); @@ -374,10 +493,13 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) } case 'run.end': { - if (this[kStatus] === 'end') break; - this[kCounters].completed++; + if (this[_constants.K_STATUS] === 'end') break; + + /** @private */ + this[_constants.K_COUNTERS].completed++; this.logger.debug(`<${this.executionId} (${this.id})> completed`); - this[kStatus] = 'end'; + /** @private */ + this[_constants.K_STATUS] = 'end'; this.broker.publish('run', 'run.leave', content); this._publishEvent('end', content); break; @@ -394,16 +516,21 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) } case 'run.discarded': { - if (this[kStatus] === 'discarded') break; - this[kCounters].discarded++; - this[kStatus] = 'discarded'; + if (this[_constants.K_STATUS] === 'discarded') break; + + /** @private */ + this[_constants.K_COUNTERS].discarded++; + + /** @private */ + this[_constants.K_STATUS] = 'discarded'; this.broker.publish('run', 'run.leave', content); break; } case 'run.leave': { message.ack(); - this[kStatus] = undefined; + /** @private */ + this[_constants.K_STATUS] = undefined; this._deactivateRunConsumers(); this._publishEvent('leave', this._createMessage()); return; @@ -411,9 +538,11 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) } message.ack(); }; + +/** @internal */ Definition.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[_constants.K_STATE_MESSAGE]; switch (stateMessage.fields.routingKey) { case 'run.discarded': case 'run.end': @@ -426,6 +555,8 @@ Definition.prototype._onResumeMessage = function onResumeMessage(message) { this._debug(`resume from ${this.status}`); return this.broker.publish('run', stateMessage.fields.routingKey, (0, _messageHelper.cloneContent)(stateMessage.content), stateMessage.properties); }; + +/** @internal */ Definition.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) { const { content, @@ -449,10 +580,13 @@ Definition.prototype._onExecutionMessage = function onExecutionMessage(routingKe this.broker.publish('run', 'run.end', content); } } - const executeMessage = this[kExecuteMessage]; - this[kExecuteMessage] = null; + const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; + +/** @internal */ Definition.prototype._onApiMessage = function onApiMessage(routingKey, message) { if (message.properties.type === 'stop') { const execution = this.execution; @@ -461,6 +595,8 @@ Definition.prototype._onApiMessage = function onApiMessage(routingKey, message) } } }; + +/** @internal */ Definition.prototype._publishEvent = function publishEvent(action, content, msgOpts) { const execution = this.execution; this.broker.publish('event', `definition.${action}`, execution ? execution._createMessage(content) : (0, _messageHelper.cloneContent)(content), { @@ -468,11 +604,16 @@ Definition.prototype._publishEvent = function publishEvent(action, content, msgO ...msgOpts }); }; + +/** @internal */ Definition.prototype._onStop = function onStop() { - this[kStopped] = true; + /** @private */ + this[_constants.K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop', this._createMessage()); }; + +/** @internal */ Definition.prototype._onBrokerReturnFn = function onBrokerReturn(message) { if (message.properties.type === 'error') { this._deactivateRunConsumers(); @@ -480,12 +621,17 @@ Definition.prototype._onBrokerReturnFn = function onBrokerReturn(message) { throw err; } }; + +/** @internal */ Definition.prototype._reset = function reset() { - this[kExec].delete('executionId'); + /** @private */ + this[_constants.K_EXECUTION].delete('executionId'); this._deactivateRunConsumers(); this.broker.purgeQueue('run-q'); this.broker.purgeQueue('execution-q'); }; + +/** @internal */ Definition.prototype._debug = function debug(msg) { this.logger.debug(`<${this.id}> ${msg}`); }; diff --git a/dist/definition/DefinitionExecution.js b/dist/definition/DefinitionExecution.js index c09da13a..aa0de5e9 100644 --- a/dist/definition/DefinitionExecution.js +++ b/dist/definition/DefinitionExecution.js @@ -7,25 +7,31 @@ exports.default = DefinitionExecution; var _Api = require("../Api.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); -const kActivated = Symbol.for('activated'); -const kProcessesQ = Symbol.for('processesQ'); -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kParent = Symbol.for('definition'); -const kProcesses = Symbol.for('processes'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); +var _constants = require("../constants.js"); +const K_PROCESSES_Q = Symbol.for('processesQ'); +const K_PARENT = Symbol.for('definition'); +const K_PROCESSES = Symbol.for('processes'); + +/** + * Drives the execution of a Definition. Activates executable processes, routes inter-process + * delegate messages and call activity hand-offs, and rolls completion up to the Definition. + * @param {import('types').Definition} definition + * @param {import('types').ContextInstance} context + */ function DefinitionExecution(definition, context) { const broker = definition.broker; - this[kParent] = definition; + + /** @private */ + this[K_PARENT] = definition; this.id = definition.id; this.type = definition.type; this.broker = broker; const environment = this.environment = definition.environment; this.context = context; const processes = context.getProcesses(); + /** @type {Set} */ const ids = new Set(); + /** @type {Set} */ const executable = new Set(); for (const bp of processes) { bp.environment.assignVariables(environment.variables); @@ -33,11 +39,16 @@ function DefinitionExecution(definition, context) { ids.add(bp.id); if (bp.isExecutable) executable.add(bp); } - this[kProcesses] = { + + /** @private */ + this[K_PROCESSES] = { + /** @type {import('../process/Process.js').Process[]} */ processes, ids, executable, + /** @type {Set} */ running: new Set(), + /** @type {Set} */ postponed: new Set() }; broker.assertExchange('execution', 'topic', { @@ -45,12 +56,19 @@ function DefinitionExecution(definition, context) { durable: true }); this.executionId = undefined; - this[kCompleted] = false; - this[kStopped] = false; - this[kActivated] = false; - this[kStatus] = 'init'; - this[kProcessesQ] = undefined; - this[kMessageHandlers] = { + /** @private */ + this[_constants.K_COMPLETED] = false; + /** @private */ + this[_constants.K_STOPPED] = false; + /** @private */ + this[_constants.K_ACTIVATED] = false; + /** @private */ + this[_constants.K_STATUS] = 'init'; + /** @private */ + this[K_PROCESSES_Q] = undefined; + + /** @private */ + this[_constants.K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onCallActivity: this._onCallActivity.bind(this), onCancelCallActivity: this._onCancelCallActivity.bind(this), @@ -63,38 +81,38 @@ function DefinitionExecution(definition, context) { Object.defineProperties(DefinitionExecution.prototype, { stopped: { get() { - return this[kStopped]; + return this[_constants.K_STOPPED]; } }, completed: { get() { - return this[kCompleted]; + return this[_constants.K_COMPLETED]; } }, status: { get() { - return this[kStatus]; + return this[_constants.K_STATUS]; } }, processes: { get() { - return [...this[kProcesses].running]; + return [...this[K_PROCESSES].running]; } }, postponedCount: { get() { - return this[kProcesses].postponed.size; + return this[K_PROCESSES].postponed.size; } }, isRunning: { get() { - return this[kActivated]; + return this[_constants.K_ACTIVATED]; } }, activityStatus: { get() { let status = 'idle'; - const running = this[kProcesses].running; + const running = this[K_PROCESSES].running; if (!running.size) return status; for (const bp of running) { const bpStatus = bp.activityStatus; @@ -115,17 +133,30 @@ Object.defineProperties(DefinitionExecution.prototype, { } } }); + +/** + * Activate executable processes and start the definition execution. Resumes if the message + * is redelivered. When `content.processId` is set, only that process is started. + * @param {import('types').ElementBrokerMessage} executeMessage + * @throws {Error} when message or executionId is missing + */ DefinitionExecution.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new Error('Definition execution requires message'); const content = executeMessage.content; const executionId = this.executionId = content.executionId; if (!executionId) throw new Error('Definition execution requires execution id'); - this[kExecuteMessage] = (0, _messageHelper.cloneMessage)(executeMessage, { + + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage, { executionId, state: 'start' }); - this[kStopped] = false; - this[kProcessesQ] = this.broker.assertQueue(`execute-${executionId}-q`, { + + /** @private */ + this[_constants.K_STOPPED] = false; + + /** @private */ + this[K_PROCESSES_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); @@ -135,7 +166,7 @@ DefinitionExecution.prototype.execute = function execute(executeMessage) { const { running, executable - } = this[kProcesses]; + } = this[K_PROCESSES]; if (content.processId) { const startWithProcess = this.getProcessById(content.processId); if (startWithProcess) { @@ -151,30 +182,45 @@ DefinitionExecution.prototype.execute = function execute(executeMessage) { this._start(); return true; }; + +/** + * Resume after recover by reactivating running processes. + */ DefinitionExecution.prototype.resume = function resume() { - this._debug(`resume ${this[kStatus]} definition execution`); - if (this[kCompleted]) return this._complete('completed'); + this._debug(`resume ${this[_constants.K_STATUS]} definition execution`); + if (this[_constants.K_COMPLETED]) return this._complete('completed'); const { running, postponed - } = this[kProcesses]; + } = this[K_PROCESSES]; this._activate(running); postponed.clear(); - this[kProcessesQ].consume(this[kMessageHandlers].onProcessMessage, { + /** @private */ + this[K_PROCESSES_Q].consume(this[_constants.K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; for (const bp of running) bp.resume(); }; + +/** + * Restore execution state captured by getState. Reinstates running processes from the snapshot. + * @param {import('types').DefinitionExecutionState} [state] + * @returns {this} + */ DefinitionExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - this[kStopped] = state.stopped; - this[kCompleted] = state.completed; - this[kStatus] = state.status; - this._debug(`recover ${this[kStatus]} definition execution`); - const running = this[kProcesses].running; + + /** @private */ + this[_constants.K_STOPPED] = state.stopped; + /** @private */ + this[_constants.K_COMPLETED] = state.completed; + /** @private */ + this[_constants.K_STATUS] = state.status; + this._debug(`recover ${this[_constants.K_STATUS]} definition execution`); + const running = this[K_PROCESSES].running; running.clear(); const ids = new Set(); for (const bpState of state.processes) { @@ -192,52 +238,90 @@ DefinitionExecution.prototype.recover = function recover(state) { } return this; }; + +/** + * Stop the running execution via the api. + */ DefinitionExecution.prototype.stop = function stop() { this.getApi().stop(); }; + +/** + * Get every process in the definition (running first, then any non-running by id). + */ DefinitionExecution.prototype.getProcesses = function getProcesses() { const { running, processes - } = this[kProcesses]; + } = this[K_PROCESSES]; const result = [...running]; for (const bp of processes) { if (!result.find(runningBp => bp.id === runningBp.id)) result.push(bp); } return result; }; + +/** + * @param {string} processId + */ DefinitionExecution.prototype.getProcessById = function getProcessById(processId) { return this.getProcesses().find(bp => bp.id === processId); }; + +/** + * Get every process matching the given id (call activities can spawn duplicates). + * @param {string} processId + */ DefinitionExecution.prototype.getProcessesById = function getProcessesById(processId) { return this.getProcesses().filter(bp => bp.id === processId); }; + +/** + * @param {string} processExecutionId + */ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExecutionId(processExecutionId) { - for (const bp of this[kProcesses].running) { + for (const bp of this[K_PROCESSES].running) { if (bp.executionId === processExecutionId) return bp; } }; + +/** + * Get processes that have an executionId, i.e. are currently running. + */ DefinitionExecution.prototype.getRunningProcesses = function getRunningProcesses() { - return [...this[kProcesses].running].filter(bp => bp.executionId); + return [...this[K_PROCESSES].running].filter(bp => bp.executionId); }; + +/** + * Get processes flagged executable in the definition. + */ DefinitionExecution.prototype.getExecutableProcesses = function getExecutableProcesses() { - return [...this[kProcesses].executable]; + return [...this[K_PROCESSES].executable]; }; + +/** + * Snapshot execution state for recover. + */ DefinitionExecution.prototype.getState = function getState() { const processes = []; - for (const bp of this[kProcesses].running) { + for (const bp of this[K_PROCESSES].running) { processes.push(bp.getState()); } return { executionId: this.executionId, - stopped: this[kStopped], - completed: this[kCompleted], - status: this[kStatus], + stopped: this[_constants.K_STOPPED], + completed: this[_constants.K_COMPLETED], + status: this[_constants.K_STATUS], processes }; }; + +/** + * Resolve a Definition Api or, when the message belongs to a child process, its process Api. + * @param {import('types').ElementBrokerMessage} [apiMessage] + */ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { - if (!apiMessage) apiMessage = this[kExecuteMessage] || { + if (!apiMessage) apiMessage = this[_constants.K_EXECUTE_MESSAGE] || { content: this._createMessage() }; const content = apiMessage.content; @@ -245,7 +329,7 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { return this._getProcessApi(apiMessage); } const api = (0, _Api.DefinitionApi)(this.broker, apiMessage); - const postponed = this[kProcesses].postponed; + const postponed = this[K_PROCESSES].postponed; const self = this; api.getExecuting = function getExecuting() { const apis = []; @@ -257,19 +341,26 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { }; return api; }; + +/** + * List currently postponed activities across every running process. + * @param {import('types').filterPostponed} [filterFn] + */ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { let result = []; - for (const bp of this[kProcesses].running) { + for (const bp of this[K_PROCESSES].running) { result = result.concat(bp.getPostponed(...args)); } return result; }; + +/** @internal */ DefinitionExecution.prototype._start = function start() { const { ids, executable, postponed - } = this[kProcesses]; + } = this[K_PROCESSES]; if (!ids.size) { return this._complete('completed'); } @@ -278,25 +369,33 @@ DefinitionExecution.prototype._start = function start() { error: new Error('No executable process') }); } - this[kStatus] = 'start'; + + /** @private */ + this[_constants.K_STATUS] = 'start'; for (const bp of executable) bp.init(); for (const bp of executable) bp.run(); postponed.clear(); - this[kProcessesQ].assertConsumer(this[kMessageHandlers].onProcessMessage, { + /** @private */ + this[K_PROCESSES_Q].assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}` }); }; + +/** @internal */ DefinitionExecution.prototype._activate = function activate(processList) { - this.broker.subscribeTmp('api', '#', this[kMessageHandlers].onApiMessage, { + this.broker.subscribeTmp('api', '#', this[_constants.K_MESSAGE_HANDLERS].onApiMessage, { noAck: true, consumerTag: '_definition-api-consumer' }); for (const bp of processList) this._activateProcess(bp); - this[kActivated] = true; + /** @private */ + this[_constants.K_ACTIVATED] = true; }; + +/** @internal */ DefinitionExecution.prototype._activateProcess = function activateProcess(bp) { - const handlers = this[kMessageHandlers]; + const handlers = this[_constants.K_MESSAGE_HANDLERS]; const broker = bp.broker; broker.subscribeTmp('message', 'message.outbound', handlers.onMessageOutbound, { noAck: true, @@ -332,11 +431,13 @@ DefinitionExecution.prototype._activateProcess = function activateProcess(bp) { priority: 100 }); }; + +/** @internal */ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, originalMessage) { const message = (0, _messageHelper.cloneMessage)(originalMessage); const content = message.content; const parent = content.parent = content.parent || {}; - const isDirectChild = this[kProcesses].ids.has(content.id); + const isDirectChild = this[K_PROCESSES].ids.has(content.id); if (isDirectChild) { parent.executionId = this.executionId; } else { @@ -347,14 +448,21 @@ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, mandatory: false }); if (!isDirectChild) return; - this[kProcessesQ].queueMessage(message.fields, (0, _messageHelper.cloneContent)(content), message.properties); + + /** @private */ + this[K_PROCESSES_Q].queueMessage(message.fields, (0, _messageHelper.cloneContent)(content), message.properties); }; + +/** @internal */ DefinitionExecution.prototype._deactivate = function deactivate() { this.broker.cancel('_definition-api-consumer'); this.broker.cancel(`_definition-activity-${this.executionId}`); - for (const bp of this[kProcesses].running) this._deactivateProcess(bp); - this[kActivated] = false; + for (const bp of this[K_PROCESSES].running) this._deactivateProcess(bp); + /** @private */ + this[_constants.K_ACTIVATED] = false; }; + +/** @internal */ DefinitionExecution.prototype._deactivateProcess = function deactivateProcess(bp) { bp.broker.cancel('_definition-outbound-message-consumer'); bp.broker.cancel('_definition-activity-consumer'); @@ -362,6 +470,8 @@ DefinitionExecution.prototype._deactivateProcess = function deactivateProcess(bp bp.broker.cancel('_definition-call-consumer'); bp.broker.cancel('_definition-call-cancel-consumer'); }; + +/** @internal */ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(routingKey, message) { const content = message.content; const isRedelivered = message.fields.redelivered; @@ -384,7 +494,8 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout this._stateChangeMessage(message, true); switch (routingKey) { case 'process.enter': - this[kStatus] = 'executing'; + /** @private */ + this[_constants.K_STATUS] = 'executing'; break; case 'process.discarded': { @@ -429,7 +540,7 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout type: 'error' }); } else { - for (const bp of new Set(this[kProcesses].running)) { + for (const bp of new Set(this[K_PROCESSES].running)) { if (bp.id !== childId) bp.stop(); } Object.assign(this.environment.output, content.output); @@ -441,9 +552,11 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout } } }; + +/** @internal */ DefinitionExecution.prototype._stateChangeMessage = function stateChangeMessage(message, postponeMessage) { let previousMsg; - const postponed = this[kProcesses].postponed; + const postponed = this[K_PROCESSES].postponed; for (const msg of postponed) { if (msg.content.executionId === message.content.executionId) { previousMsg = msg; @@ -454,6 +567,8 @@ DefinitionExecution.prototype._stateChangeMessage = function stateChangeMessage( if (previousMsg) previousMsg.ack(); if (postponeMessage) postponed.add(message); }; + +/** @internal */ DefinitionExecution.prototype._onProcessCompleted = function onProcessCompleted(message) { this._stateChangeMessage(message, false); if (message.fields.redelivered) return message.ack(); @@ -473,20 +588,27 @@ DefinitionExecution.prototype._onProcessCompleted = function onProcessCompleted( this._complete('completed'); } }; + +/** @internal */ DefinitionExecution.prototype._onStopped = function onStopped(message) { - const running = this[kProcesses].running; + const running = this[K_PROCESSES].running; this._debug(`stop definition execution (stop process executions ${running.size})`); - this[kProcessesQ].close(); + /** @private */ + this[K_PROCESSES_Q].close(); for (const bp of new Set(running)) bp.stop(); this._deactivate(); - this[kStopped] = true; - return this.broker.publish('execution', `execution.stopped.${this.executionId}`, (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + + /** @private */ + this[_constants.K_STOPPED] = true; + return this.broker.publish('execution', `execution.stopped.${this.executionId}`, (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { ...message.content }), { type: 'stopped', persistent: false }); }; + +/** @internal */ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, message) { const messageType = message.properties.type; const delegate = message.properties.delegate; @@ -498,24 +620,27 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, }); } if (delegate) { - for (const bp of new Set(this[kProcesses].running)) { + for (const bp of new Set(this[K_PROCESSES].running)) { bp.broker.publish('api', routingKey, (0, _messageHelper.cloneContent)(message.content), message.properties); } } if (this.executionId !== message.content.executionId) return; if (messageType === 'stop') { - this[kProcessesQ].queueMessage({ + /** @private */ + this[K_PROCESSES_Q].queueMessage({ routingKey: 'execution.stop' }, (0, _messageHelper.cloneContent)(message.content), { persistent: false }); } }; + +/** @internal */ DefinitionExecution.prototype._startProcessesByMessage = function startProcessesByMessage(reference) { const { processes: bps, running - } = this[kProcesses]; + } = this[K_PROCESSES]; if (bps.length < 2) return; for (const bp of bps) { if (bp.isExecutable) continue; @@ -538,6 +663,8 @@ DefinitionExecution.prototype._startProcessesByMessage = function startProcesses if (reference.referenceType === 'message') return; } }; + +/** @internal */ DefinitionExecution.prototype._onMessageOutbound = function onMessageOutbound(routingKey, message) { const content = message.content; const { @@ -559,11 +686,14 @@ DefinitionExecution.prototype._onMessageOutbound = function onMessageOutbound(ro if (found) return; targetProcess = targetProcess || this.context.getNewProcessById(target.processId); this._activateProcess(targetProcess); - this[kProcesses].running.add(targetProcess); + /** @private */ + this[K_PROCESSES].running.add(targetProcess); targetProcess.init(); targetProcess.run(); targetProcess.sendMessage(message); }; + +/** @internal */ DefinitionExecution.prototype._onCallActivity = function onCallActivity(routingKey, message) { const content = message.content; const { @@ -591,12 +721,15 @@ DefinitionExecution.prototype._onCallActivity = function onCallActivity(routingK if (!targetProcess) return; this._debug(`call from <${fromParent.id}.${fromId}> to <${calledElement}>`); this._activateProcess(targetProcess); - this[kProcesses].running.add(targetProcess); + /** @private */ + this[K_PROCESSES].running.add(targetProcess); targetProcess.init(bpExecutionId); targetProcess.run({ inbound: [(0, _messageHelper.cloneContent)(content)] }); }; + +/** @internal */ DefinitionExecution.prototype._onCancelCallActivity = function onCancelCallActivity(routingKey, message) { const { calledElement, @@ -620,6 +753,8 @@ DefinitionExecution.prototype._onCancelCallActivity = function onCancelCallActiv targetProcess.getApi().discard(); } }; + +/** @internal */ DefinitionExecution.prototype._onDelegateMessage = function onDelegateMessage(routingKey, executeMessage) { const content = executeMessage.content; const messageType = executeMessage.properties.type; @@ -646,19 +781,25 @@ DefinitionExecution.prototype._onDelegateMessage = function onDelegateMessage(ro type: messageType }); }; + +/** @internal */ DefinitionExecution.prototype._removeProcessByExecutionId = function removeProcessByExecutionId(processExecutionId) { const bp = this.getProcessByExecutionId(processExecutionId); - if (bp) this[kProcesses].running.delete(bp); + if (bp) this[K_PROCESSES].running.delete(bp); return bp; }; + +/** @internal */ DefinitionExecution.prototype._complete = function complete(completionType, content, options) { this._deactivate(); - const stateMessage = this[kExecuteMessage]; + const stateMessage = this[_constants.K_EXECUTE_MESSAGE]; this._debug(`definition execution ${completionType} in ${Date.now() - stateMessage.properties.timestamp}ms`); if (!content) content = this._createMessage(); - this[kCompleted] = true; - this[kStatus] = completionType; - this.broker.deleteQueue(this[kProcessesQ].name); + /** @private */ + this[_constants.K_COMPLETED] = true; + /** @private */ + this[_constants.K_STATUS] = completionType; + this.broker.deleteQueue(this[K_PROCESSES_Q].name); return this.broker.publish('execution', `execution.${completionType}.${this.executionId}`, { ...stateMessage.content, output: { @@ -672,15 +813,19 @@ DefinitionExecution.prototype._complete = function complete(completionType, cont ...options }); }; + +/** @internal */ DefinitionExecution.prototype._createMessage = function createMessage(content) { return { id: this.id, type: this.type, executionId: this.executionId, - status: this[kStatus], + status: this[_constants.K_STATUS], ...content }; }; + +/** @internal */ DefinitionExecution.prototype._getProcessApi = function getProcessApi(message) { const content = message.content; let api = this._getProcessApiByExecutionId(content.executionId, message); @@ -694,11 +839,16 @@ DefinitionExecution.prototype._getProcessApi = function getProcessApi(message) { if (api) return api; } }; + +/** @internal */ DefinitionExecution.prototype._getProcessApiByExecutionId = function getProcessApiByExecutionId(parentExecutionId, message) { const processInstance = this.getProcessByExecutionId(parentExecutionId); if (!processInstance) return; return processInstance.getApi(message); }; + +/** @internal */ DefinitionExecution.prototype._debug = function debug(logMessage) { - this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); + /** @private */ + this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; \ No newline at end of file diff --git a/dist/eventDefinitions/CancelEventDefinition.js b/dist/eventDefinitions/CancelEventDefinition.js index 5a0f7797..1469e6df 100644 --- a/dist/eventDefinitions/CancelEventDefinition.js +++ b/dist/eventDefinitions/CancelEventDefinition.js @@ -5,8 +5,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.default = CancelEventDefinition; var _messageHelper = require("../messageHelper.js"); -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); +var _constants = require("../constants.js"); function CancelEventDefinition(activity, eventDefinition) { const { id, @@ -28,15 +27,17 @@ function CancelEventDefinition(activity, eventDefinition) { } Object.defineProperty(CancelEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); CancelEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, @@ -90,10 +91,11 @@ CancelEventDefinition.prototype._onCatchMessage = function onCatchMessage(_, mes return this._complete(content.message); }; CancelEventDefinition.prototype._complete = function complete(output) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); this._debug('completed'); - const content = (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + const content = (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { output, state: 'cancel' }); @@ -103,9 +105,10 @@ CancelEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey switch (message.properties.type) { case 'discard': { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - const content = (0, _messageHelper.cloneContent)(this[kExecuteMessage].content); + const content = (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content); return this.broker.publish('execution', 'execute.discard', content); } case 'stop': diff --git a/dist/eventDefinitions/CompensateEventDefinition.js b/dist/eventDefinitions/CompensateEventDefinition.js index 51d98335..6562deb7 100644 --- a/dist/eventDefinitions/CompensateEventDefinition.js +++ b/dist/eventDefinitions/CompensateEventDefinition.js @@ -6,11 +6,9 @@ Object.defineProperty(exports, "__esModule", { exports.default = CompensateEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageQ = Symbol.for('messageQ'); -const kCompensateQ = Symbol.for('compensateQ'); -const kAssociations = Symbol.for('associations'); +var _constants = require("../constants.js"); +const K_COMPENSATE_Q = Symbol.for('compensateQ'); +const K_ASSOCIATIONS = Symbol.for('associations'); function CompensateEventDefinition(activity, eventDefinition, context) { const { id, @@ -28,14 +26,18 @@ function CompensateEventDefinition(activity, eventDefinition, context) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); if (!isThrowing) { - this[kCompleted] = false; - this[kAssociations] = context.getOutboundAssociations(id); + /** @private */ + this[_constants.K_COMPLETED] = false; + /** @private */ + this[K_ASSOCIATIONS] = context.getOutboundAssociations(id); const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { + /** @private */ + this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - this[kCompensateQ] = broker.assertQueue('compensate-q', { + /** @private */ + this[K_COMPENSATE_Q] = broker.assertQueue('compensate-q', { autoDelete: false, durable: true }); @@ -47,18 +49,21 @@ function CompensateEventDefinition(activity, eventDefinition, context) { } Object.defineProperty(CompensateEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); CompensateEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; CompensateEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[_constants.K_COMPLETED] = false; if (executeMessage.fields.routingKey === 'execute.compensating') { this._debug('resumed at compensating'); - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; return this._compensate(); } const executeContent = executeMessage.content; @@ -74,11 +79,13 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute noAck: true, consumerTag: '_oncollect-messages' }); - this[kMessageQ].consume(this._onCompensateApiMessage.bind(this), { + + /** @private */ + this[_constants.K_MESSAGE_Q].consume(this._onCompensateApiMessage.bind(this), { noAck: true, consumerTag: `_oncompensate-${executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; broker.subscribeTmp('api', `activity.#.${parent.executionId}#`, this._onApiMessage.bind(this), { noAck: true, consumerTag: `_api-${executionId}` @@ -113,15 +120,16 @@ CompensateEventDefinition.prototype._onCollect = function onCollect(routingKey, case 'execute.error': case 'execute.completed': { - return this[kCompensateQ].queueMessage(message.fields, (0, _messageHelper.cloneContent)(message.content), message.properties); + return this[K_COMPENSATE_Q].queueMessage(message.fields, (0, _messageHelper.cloneContent)(message.content), message.properties); } } }; CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompensateApiMessage(routingKey, message) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; const output = message.content.message; const broker = this.broker; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[_constants.K_EXECUTE_MESSAGE].content; this._stopCollect(); this._debug('caught compensate event'); const catchContent = (0, _messageHelper.cloneContent)(executeContent, { @@ -131,7 +139,9 @@ CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompens executionId: executeContent.parent.executionId }); catchContent.parent = (0, _messageHelper.shiftParent)(catchContent.parent); - this[kCompensateQ].queueMessage({ + + /** @private */ + this[K_COMPENSATE_Q].queueMessage({ routingKey: 'execute.compensated' }, (0, _messageHelper.cloneContent)(executeContent)); broker.publish('execution', 'execute.compensating', (0, _messageHelper.cloneContent)(executeContent, { @@ -145,7 +155,7 @@ CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompens return this._compensate(); }; CompensateEventDefinition.prototype._compensate = function compensate() { - return this[kCompensateQ].consume(this._onCollected.bind(this), { + return this[K_COMPENSATE_Q].consume(this._onCollected.bind(this), { noAck: true, consumerTag: '_convey-messages' }); @@ -158,14 +168,16 @@ CompensateEventDefinition.prototype._onCollected = function onCollected(routingK cancelActivity: false })); } - for (const association of this[kAssociations]) association.take((0, _messageHelper.cloneMessage)(message)); + for (const association of this[K_ASSOCIATIONS]) association.take((0, _messageHelper.cloneMessage)(message)); }; CompensateEventDefinition.prototype._onDiscardApiMessage = function onDiscardApiMessage(routingKey, message) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - this[kCompensateQ].purge(); - for (const association of this[kAssociations]) association.discard((0, _messageHelper.cloneMessage)(message)); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content)); + /** @private */ + this[K_COMPENSATE_Q].purge(); + for (const association of this[K_ASSOCIATIONS]) association.discard((0, _messageHelper.cloneMessage)(message)); + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); }; CompensateEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { const messageType = message.properties.type; @@ -190,7 +202,8 @@ CompensateEventDefinition.prototype._stopCollect = function stopCollect() { broker.cancel(`_api-${executionId}`); broker.cancel(`_oncompensate-${executionId}`); broker.cancel('_oncollect-messages'); - this[kMessageQ].purge(); + /** @private */ + this[_constants.K_MESSAGE_Q].purge(); }; CompensateEventDefinition.prototype._stop = function stop() { this._stopCollect(); diff --git a/dist/eventDefinitions/ConditionalEventDefinition.js b/dist/eventDefinitions/ConditionalEventDefinition.js index d05f8d24..8f98cce9 100644 --- a/dist/eventDefinitions/ConditionalEventDefinition.js +++ b/dist/eventDefinitions/ConditionalEventDefinition.js @@ -7,7 +7,7 @@ exports.default = ConditionalEventDefinition; var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); var _condition = require("../condition.js"); -const kExecuteMessage = Symbol.for('executeMessage'); +var _constants = require("../constants.js"); function ConditionalEventDefinition(activity, eventDefinition, _context, index) { const { id, @@ -29,11 +29,12 @@ function ConditionalEventDefinition(activity, eventDefinition, _context, index) } Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); ConditionalEventDefinition.prototype.execute = function execute(executeMessage) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; if (!this.condition) return this._setup(executeMessage); this.evaluate(executeMessage, (err, result) => { this.evaluateCallback(err, result); @@ -94,7 +95,7 @@ ConditionalEventDefinition.prototype.evaluate = function evaluate(message, callb */ ConditionalEventDefinition.prototype.evaluateCallback = function evaluateCallback(err, result) { const broker = this.broker; - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; const executeContent = executeMessage.content; if (err) { return broker.publish('execution', 'execute.error', (0, _messageHelper.cloneContent)(executeContent, { @@ -104,7 +105,7 @@ ConditionalEventDefinition.prototype.evaluateCallback = function evaluateCallbac })); } this._debug(`condition evaluated to ${!!result}`); - this.broker.publish('event', 'activity.condition', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + this.broker.publish('event', 'activity.condition', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { conditionResult: result })); if (!result) return; @@ -166,7 +167,7 @@ ConditionalEventDefinition.prototype._onApiMessage = function onApiMessage(routi { this._stop(); this._debug('discarded'); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { state: 'discard' })); } diff --git a/dist/eventDefinitions/ErrorEventDefinition.js b/dist/eventDefinitions/ErrorEventDefinition.js index 75afbe5b..78008a8b 100644 --- a/dist/eventDefinitions/ErrorEventDefinition.js +++ b/dist/eventDefinitions/ErrorEventDefinition.js @@ -6,11 +6,7 @@ Object.defineProperty(exports, "__esModule", { exports.default = ErrorEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); +var _constants = require("../constants.js"); function ErrorEventDefinition(activity, eventDefinition) { const { id, @@ -34,12 +30,14 @@ function ErrorEventDefinition(activity, eventDefinition) { this.environment = environment; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[kReferenceElement] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing) { - this[kCompleted] = false; + /** @private */ + this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { + /** @private */ + this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); @@ -51,27 +49,31 @@ function ErrorEventDefinition(activity, eventDefinition) { } Object.defineProperty(ErrorEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); ErrorEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent?.executionId; - const info = this[kReferenceInfo] = this._getReferenceInfo(executeMessage); - this[kMessageQ].consume(this._onThrowApiMessage.bind(this), { + const info = this[_constants.K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage); + + /** @private */ + this[_constants.K_MESSAGE_Q].consume(this._onThrowApiMessage.bind(this), { noAck: true, consumerTag: `_onthrow-${executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; this._debug(`expect ${info.description}`); const broker = this.broker; broker.subscribeTmp('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { @@ -92,7 +94,7 @@ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessa ...info.message } })); - if (this[kCompleted]) return this._stop(); + if (this[_constants.K_COMPLETED]) return this._stop(); } const waitContent = (0, _messageHelper.cloneContent)(executeContent, { executionId: parentExecutionId, @@ -132,24 +134,25 @@ ErrorEventDefinition.prototype.executeThrow = function executeThrow(executeMessa }; ErrorEventDefinition.prototype._onErrorMessage = function onErrorMessage(routingKey, message) { const error = message.content.error; - if (!this[kReferenceElement]) return this._catchError(routingKey, message, error); + if (!this[_constants.K_REFERENCE_ELEMENT]) return this._catchError(routingKey, message, error); if (!error) return; - const info = this[kReferenceInfo]; + const info = this[_constants.K_REFERENCE_INFO]; if ('' + error.code !== '' + info.message.code) return; return this._catchError(routingKey, message, error); }; ErrorEventDefinition.prototype._onThrowApiMessage = function onThrowApiMessage(routingKey, message) { const error = message.content.message; - if (!this[kReferenceElement]) return this._catchError(routingKey, message, error); - const info = this[kReferenceInfo]; + if (!this[_constants.K_REFERENCE_ELEMENT]) return this._catchError(routingKey, message, error); + const info = this[_constants.K_REFERENCE_INFO]; if (info.message.id !== error?.id) return; return this._catchError(routingKey, message, error); }; ErrorEventDefinition.prototype._catchError = function catchError(routingKey, message, error) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - this._debug(`caught ${this[kReferenceInfo].description}`); - const executeContent = this[kExecuteMessage].content; + this._debug(`caught ${this[_constants.K_REFERENCE_INFO].description}`); + const executeContent = this[_constants.K_EXECUTE_MESSAGE].content; const parent = executeContent.parent; const catchContent = (0, _messageHelper.cloneContent)(executeContent, { source: { @@ -176,9 +179,10 @@ ErrorEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, switch (messageType) { case 'discard': { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content)); + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); } case 'stop': { @@ -193,10 +197,11 @@ ErrorEventDefinition.prototype._stop = function stop() { broker.cancel(`_onthrow-${executionId}`); broker.cancel(`_onerror-${executionId}`); broker.cancel(`_api-${executionId}`); - this[kMessageQ].purge(); + /** @private */ + this[_constants.K_MESSAGE_Q].purge(); }; ErrorEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[_constants.K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { diff --git a/dist/eventDefinitions/EscalationEventDefinition.js b/dist/eventDefinitions/EscalationEventDefinition.js index e81b4fca..4bdf5de5 100644 --- a/dist/eventDefinitions/EscalationEventDefinition.js +++ b/dist/eventDefinitions/EscalationEventDefinition.js @@ -7,12 +7,9 @@ exports.default = EscalationEventDefinition; var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReference = Symbol.for('reference'); +const K_REFERENCE = Symbol.for('reference'); function EscalationEventDefinition(activity, eventDefinition) { const { id, @@ -35,12 +32,14 @@ function EscalationEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[kReferenceElement] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing) { - this[kCompleted] = false; + /** @private */ + this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { + /** @private */ + this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); @@ -52,27 +51,30 @@ function EscalationEventDefinition(activity, eventDefinition) { } Object.defineProperty(EscalationEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); EscalationEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; EscalationEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; - const info = this[kReference] = this._getReferenceInfo(executeMessage); + const info = this[K_REFERENCE] = this._getReferenceInfo(executeMessage); const broker = this.broker; - this[kMessageQ].consume(this._onCatchMessage.bind(this), { + /** @private */ + this[_constants.K_MESSAGE_Q].consume(this._onCatchMessage.bind(this), { noAck: true, consumerTag: `_onescalate-${executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; broker.subscribeTmp('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { noAck: true, consumerTag: `_api-${executionId}` @@ -110,13 +112,14 @@ EscalationEventDefinition.prototype.executeThrow = function executeThrow(execute return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); }; EscalationEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { - const info = this[kReference]; + const info = this[K_REFERENCE]; if ((0, _getPropertyValue.default)(message, 'content.message.id') !== info.message.id) return; const output = message.content.message; - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); this._debug(`caught ${info.description}`); - const executeContent = this[kExecuteMessage].content; + const executeContent = this[_constants.K_EXECUTE_MESSAGE].content; const { parent, ...content @@ -145,9 +148,10 @@ EscalationEventDefinition.prototype._onApiMessage = function onApiMessage(routin } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content)); + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); } case 'stop': { @@ -163,7 +167,7 @@ EscalationEventDefinition.prototype._stop = function stop() { broker.cancel(`_onescalate-${executionId}`); }; EscalationEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[_constants.K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { diff --git a/dist/eventDefinitions/EventDefinitionExecution.js b/dist/eventDefinitions/EventDefinitionExecution.js index a6e6cfcc..32672b4f 100644 --- a/dist/eventDefinitions/EventDefinitionExecution.js +++ b/dist/eventDefinitions/EventDefinitionExecution.js @@ -5,28 +5,29 @@ Object.defineProperty(exports, "__esModule", { }); exports.default = EventDefinitionExecution; var _messageHelper = require("../messageHelper.js"); -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kStopped = Symbol.for('stopped'); +var _constants = require("../constants.js"); function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKey = 'execute.completed') { this.id = activity.id; this.activity = activity; this.broker = activity.broker; this.eventDefinitions = eventDefinitions; this.completedRoutingKey = completedRoutingKey; - this[kCompleted] = false; - this[kStopped] = false; - this[kExecuteMessage] = null; + /** @private */ + this[_constants.K_COMPLETED] = false; + /** @private */ + this[_constants.K_STOPPED] = false; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = null; } Object.defineProperties(EventDefinitionExecution.prototype, { completed: { get() { - return this[kCompleted]; + return this[_constants.K_COMPLETED]; } }, stopped: { get() { - return this[kStopped]; + return this[_constants.K_STOPPED]; } } }); @@ -35,7 +36,9 @@ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { if (content.isDefinitionScope) return this._executeDefinition(executeMessage); if (!content.isRootScope) return; const broker = this.broker; - this[kExecuteMessage] = executeMessage; + + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const executionId = content.executionId; broker.subscribeTmp('execution', 'execute.#', this._onExecuteMessage.bind(this), { noAck: true, @@ -54,8 +57,8 @@ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { const parent = (0, _messageHelper.unshiftParent)(content.parent, content); const eventDefinitions = this.eventDefinitions; for (let index = 0; index < eventDefinitions.length; ++index) { - if (this[kCompleted]) break; - if (this[kStopped]) break; + if (this[_constants.K_COMPLETED]) break; + if (this[_constants.K_STOPPED]) break; const ed = eventDefinitions[index]; const edExecutionId = `${executionId}_${index}`; this._debug(executionId, `start event definition ${ed.type}, index ${index}`); @@ -109,10 +112,11 @@ EventDefinitionExecution.prototype._complete = function complete(message) { index, parent } = message.content; - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._debug(executionId, `event definition ${type} completed, index ${index}`); const completeContent = (0, _messageHelper.cloneContent)(message.content, { - executionId: this[kExecuteMessage].content.executionId, + executionId: this[_constants.K_EXECUTE_MESSAGE].content.executionId, isRootScope: true, isDefinitionScope: undefined }); @@ -132,7 +136,8 @@ EventDefinitionExecution.prototype._executeDefinition = function executeDefiniti ed.execute(message); }; EventDefinitionExecution.prototype._stop = function stop() { - this[kStopped] = true; + /** @private */ + this[_constants.K_STOPPED] = true; this.broker.cancel('_eventdefinition-execution-execute-tag'); this.broker.cancel('_eventdefinition-execution-api-tag'); }; diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index f2ba54eb..9407b2d2 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { exports.default = LinkEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); -const kExecuteMessage = Symbol.for('executeMessage'); +var _constants = require("../constants.js"); function LinkEventDefinition(activity, eventDefinition) { const { id, @@ -66,14 +66,15 @@ function LinkEventDefinition(activity, eventDefinition) { } Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); LinkEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; const { executionId, diff --git a/dist/eventDefinitions/MessageEventDefinition.js b/dist/eventDefinitions/MessageEventDefinition.js index c8686434..812ce2c0 100644 --- a/dist/eventDefinitions/MessageEventDefinition.js +++ b/dist/eventDefinitions/MessageEventDefinition.js @@ -7,12 +7,8 @@ exports.default = MessageEventDefinition; var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); function MessageEventDefinition(activity, eventDefinition) { const { id, @@ -35,12 +31,14 @@ function MessageEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[kReferenceElement] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing) { - this[kCompleted] = false; + /** @private */ + this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { + /** @private */ + this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); @@ -51,30 +49,33 @@ function MessageEventDefinition(activity, eventDefinition) { } Object.defineProperty(MessageEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); MessageEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent?.executionId; - const info = this[kReferenceInfo] = this._getReferenceInfo(executeMessage); + const info = this[_constants.K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage); this._debug(`expect ${info.description}`); const broker = this.broker; const onCatchMessage = this._onCatchMessage.bind(this); - this[kMessageQ].consume(onCatchMessage, { + /** @private */ + this[_constants.K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-message-${executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; const onApiMessage = this._onApiMessage.bind(this); broker.subscribeTmp('api', `activity.#.${executionId}`, onApiMessage, { noAck: true, @@ -124,12 +125,12 @@ MessageEventDefinition.prototype.executeThrow = function executeThrow(executeMes return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); }; MessageEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { - if ((0, _getPropertyValue.default)(message, 'content.message.id') !== this[kReferenceInfo].message.id) return; + if ((0, _getPropertyValue.default)(message, 'content.message.id') !== this[_constants.K_REFERENCE_INFO].message.id) return; const { type, correlationId } = message.properties; - this.broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + this.broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { message: { ...message.content.message } @@ -156,9 +157,10 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content), { + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content), { correlationId }); } @@ -169,11 +171,12 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe } }; MessageEventDefinition.prototype._complete = function complete(verb, output, options) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - this._debug(`${verb} ${this[kReferenceInfo].description}`); + this._debug(`${verb} ${this[_constants.K_REFERENCE_INFO].description}`); const broker = this.broker; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[_constants.K_EXECUTE_MESSAGE].content; const catchContent = (0, _messageHelper.cloneContent)(executeContent, { message: { ...output @@ -196,10 +199,11 @@ MessageEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-${executionId}`); broker.cancel(`_api-parent-${executionId}`); broker.cancel(`_api-delegated-${executionId}`); - this[kMessageQ].purge(); + /** @private */ + this[_constants.K_MESSAGE_Q].purge(); }; MessageEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[_constants.K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { diff --git a/dist/eventDefinitions/SignalEventDefinition.js b/dist/eventDefinitions/SignalEventDefinition.js index d7483ec7..ad2793e3 100644 --- a/dist/eventDefinitions/SignalEventDefinition.js +++ b/dist/eventDefinitions/SignalEventDefinition.js @@ -7,12 +7,8 @@ exports.default = SignalEventDefinition; var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); function SignalEventDefinition(activity, eventDefinition) { const { id, @@ -36,12 +32,14 @@ function SignalEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[kReferenceElement] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing && isStart) { - this[kCompleted] = false; + /** @private */ + this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { + /** @private */ + this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); @@ -52,30 +50,33 @@ function SignalEventDefinition(activity, eventDefinition) { } Object.defineProperty(SignalEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); SignalEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent?.executionId; - const info = this[kReferenceInfo] = this._getReferenceInfo(executeMessage); + const info = this[_constants.K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage); const broker = this.broker; const onCatchMessage = this._onCatchMessage.bind(this); if (this.activity.isStart) { - this[kMessageQ].consume(onCatchMessage, { + /** @private */ + this[_constants.K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-signal-${executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; } const onApiMessage = this._onApiMessage.bind(this); broker.subscribeTmp('api', `activity.#.${parentExecutionId}`, onApiMessage, { @@ -125,15 +126,16 @@ SignalEventDefinition.prototype.executeThrow = function executeThrow(executeMess return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); }; SignalEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { - const info = this[kReferenceInfo]; + const info = this[_constants.K_REFERENCE_INFO]; if ((0, _getPropertyValue.default)(message, 'content.message.id') !== info.message.id) return; - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); const { type, correlationId } = message.properties; - this.broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + this.broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { message: { ...message.content.message } @@ -157,9 +159,10 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content), { + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content), { correlationId }); } @@ -171,10 +174,11 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey } }; SignalEventDefinition.prototype._complete = function complete(output, options) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - this._debug(`signaled with ${this[kReferenceInfo].description}`); - return this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + this._debug(`signaled with ${this[_constants.K_REFERENCE_INFO].description}`); + return this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { output, state: 'signal' }), options); @@ -186,10 +190,10 @@ SignalEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-parent-${executionId}`); broker.cancel(`_api-${executionId}`); broker.cancel(`_api-delegated-${executionId}`); - if (this.activity.isStart) this[kMessageQ].purge(); + if (this.activity.isStart) this[_constants.K_MESSAGE_Q].purge(); }; SignalEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[_constants.K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { diff --git a/dist/eventDefinitions/TimerEventDefinition.js b/dist/eventDefinitions/TimerEventDefinition.js index 8d311faa..ac2249d3 100644 --- a/dist/eventDefinitions/TimerEventDefinition.js +++ b/dist/eventDefinitions/TimerEventDefinition.js @@ -7,9 +7,9 @@ exports.default = TimerEventDefinition; var _piso = require("@0dep/piso"); var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); -const kStopped = Symbol.for('stopped'); -const kTimerContent = Symbol.for('timerContent'); -const kTimer = Symbol.for('timer'); +var _constants = require("../constants.js"); +const K_TIMER_CONTENT = Symbol.for('timerContent'); +const K_TIMER = Symbol.for('timer'); const timerTypes = new Set(['timeDuration', 'timeDate', 'timeCycle']); function TimerEventDefinition(activity, eventDefinition) { const type = this.type = eventDefinition.type || 'TimerEventDefinition'; @@ -26,23 +26,26 @@ function TimerEventDefinition(activity, eventDefinition) { if (timeDate) this.timeDate = timeDate; this.broker = activity.broker; this.logger = environment.Logger(type.toLowerCase()); - this[kStopped] = false; - this[kTimer] = null; + + /** @private */ + this[_constants.K_STOPPED] = false; + /** @private */ + this[K_TIMER] = null; } Object.defineProperties(TimerEventDefinition.prototype, { executionId: { get() { - return this[kTimerContent]?.executionId; + return this[K_TIMER_CONTENT]?.executionId; } }, stopped: { get() { - return this[kStopped]; + return this[_constants.K_STOPPED]; } }, timer: { get() { - return this[kTimer]; + return this[K_TIMER]; } } }); @@ -51,12 +54,13 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { routingKey: executeKey, redelivered: isResumed } = executeMessage.fields; - const timer = this[kTimer]; + const timer = this[K_TIMER]; if (timer && executeKey === 'execute.timer') { return; } - if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer); - this[kStopped] = false; + if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); + /** @private */ + this[_constants.K_STOPPED] = false; const content = executeMessage.content; const executionId = content.executionId; const startedAt = this.startedAt = 'startedAt' in content ? new Date(content.startedAt) : new Date(); @@ -67,7 +71,7 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { this.logger.error(`<${executionId} (${this.activity.id})> failed to get timeout delay: ${err}`); throw new _Errors.RunError(err.message, executeMessage, err); } - const timerContent = this[kTimerContent] = (0, _messageHelper.cloneContent)(content, { + const timerContent = this[K_TIMER_CONTENT] = (0, _messageHelper.cloneContent)(content, { ...resolvedTimer, ...(isResumed && { isResumed @@ -91,7 +95,8 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { if (timerContent.timeout <= 0) return this._completed(); const timers = this.environment.timers.register(timerContent); const delay = timerContent.timeout; - this[kTimer] = timers.setTimeout(this._completed.bind(this), delay, { + /** @private */ + this[K_TIMER] = timers.setTimeout(this._completed.bind(this), delay, { id: content.id, type: this.type, executionId, @@ -100,15 +105,15 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { this._debug(`set timeout with delay ${delay}`); }; TimerEventDefinition.prototype.stop = function stopTimer() { - const timer = this[kTimer]; - if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer); + const timer = this[K_TIMER]; + if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); }; TimerEventDefinition.prototype._completed = function completed(completeContent, options) { this._stop(); const stoppedAt = new Date(); const runningTime = stoppedAt.getTime() - this.startedAt.getTime(); this._debug(`completed in ${runningTime}ms`); - const timerContent = this[kTimerContent]; + const timerContent = this[K_TIMER_CONTENT]; const content = { stoppedAt, runningTime, @@ -144,7 +149,7 @@ TimerEventDefinition.prototype._onDelegatedApiMessage = function onDelegatedApiM type, correlationId } = message.properties; - this.broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(this[kTimerContent], { + this.broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(this[K_TIMER_CONTENT], { message: { ...content.message } @@ -181,7 +186,7 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, { this._stop(); this._debug('discarded'); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kTimerContent], { + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[K_TIMER_CONTENT], { state: 'discard' }), { correlationId @@ -190,9 +195,10 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, } }; TimerEventDefinition.prototype._stop = function stop() { - this[kStopped] = true; - const timer = this[kTimer]; - if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer); + /** @private */ + this[_constants.K_STOPPED] = true; + const timer = this[K_TIMER]; + if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); const broker = this.broker; broker.cancel(`_api-${this.executionId}`); broker.cancel(`_api-delegated-${this.executionId}`); diff --git a/dist/events/BoundaryEvent.js b/dist/events/BoundaryEvent.js index 426bbc3e..87a91e3b 100644 --- a/dist/events/BoundaryEvent.js +++ b/dist/events/BoundaryEvent.js @@ -9,12 +9,11 @@ var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); var _messageHelper = require("../messageHelper.js"); var _shared = require("../shared.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kAttachedTags = Symbol.for('attachedConsumers'); -const kCompleteContent = Symbol.for('completeContent'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kExecution = Symbol.for('execution'); -const kShovels = Symbol.for('shovels'); +const K_ATTACHED_TAGS = Symbol.for('attachedConsumers'); +const K_COMPLETE_CONTENT = Symbol.for('completeContent'); +const K_SHOVELS = Symbol.for('shovels'); function BoundaryEvent(activityDef, context) { return new _Activity.default(BoundaryEventBehaviour, activityDef, context); } @@ -25,14 +24,17 @@ function BoundaryEventBehaviour(activity) { this.activity = activity; this.environment = activity.environment; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions, 'execute.bound.completed'); - this[kShovels] = new Set(); - this[kAttachedTags] = new Set(); + /** @private */ + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions, 'execute.bound.completed'); + /** @private */ + this[K_SHOVELS] = new Set(); + /** @private */ + this[K_ATTACHED_TAGS] = new Set(); } Object.defineProperties(BoundaryEventBehaviour.prototype, { executionId: { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }, cancelActivity: { @@ -47,9 +49,10 @@ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { isRootScope, executionId } = executeMessage.content; - const eventDefinitionExecution = this[kExecution]; + const eventDefinitionExecution = this[_constants.K_EXECUTION]; if (isRootScope && executeMessage.content.id === this.id) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const broker = this.broker; if (executeMessage.fields.routingKey === 'execute.bound.completed') { this._stop(); @@ -61,7 +64,8 @@ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { consumerTag, priority: 300 }); - this[kAttachedTags].add(consumerTag); + /** @private */ + this[K_ATTACHED_TAGS].add(consumerTag); broker.subscribeOnce('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { consumerTag: `_api-${executionId}` }); @@ -108,17 +112,20 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, { cancelActivity: false })); } - this[kCompleteContent] = content; + + /** @private */ + this[K_COMPLETE_CONTENT] = content; const { inbound, executionId - } = this[kExecuteMessage].content; + } = this[_constants.K_EXECUTE_MESSAGE].content; const attachedToContent = inbound?.[0]; const attachedTo = this.attachedTo; this.activity.logger.debug(`<${executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`); if (content.isRecovered && !attachedTo.isRunning) { const attachedExecuteTag = `_on-attached-execute-${executionId}`; - this[kAttachedTags].add(attachedExecuteTag); + /** @private */ + this[K_ATTACHED_TAGS].add(attachedExecuteTag); attachedTo.broker.subscribeOnce('execution', '#', () => { attachedTo.getApi({ content: attachedToContent @@ -137,8 +144,8 @@ BoundaryEventBehaviour.prototype._onAttachedLeave = function onAttachedLeave(_, }) { if (content.id !== this.attachedTo.id) return; this._stop(); - const completeContent = this[kCompleteContent]; - if (!completeContent) return this.broker.publish('execution', 'execute.discard', this[kExecuteMessage].content); + const completeContent = this[K_COMPLETE_CONTENT]; + if (!completeContent) return this.broker.publish('execution', 'execute.discard', this[_constants.K_EXECUTE_MESSAGE].content); return this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(completeContent)); }; BoundaryEventBehaviour.prototype._onExpectMessage = function onExpectMessage(_, { @@ -152,7 +159,8 @@ BoundaryEventBehaviour.prototype._onExpectMessage = function onExpectMessage(_, } = content; const attachedTo = this.attachedTo; const errorConsumerTag = `_bound-error-listener-${executionId}`; - this[kAttachedTags].add(errorConsumerTag); + /** @private */ + this[K_ATTACHED_TAGS].add(errorConsumerTag); attachedTo.broker.subscribeTmp('event', pattern, (__, message) => { if (message.content.id !== attachedTo.id) return; this.broker.publish(exchange, expectRoutingKey, (0, _messageHelper.cloneContent)(message.content, { @@ -172,7 +180,7 @@ BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_, const { executionId, parent - } = this[kExecuteMessage].content; + } = this[_constants.K_EXECUTE_MESSAGE].content; const id = this.id, attachedTo = this.attachedTo; this.activity.logger.debug(`<${executionId} (${id})> detach from activity <${attachedTo.id}>`); @@ -184,7 +192,8 @@ BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_, sourcePattern } = content; const shovelName = `_detached-${(0, _shared.brokerSafeId)(id)}_${detachId}`; - this[kShovels].add(shovelName); + /** @private */ + this[K_SHOVELS].add(shovelName); const broker = this.broker; attachedTo.broker.createShovel(shovelName, { exchange: sourceExchange, @@ -219,7 +228,7 @@ BoundaryEventBehaviour.prototype._onApiMessage = function onApiMessage(_, messag } }; BoundaryEventBehaviour.prototype._onRepeatMessage = function onRepeatMessage(_, message) { - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; const repeat = message.content.repeat; this.broker.getQueue('inbound-q').queueMessage({ routingKey: 'activity.restart' @@ -231,10 +240,12 @@ BoundaryEventBehaviour.prototype._stop = function stop(detach) { const attachedTo = this.attachedTo, broker = this.broker, executionId = this.executionId; - for (const tag of this[kAttachedTags]) attachedTo.broker.cancel(tag); - this[kAttachedTags].clear(); - for (const shovelName of this[kShovels]) attachedTo.broker.closeShovel(shovelName); - this[kShovels].clear(); + for (const tag of this[K_ATTACHED_TAGS]) attachedTo.broker.cancel(tag); + /** @private */ + this[K_ATTACHED_TAGS].clear(); + for (const shovelName of this[K_SHOVELS]) attachedTo.broker.closeShovel(shovelName); + /** @private */ + this[K_SHOVELS].clear(); broker.cancel('_execution-tag'); broker.cancel(`_execution-completed-${executionId}`); if (detach) return; diff --git a/dist/events/EndEvent.js b/dist/events/EndEvent.js index b7696c76..ec1c7018 100644 --- a/dist/events/EndEvent.js +++ b/dist/events/EndEvent.js @@ -8,8 +8,8 @@ exports.default = EndEvent; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kExecution = Symbol.for('execution'); function EndEvent(activityDef, context) { return new _Activity.default(EndEventBehaviour, { ...activityDef, @@ -20,10 +20,11 @@ function EndEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + /** @private */ + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); } EndEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[_constants.K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } diff --git a/dist/events/IntermediateCatchEvent.js b/dist/events/IntermediateCatchEvent.js index 5cce1b38..aa72a938 100644 --- a/dist/events/IntermediateCatchEvent.js +++ b/dist/events/IntermediateCatchEvent.js @@ -8,8 +8,8 @@ exports.default = IntermediateCatchEvent; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kExecution = Symbol.for('execution'); function IntermediateCatchEvent(activityDef, context) { return new _Activity.default(IntermediateCatchEventBehaviour, { ...activityDef, @@ -20,10 +20,11 @@ function IntermediateCatchEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + /** @private */ + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); } IntermediateCatchEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[_constants.K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } diff --git a/dist/events/IntermediateThrowEvent.js b/dist/events/IntermediateThrowEvent.js index 9cb5bf58..36a02b00 100644 --- a/dist/events/IntermediateThrowEvent.js +++ b/dist/events/IntermediateThrowEvent.js @@ -8,8 +8,8 @@ exports.default = IntermediateThrowEvent; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kExecution = Symbol.for('execution'); function IntermediateThrowEvent(activityDef, context) { return new _Activity.default(IntermediateThrowEventBehaviour, { ...activityDef, @@ -20,10 +20,11 @@ function IntermediateThrowEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + /** @private */ + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); } IntermediateThrowEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[_constants.K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } diff --git a/dist/events/StartEvent.js b/dist/events/StartEvent.js index b66b9788..f6a594f8 100644 --- a/dist/events/StartEvent.js +++ b/dist/events/StartEvent.js @@ -8,9 +8,8 @@ exports.default = StartEvent; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kExecuteMessage = Symbol.for('executeMessage'); -const kExecution = Symbol.for('execution'); function StartEvent(activityDef, context) { return new _Activity.default(StartEventBehaviour, activityDef, context); } @@ -19,15 +18,16 @@ function StartEventBehaviour(activity) { this.type = activity.type; this.activity = activity; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + /** @private */ + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); } Object.defineProperty(StartEventBehaviour.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); StartEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[_constants.K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } @@ -37,7 +37,8 @@ StartEventBehaviour.prototype.execute = function execute(executeMessage) { return broker.publish('execution', 'execute.completed', content); } const executionId = content.executionId; - this[kExecuteMessage] = executeMessage; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; broker.subscribeTmp('api', `activity.#.${executionId}`, (...args) => this._onApiMessage(...args), { noAck: true, consumerTag: `_api-${executionId}`, @@ -64,7 +65,7 @@ StartEventBehaviour.prototype._onApiMessage = function onApiMessage(routingKey, case 'signal': { this._stop(); - const content = this[kExecuteMessage].content; + const content = this[_constants.K_EXECUTE_MESSAGE].content; return this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(content, { output: message.content.message, state: 'signal' @@ -75,7 +76,7 @@ StartEventBehaviour.prototype._onApiMessage = function onApiMessage(routingKey, case 'discard': { this._stop(); - const content = this[kExecuteMessage].content; + const content = this[_constants.K_EXECUTE_MESSAGE].content; return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(content), { correlationId }); @@ -95,7 +96,7 @@ StartEventBehaviour.prototype._onDelegatedApiMessage = function onDelegatedApiMe type, correlationId } = message.properties; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[_constants.K_EXECUTE_MESSAGE].content; this.broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(executeContent, { message: { ...content.message diff --git a/dist/flows/Association.js b/dist/flows/Association.js index 22b03eb5..2ff3464f 100644 --- a/dist/flows/Association.js +++ b/dist/flows/Association.js @@ -8,7 +8,13 @@ var _messageHelper = require("../messageHelper.js"); var _EventBroker = require("../EventBroker.js"); var _Api = require("../Api.js"); var _shared = require("../shared.js"); -const kCounters = Symbol.for('counters'); +var _constants = require("../constants.js"); +/** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * @param {import('moddle-context-serializer').SerializableElement} associationDef + * @param {import('types').ContextInstance} context + */ function Association(associationDef, { environment }) { @@ -31,7 +37,9 @@ function Association(associationDef, { this.isAssociation = true; this.environment = environment; const logger = this.logger = environment.Logger(type.toLowerCase()); - this[kCounters] = { + + /** @private */ + this[_constants.K_COUNTERS] = { take: 0, discard: 0 }; @@ -52,24 +60,41 @@ function Association(associationDef, { logger.debug(`<${id}> init, <${sourceId}> -> <${targetId}>`); } Object.defineProperty(Association.prototype, 'counters', { + /** @returns {{ take: number, discard: number }} */ get() { return { - ...this[kCounters] + ...this[_constants.K_COUNTERS] }; } }); + +/** + * Take the association and publish association.take. + * @param {Record} [content] + */ Association.prototype.take = function take(content) { this.logger.debug(`<${this.id}> take target <${this.targetId}>`); - ++this[kCounters].take; + ++this[_constants.K_COUNTERS].take; this._publishEvent('take', content); return true; }; + +/** + * Discard the association and publish association.discard. + * @param {Record} [content] + */ Association.prototype.discard = function discard(content) { this.logger.debug(`<${this.id}> discard target <${this.targetId}>`); - ++this[kCounters].discard; + ++this[_constants.K_COUNTERS].discard; this._publishEvent('discard', content); return true; }; + +/** + * Snapshot association state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * @returns {import('types').AssociationState | undefined} + */ Association.prototype.getState = function getState() { const brokerState = this.broker.getState(true); if (!brokerState && this.environment.settings.disableTrackState) return; @@ -80,18 +105,34 @@ Association.prototype.getState = function getState() { broker: brokerState }; }; + +/** + * Restore association state captured by getState. + * @param {import('types').AssociationState} state + */ Association.prototype.recover = function recover(state) { - Object.assign(this[kCounters], state.counters); + Object.assign(this[_constants.K_COUNTERS], state.counters); this.broker.recover(state.broker); }; + +/** + * Resolve an association-scoped Api wrapper. + * @param {import('types').ElementBrokerMessage} [message] + */ Association.prototype.getApi = function getApi(message) { return new _Api.Api('association', this.broker, message || { content: this._createMessageContent() }); }; + +/** + * Stop the association's broker. + */ Association.prototype.stop = function stop() { this.broker.stop(); }; + +/** @internal */ Association.prototype._publishEvent = function publishEvent(action, content) { const eventContent = this._createMessageContent({ action, @@ -102,6 +143,8 @@ Association.prototype._publishEvent = function publishEvent(action, content) { type: action }); }; + +/** @internal */ Association.prototype._createMessageContent = function createMessageContent(override) { return { ...override, diff --git a/dist/flows/MessageFlow.js b/dist/flows/MessageFlow.js index 9cd68b8c..fedc0ff1 100644 --- a/dist/flows/MessageFlow.js +++ b/dist/flows/MessageFlow.js @@ -8,8 +8,16 @@ var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _EventBroker = require("../EventBroker.js"); var _Api = require("../Api.js"); -const kCounters = Symbol.for('counters'); -const kSourceElement = Symbol.for('sourceElement'); +var _constants = require("../constants.js"); +const K_SOURCE_ELEMENT = Symbol.for('sourceElement'); + +/** + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('types').ContextInstance} context + */ function MessageFlow(flowDef, context) { const { id, @@ -29,7 +37,9 @@ function MessageFlow(flowDef, context) { this.behaviour = behaviour; this.environment = context.environment; this.context = context; - this[kCounters] = { + + /** @private */ + this[_constants.K_COUNTERS] = { messages: 0 }; const { @@ -44,16 +54,25 @@ function MessageFlow(flowDef, context) { this.once = once; this.emit = emit; this.waitFor = waitFor; - this[kSourceElement] = context.getActivityById(source.id) || context.getProcessById(source.processId); + + /** @private */ + this[K_SOURCE_ELEMENT] = context.getActivityById(source.id) || context.getProcessById(source.processId); this.logger = context.environment.Logger(type.toLowerCase()); } Object.defineProperty(MessageFlow.prototype, 'counters', { + /** @returns {{ messages: number }} */ get() { return { - ...this[kCounters] + ...this[_constants.K_COUNTERS] }; } }); + +/** + * Snapshot message-flow state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * @returns {import('types').MessageFlowState | undefined} + */ MessageFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); if (!brokerState && this.environment.settings.disableTrackState) return; @@ -64,17 +83,31 @@ MessageFlow.prototype.getState = function getState() { broker: brokerState }; }; + +/** + * Restore message-flow state captured by getState. + * @param {import('types').MessageFlowState} state + */ MessageFlow.prototype.recover = function recover(state) { - Object.assign(this[kCounters], state.counters); + Object.assign(this[_constants.K_COUNTERS], state.counters); this.broker.recover(state.broker); }; + +/** + * Resolve a message-scoped Api wrapper. + * @param {import('types').ElementBrokerMessage} [message] + */ MessageFlow.prototype.getApi = function getApi(message) { return new _Api.Api('message', this.broker, message || { content: this._createMessageContent() }); }; + +/** + * Subscribe to the source element's message and end events to bridge the message across. + */ MessageFlow.prototype.activate = function activate() { - const sourceElement = this[kSourceElement]; + const sourceElement = this[K_SOURCE_ELEMENT]; const safeId = (0, _shared.brokerSafeId)(this.id); sourceElement.on('message', this.deactivate.bind(this), { consumerTag: `_message-on-message-${safeId}` @@ -83,21 +116,29 @@ MessageFlow.prototype.activate = function activate() { consumerTag: `_message-on-end-${safeId}` }); }; + +/** + * Cancel the source element subscriptions added by activate. + */ MessageFlow.prototype.deactivate = function deactivate() { - const sourceElement = this[kSourceElement]; + const sourceElement = this[K_SOURCE_ELEMENT]; const safeId = (0, _shared.brokerSafeId)(this.id); sourceElement.broker.cancel(`_message-on-end-${safeId}`); sourceElement.broker.cancel(`_message-on-message-${safeId}`); }; + +/** @internal */ MessageFlow.prototype._onSourceEnd = function onSourceEnd({ content }) { - ++this[kCounters].messages; + ++this[_constants.K_COUNTERS].messages; const source = this.source; const target = this.target; this.logger.debug(`<${this.id}> sending message from <${source.processId}.${source.id}> to <${target.id ? `${target.processId}.${target.id}` : target.processId}>`); this.broker.publish('event', 'message.outbound', this._createMessageContent(content.message)); }; + +/** @internal */ MessageFlow.prototype._createMessageContent = function createMessage(message) { return { id: this.id, diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index 08a480ab..11a36c0d 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -3,14 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.SequenceFlow = SequenceFlow; exports.default = void 0; var _messageHelper = require("../messageHelper.js"); var _shared = require("../shared.js"); var _EventBroker = require("../EventBroker.js"); var _Api = require("../Api.js"); var _condition = require("../condition.js"); -const kCounters = Symbol.for('counters'); +var _constants = require("../constants.js"); var _default = exports.default = SequenceFlow; +/** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('types').ContextInstance} context + */ function SequenceFlow(flowDef, { environment }) { @@ -35,7 +42,9 @@ function SequenceFlow(flowDef, { this.isSequenceFlow = true; this.environment = environment; const logger = this.logger = environment.Logger(type.toLowerCase()); - this[kCounters] = { + + /** @private */ + this[_constants.K_COUNTERS] = { looped: 0, take: 0, discard: 0 @@ -60,32 +69,50 @@ function SequenceFlow(flowDef, { logger.debug(`<${id}> init, <${sourceId}> -> <${targetId}>`); } Object.defineProperty(SequenceFlow.prototype, 'counters', { + /** @returns {{ take: number, discard: number, looped: number }} */ get() { return { - ...this[kCounters] + ...this[_constants.K_COUNTERS] }; } }); + +/** + * Take the flow and publish flow.take. + * @param {Record} [content] + */ SequenceFlow.prototype.take = function take(content) { const sequenceId = content?.sequenceId; this.logger.debug(`<${sequenceId} (${this.id})> take, target <${this.targetId}>`); - ++this[kCounters].take; + ++this[_constants.K_COUNTERS].take; this._publishEvent('take', content); return true; }; + +/** + * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits + * flow.looped instead when the target id is already in the sequence. + * @param {Record} [content] + */ SequenceFlow.prototype.discard = function discard(content = {}) { const sequenceId = content?.sequenceId ?? (0, _shared.getUniqueId)(this.id); const discardSequence = content.discardSequence = content.discardSequence?.slice() || []; if (discardSequence.indexOf(this.targetId) > -1) { - ++this[kCounters].looped; + ++this[_constants.K_COUNTERS].looped; this.logger.debug(`<${this.id}> discard loop detected <${this.sourceId}> -> <${this.targetId}>. Stop.`); return this._publishEvent('looped', content); } discardSequence.push(this.sourceId); this.logger.debug(`<${sequenceId} (${this.id})> discard, target <${this.targetId}>`); - ++this[kCounters].discard; + ++this[_constants.K_COUNTERS].discard; this._publishEvent('discard', content); }; + +/** + * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` + * is set. + * @returns {import('types').SequenceFlowState | undefined} + */ SequenceFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); if (!brokerState && this.environment.settings.disableTrackState) return; @@ -96,18 +123,38 @@ SequenceFlow.prototype.getState = function getState() { broker: brokerState }; }; + +/** + * Restore flow state captured by getState. + * @param {import('types').SequenceFlowState} state + */ SequenceFlow.prototype.recover = function recover(state) { - Object.assign(this[kCounters], state.counters); + Object.assign(this[_constants.K_COUNTERS], state.counters); this.broker.recover(state.broker); }; + +/** + * Resolve a Flow Api wrapper. + * @param {import('types').ElementBrokerMessage} [message] + */ SequenceFlow.prototype.getApi = function getApi(message) { return (0, _Api.FlowApi)(this.broker, message || { content: this.createMessage() }); }; + +/** + * Stop the flow's broker. + */ SequenceFlow.prototype.stop = function stop() { this.broker.stop(); }; + +/** + * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop + * when the target was already visited, otherwise flow.shake. + * @param {import('types').ElementBrokerMessage} message + */ SequenceFlow.prototype.shake = function shake(message) { const content = (0, _messageHelper.cloneContent)(message.content); content.sequence = content.sequence || []; @@ -137,6 +184,12 @@ SequenceFlow.prototype.shake = function shake(message) { }); } }; + +/** + * Resolve the flow's condition (script or expression). Returns null when no condition is set. + * Emits a fatal error when the script language is missing or unsupported. + * @returns {import('types').ISequenceFlowCondition | null} + */ SequenceFlow.prototype.getCondition = function getCondition() { const conditionExpression = this.behaviour.conditionExpression; if (!conditionExpression) return null; @@ -153,6 +206,11 @@ SequenceFlow.prototype.getCondition = function getCondition() { } return new _condition.ExpressionCondition(this, conditionExpression.body); }; + +/** + * Build a flow event message body, optionally merging override content. + * @param {Record} [override] + */ SequenceFlow.prototype.createMessage = function createMessage(override) { return { ...override, @@ -166,6 +224,12 @@ SequenceFlow.prototype.createMessage = function createMessage(override) { parent: (0, _messageHelper.cloneParent)(this.parent) }; }; + +/** + * Evaluate the flow's condition for the source activity message. Default flows are always taken. + * @param {import('types').ElementBrokerMessage} fromMessage Source activity message + * @param {(err: Error | null, result?: boolean | object) => void} callback Callback with truthy result if flow should be taken + */ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { if (this.isDefault) { return callback(null, true); @@ -176,6 +240,8 @@ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { } flowCondition.execute(fromMessage, callback); }; + +/** @internal */ SequenceFlow.prototype._publishEvent = function publishEvent(action, content) { const eventContent = this.createMessage({ action, diff --git a/dist/gateways/EventBasedGateway.js b/dist/gateways/EventBasedGateway.js index 5cbedc7a..b3f19894 100644 --- a/dist/gateways/EventBasedGateway.js +++ b/dist/gateways/EventBasedGateway.js @@ -7,9 +7,8 @@ exports.EventBasedGatewayBehaviour = EventBasedGatewayBehaviour; exports.default = EventBasedGateway; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kCompleted = Symbol.for('completed'); -const kTargets = Symbol.for('targets'); function EventBasedGateway(activityDef, context) { return new _Activity.default(EventBasedGatewayBehaviour, activityDef, context); } @@ -19,7 +18,8 @@ function EventBasedGatewayBehaviour(activity, context) { this.activity = activity; this.broker = activity.broker; this.context = context; - this[kTargets] = new Set(activity.outbound.map(flow => context.getActivityById(flow.targetId))); + /** @private */ + this[_constants.K_TARGETS] = new Set(activity.outbound.map(flow => context.getActivityById(flow.targetId))); } EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; @@ -28,8 +28,9 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) outbound = [], outboundTaken } = executeContent; - const targets = this[kTargets]; - this[kCompleted] = false; + const targets = this[_constants.K_TARGETS]; + /** @private */ + this[_constants.K_COMPLETED] = false; if (!targets.size) return this._complete(executeContent); for (const flow of this.activity.outbound) { outbound.push({ @@ -37,10 +38,10 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) action: 'take' }); } - if (!this[kCompleted] && outboundTaken) return; + if (!this[_constants.K_COMPLETED] && outboundTaken) return; const targetConsumerTag = `_gateway-listener-${this.id}`; const onTargetCompleted = this._onTargetCompleted.bind(this, executeMessage); - for (const target of this[kTargets]) { + for (const target of this[_constants.K_TARGETS]) { target.broker.subscribeOnce('event', 'activity.end', onTargetCompleted, { consumerTag: targetConsumerTag }); @@ -49,7 +50,9 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) broker.subscribeOnce('api', `activity.stop.${executionId}`, () => this._stop(), { consumerTag: '_api-stop-execution' }); - this[kCompleted] = false; + + /** @private */ + this[_constants.K_COMPLETED] = false; if (!executeMessage.fields.redelivered) { return broker.publish('execution', 'execute.outbound.take', (0, _messageHelper.cloneContent)(executeContent, { outboundTaken: true @@ -65,7 +68,7 @@ EventBasedGatewayBehaviour.prototype._onTargetCompleted = function onTargetCompl const executionId = executeContent.executionId; this.activity.logger.debug(`<${executionId} (${this.id})> <${targetExecutionId}> completed run, discarding the rest`); this._stop(); - for (const target of this[kTargets]) { + for (const target of this[_constants.K_TARGETS]) { if (target === owner) continue; target.discard(); } @@ -79,11 +82,12 @@ EventBasedGatewayBehaviour.prototype._onTargetCompleted = function onTargetCompl this._complete(completedContent); }; EventBasedGatewayBehaviour.prototype._complete = function complete(completedContent) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(completedContent)); }; EventBasedGatewayBehaviour.prototype._stop = function stop() { const targetConsumerTag = `_gateway-listener-${this.id}`; - for (const target of this[kTargets]) target.broker.cancel(targetConsumerTag); + for (const target of this[_constants.K_TARGETS]) target.broker.cancel(targetConsumerTag); this.broker.cancel('_api-stop-execution'); }; \ No newline at end of file diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 5c4ab8f4..4621e8b5 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -7,13 +7,12 @@ exports.ParallelGatewayBehaviour = ParallelGatewayBehaviour; exports.default = ParallelGateway; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const STATE_MONTITORING = 'monitoring'; const STATE_SETUP = 'setup'; -const kPeers = Symbol.for('peers'); -const kInboundSourceIds = Symbol.for('inbound peers'); -const kTargets = Symbol.for('targets'); -const kExecuteMessage = Symbol.for('executeMessage'); +const K_PEERS = Symbol.for('peers'); +const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); function ParallelGateway(activityDef, context) { const activity = new _Activity.default(ParallelGatewayBehaviour, { ...activityDef, @@ -26,7 +25,7 @@ function ParallelGateway(activityDef, context) { consumerTag: '_api-shake', priority: 1000 }); - const peers = activity[kPeers] = new Map(activity.inbound.map(({ + const peers = activity[K_PEERS] = new Map(activity.inbound.map(({ id: flowId, sourceId }) => [flowId, new Set([sourceId])])); @@ -60,12 +59,13 @@ function ParallelGatewayBehaviour(activity) { this.isConverging = new Set(activity.inbound.map(({ sourceId }) => sourceId)).size > 1; - this[kExecuteMessage] = undefined; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = undefined; } Object.defineProperties(ParallelGatewayBehaviour.prototype, { executionId: { get() { - return this[kExecuteMessage]?.content.executionId; + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } } }); @@ -74,7 +74,8 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { const isRedelivered = executeMessage.fields.redelivered; const executeContent = executeMessage.content; if (executeContent.isRootScope) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; switch (routingKey) { case 'execute.start': { @@ -90,10 +91,11 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { } }; ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { - const peerIds = new Set([...this.activity[kPeers].values()].map(v => [...v]).flat()); - this[kTargets] = new Map([...peerIds].map(pid => [pid, this.activity.getActivityById(pid)])); - this.peerMonitor = new PeerMonitor(this.activity, this.activity[kInboundSourceIds], this[kTargets]); - const message = this[kExecuteMessage] = (0, _messageHelper.cloneMessage)(executeMessage); + const peerIds = new Set([...this.activity[K_PEERS].values()].map(v => [...v]).flat()); + /** @private */ + this[_constants.K_TARGETS] = new Map([...peerIds].map(pid => [pid, this.activity.getActivityById(pid)])); + this.peerMonitor = new PeerMonitor(this.activity, this.activity[K_INBOUND_SOURCE_IDS], this[_constants.K_TARGETS]); + const message = this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage); const executeContent = message.content; const { executionId @@ -148,7 +150,7 @@ ParallelGatewayBehaviour.prototype._complete = function complete() { this._stop(); const state = take ? 'completed' : 'discard'; this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring with state: ${state}`); - const content = (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + const content = (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { isRootScope: true, state }); diff --git a/dist/io/InputOutputSpecification.js b/dist/io/InputOutputSpecification.js index b1354e12..7068e811 100644 --- a/dist/io/InputOutputSpecification.js +++ b/dist/io/InputOutputSpecification.js @@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { exports.default = IoSpecification; var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); var _shared = require("../shared.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kConsuming = Symbol.for('consuming'); function IoSpecification(activity, ioSpecificationDef, context) { const { id, @@ -22,19 +22,20 @@ function IoSpecification(activity, ioSpecificationDef, context) { this.context = context; } IoSpecification.prototype.activate = function activate(message) { - if (this[kConsuming]) return; + if (this[_constants.K_CONSUMING]) return; if (message?.fields.redelivered && message.fields.routingKey === 'run.start') { this._onFormatEnter(); } if (message?.fields.redelivered && message.fields.routingKey === 'run.end') { this._onFormatComplete(message); } - this[kConsuming] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { + /** @private */ + this[_constants.K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); }; IoSpecification.prototype.deactivate = function deactivate() { - if (this[kConsuming]) this[kConsuming] = this[kConsuming].cancel(); + if (this[_constants.K_CONSUMING]) this[_constants.K_CONSUMING] = this[_constants.K_CONSUMING].cancel(); }; IoSpecification.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { const { diff --git a/dist/io/Properties.js b/dist/io/Properties.js index 9bf8035a..47f1fe8a 100644 --- a/dist/io/Properties.js +++ b/dist/io/Properties.js @@ -5,13 +5,13 @@ Object.defineProperty(exports, "__esModule", { }); exports.default = Properties; var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kProperties = Symbol.for('properties'); -const kConsuming = Symbol.for('consuming'); +const K_PROPERTIES = Symbol.for('properties'); function Properties(activity, propertiesDef, context) { this.activity = activity; this.broker = activity.broker; - const props = this[kProperties] = { + const props = this[K_PROPERTIES] = { properties: new Set(), dataInputObjects: new Set(), dataOutputObjects: new Set() @@ -73,19 +73,21 @@ function Properties(activity, propertiesDef, context) { } } Properties.prototype.activate = function activate(message) { - if (this[kConsuming]) return; + if (this[_constants.K_CONSUMING]) return; if (message.fields.redelivered && message.fields.routingKey === 'run.start') { this._onActivityEvent('activity.enter', message); } if (message.fields.redelivered && message.content.properties) { this._onActivityEvent('activity.extension.resume', message); } - this[kConsuming] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { + + /** @private */ + this[_constants.K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); }; Properties.prototype.deactivate = function deactivate() { - if (this[kConsuming]) this[kConsuming] = this[kConsuming].cancel(); + if (this[_constants.K_CONSUMING]) this[_constants.K_CONSUMING] = this[_constants.K_CONSUMING].cancel(); }; Properties.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { switch (routingKey) { @@ -98,7 +100,7 @@ Properties.prototype._onActivityEvent = function onActivityEvent(routingKey, mes }; Properties.prototype._formatOnEnter = function formatOnEnter(message) { const startRoutingKey = 'run.enter.bpmn-properties'; - const dataInputObjects = this[kProperties].dataInputObjects; + const dataInputObjects = this[K_PROPERTIES].dataInputObjects; const broker = this.broker; if (!dataInputObjects.size) { return broker.getQueue('format-run-q').queueMessage({ @@ -124,7 +126,7 @@ Properties.prototype._formatOnComplete = function formatOnComplete(message) { const startRoutingKey = 'run.end.bpmn-properties'; const messageOutput = (0, _getPropertyValue.default)(message, 'content.output.properties') || {}; const outputProperties = this._getProperties(message, messageOutput); - const dataOutputObjects = this[kProperties].dataOutputObjects; + const dataOutputObjects = this[K_PROPERTIES].dataOutputObjects; const broker = this.broker; if (!dataOutputObjects.size) { return broker.getQueue('format-run-q').queueMessage({ @@ -157,7 +159,7 @@ Properties.prototype._getProperties = function getProperties(message, values) { id, type, name - } of this[kProperties].properties) { + } of this[K_PROPERTIES].properties) { if (!(id in response)) { response[id] = { id, diff --git a/dist/process/Lane.js b/dist/process/Lane.js index d1dc9880..c50d38b7 100644 --- a/dist/process/Lane.js +++ b/dist/process/Lane.js @@ -4,7 +4,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Lane; -const kProcess = Symbol.for('process'); +const K_PROCESS = Symbol.for('process'); + +/** + * Process lane. Wraps a `` definition and points back to its owning process; + * activities reference their lane through `Activity.lane`. + * @param {import('types').Process} process + * @param {import('moddle-context-serializer').SerializableElement} laneDefinition + */ function Lane(process, laneDefinition) { const { broker, @@ -15,7 +22,9 @@ function Lane(process, laneDefinition) { type, behaviour } = laneDefinition; - this[kProcess] = process; + + /** @private */ + this[K_PROCESS] = process; this.id = id; this.type = type; this.name = behaviour.name; @@ -32,7 +41,8 @@ function Lane(process, laneDefinition) { this.logger = environment.Logger(type.toLowerCase()); } Object.defineProperty(Lane.prototype, 'process', { + /** @returns {import('types').Process} */ get() { - return this[kProcess]; + return this[K_PROCESS]; } }); \ No newline at end of file diff --git a/dist/process/Process.js b/dist/process/Process.js index 22c70118..8daa7e22 100644 --- a/dist/process/Process.js +++ b/dist/process/Process.js @@ -11,18 +11,16 @@ var _Api = require("../Api.js"); var _EventBroker = require("../EventBroker.js"); var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kConsuming = Symbol.for('consuming'); -const kCounters = Symbol.for('counters'); -const kExec = Symbol.for('execution'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kExtensions = Symbol.for('extensions'); -const kLanes = Symbol.for('lanes'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kStateMessage = Symbol.for('stateMessage'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); +const K_LANES = Symbol.for('lanes'); var _default = exports.default = Process; +/** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * @param {import('moddle-context-serializer').SerializableElement} processDef + * @param {import('types').ContextInstance} context + */ function Process(processDef, context) { const { id, @@ -42,14 +40,19 @@ function Process(processDef, context) { this.isExecutable = isExecutable; const environment = this.environment = context.environment; this.context = context; - this[kCounters] = { + /** @private */ + this[_constants.K_COUNTERS] = { completed: 0, discarded: 0 }; - this[kConsuming] = false; - this[kExec] = new Map(); - this[kStatus] = undefined; - this[kStopped] = false; + /** @private */ + this[_constants.K_CONSUMING] = false; + /** @private */ + this[_constants.K_EXECUTION] = new Map(); + /** @private */ + this[_constants.K_STATUS] = undefined; + /** @private */ + this[_constants.K_STOPPED] = false; const { broker, on, @@ -60,79 +63,95 @@ function Process(processDef, context) { this.on = on; this.once = once; this.waitFor = waitFor; - this[kMessageHandlers] = { + + /** @private */ + this[_constants.K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onRunMessage: this._onRunMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this) }; this.logger = environment.Logger(type.toLowerCase()); if (behaviour.lanes) { - this[kLanes] = behaviour.lanes.map(lane => new lane.Behaviour(this, lane)); + /** @private */ + this[K_LANES] = behaviour.lanes.map(lane => new lane.Behaviour(this, lane)); } - this[kExtensions] = context.loadExtensions(this); + /** @private */ + this[_constants.K_EXTENSIONS] = context.loadExtensions(this); } Object.defineProperties(Process.prototype, { counters: { get() { return { - ...this[kCounters] + ...this[_constants.K_COUNTERS] }; } }, lanes: { get() { - return this[kLanes]?.slice(); + return this[K_LANES]?.slice(); } }, extensions: { get() { - return this[kExtensions]; + return this[_constants.K_EXTENSIONS]; } }, stopped: { get() { - return this[kStopped]; + return this[_constants.K_STOPPED]; } }, isRunning: { get() { - if (!this[kConsuming]) return false; + if (!this[_constants.K_CONSUMING]) return false; return !!this.status; } }, executionId: { get() { - const exec = this[kExec]; + const exec = this[_constants.K_EXECUTION]; return exec.get('executionId') || exec.get('initExecutionId'); } }, execution: { get() { - return this[kExec].get('execution'); + return this[_constants.K_EXECUTION].get('execution'); } }, status: { get() { - return this[kStatus]; + return this[_constants.K_STATUS]; } }, activityStatus: { get() { - return this[kExec].get('execution')?.activityStatus || 'idle'; + return this[_constants.K_EXECUTION].get('execution')?.activityStatus || 'idle'; } } }); + +/** + * Allocate an executionId and emit init event without starting the run. + * @param {string} [useAsExecutionId] Override for the generated execution id + */ Process.prototype.init = function init(useAsExecutionId) { const initExecutionId = useAsExecutionId || (0, _shared.getUniqueId)(this.id); - this[kExec].set('initExecutionId', initExecutionId); + /** @private */ + this[_constants.K_EXECUTION].set('initExecutionId', initExecutionId); this._debug(`initialized with executionId <${initExecutionId}>`); this._publishEvent('init', this._createMessage({ executionId: initExecutionId })); }; + +/** + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param {Record} [runContent] Optional content merged into the run message + * @throws {Error} when the process is already running + */ Process.prototype.run = function run(runContent) { if (this.isRunning) throw new Error(`process <${this.id}> is already running`); - const exec = this[kExec]; + const exec = this[_constants.K_EXECUTION]; const executionId = exec.get('initExecutionId') || (0, _shared.getUniqueId)(this.id); exec.delete('initExecutionId'); exec.set('executionId', executionId); @@ -146,10 +165,18 @@ Process.prototype.run = function run(runContent) { broker.publish('run', 'run.execute', (0, _messageHelper.cloneContent)(content)); this._activateRunConsumers(); }; + +/** + * Resume after recover by republishing the last run message. + * @returns {this} + * @throws {Error} when called on a running process + */ Process.prototype.resume = function resume() { if (this.isRunning) throw new Error(`cannot resume running process <${this.id}>`); if (!this.status) return this; - this[kStopped] = false; + + /** @private */ + this[_constants.K_STOPPED] = false; const content = this._createMessage(); this.broker.publish('run', 'run.resume', content, { persistent: false @@ -157,6 +184,10 @@ Process.prototype.resume = function resume() { this._activateRunConsumers(); return this; }; + +/** + * Snapshot process state for recover. + */ Process.prototype.getState = function getState() { return { id: this.id, @@ -170,15 +201,26 @@ Process.prototype.getState = function getState() { execution: this.execution?.getState() }; }; + +/** + * Restore process state captured by getState. + * @param {import('types').ProcessState} [state] + * @returns {this} + * @throws {Error} when called on a running process + */ Process.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running process <${this.id}>`); if (!state) return this; - this[kStopped] = !!state.stopped; - this[kStatus] = state.status; - const exec = this[kExec]; + + /** @private */ + this[_constants.K_STOPPED] = !!state.stopped; + /** @private */ + this[_constants.K_STATUS] = state.status; + const exec = this[_constants.K_EXECUTION]; exec.set('executionId', state.executionId); - this[kCounters] = { - ...this[kCounters], + /** @private */ + this[_constants.K_COUNTERS] = { + ...this[_constants.K_COUNTERS], ...state.counters }; this.environment.recover(state.environment); @@ -188,36 +230,63 @@ Process.prototype.recover = function recover(state) { this.broker.recover(state.broker); return this; }; + +/** + * Walk activity graph from the given start id, or every start activity when omitted. + * @param {string} [startId] + */ Process.prototype.shake = function shake(startId) { if (this.isRunning) return this.execution.shake(startId); return new _ProcessExecution.default(this, this.context).shake(startId); }; + +/** + * Stop the process if running. + */ Process.prototype.stop = function stop() { if (!this.isRunning) return; this.getApi().stop(); }; + +/** + * Resolve a Process Api wrapper, preferring the running execution if any. + * @param {import('types').ElementBrokerMessage} [message] + */ Process.prototype.getApi = function getApi(message) { const execution = this.execution; if (execution) return execution.getApi(message); - return (0, _Api.ProcessApi)(this.broker, message || this[kStateMessage]); + return (0, _Api.ProcessApi)(this.broker, message || this[_constants.K_STATE_MESSAGE]); }; + +/** + * Send a delegated signal to the running process. + * @param {import('types').signalMessage} [message] + */ Process.prototype.signal = function signal(message) { return this.getApi().signal(message, { delegate: true }); }; + +/** + * Cancel a running activity inside the process by delegated api message. + * @param {import('types').signalMessage} [message] + */ Process.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { delegate: true }); }; + +/** @internal */ Process.prototype._activateRunConsumers = function activateRunConsumers() { - this[kConsuming] = true; + /** @private */ + this[_constants.K_CONSUMING] = true; const broker = this.broker; const { onApiMessage, onRunMessage - } = this[kMessageHandlers]; + } = this[_constants.K_MESSAGE_HANDLERS]; broker.subscribeTmp('api', `process.*.${this.executionId}`, onApiMessage, { noAck: true, consumerTag: '_process-api', @@ -228,13 +297,18 @@ Process.prototype._activateRunConsumers = function activateRunConsumers() { consumerTag: '_process-run' }); }; + +/** @internal */ Process.prototype._deactivateRunConsumers = function deactivateRunConsumers() { const broker = this.broker; broker.cancel('_process-api'); broker.cancel('_process-run'); broker.cancel('_process-execution'); - this[kConsuming] = false; + /** @private */ + this[_constants.K_CONSUMING] = false; }; + +/** @internal */ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { const { content, @@ -243,35 +317,44 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { if (routingKey === 'run.resume') { return this._onResumeMessage(message); } - this[kStateMessage] = message; + + /** @private */ + this[_constants.K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this._debug('enter'); - this[kStatus] = 'entered'; + + /** @private */ + this[_constants.K_STATUS] = 'entered'; if (fields.redelivered) break; - this[kExec].delete('execution'); + + /** @private */ + this[_constants.K_EXECUTION].delete('execution'); this._publishEvent('enter', content); break; } case 'run.start': { this._debug('start'); - this[kStatus] = 'start'; + /** @private */ + this[_constants.K_STATUS] = 'start'; this._publishEvent('start', content); break; } case 'run.execute': { - const exec = this[kExec]; - this[kStatus] = 'executing'; + const exec = this[_constants.K_EXECUTION]; + /** @private */ + this[_constants.K_STATUS] = 'executing'; const executeMessage = (0, _messageHelper.cloneMessage)(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - this[kExecuteMessage] = message; - this.broker.getQueue('execution-q').assertConsumer(this[kMessageHandlers].onExecutionMessage, { + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = message; + this.broker.getQueue('execution-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, consumerTag: '_process-execution' }); @@ -281,7 +364,8 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } case 'run.error': { - this[kStatus] = 'errored'; + /** @private */ + this[_constants.K_STATUS] = 'errored'; this._publishEvent('error', (0, _messageHelper.cloneContent)(content, { error: fields.redelivered ? (0, _Errors.makeErrorFromMessage)(message) : content.error })); @@ -289,26 +373,33 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } case 'run.end': { - this[kStatus] = 'end'; + /** @private */ + this[_constants.K_STATUS] = 'end'; if (fields.redelivered) break; this._debug('completed'); - this[kCounters].completed++; + + /** @private */ + this[_constants.K_COUNTERS].completed++; this.broker.publish('run', 'run.leave', content); this._publishEvent('end', content); break; } case 'run.discarded': { - this[kStatus] = 'discarded'; + /** @private */ + this[_constants.K_STATUS] = 'discarded'; if (fields.redelivered) break; - this[kCounters].discarded++; + + /** @private */ + this[_constants.K_COUNTERS].discarded++; this.broker.publish('run', 'run.leave', content); this._publishEvent('discarded', content); break; } case 'run.leave': { - this[kStatus] = undefined; + /** @private */ + this[_constants.K_STATUS] = undefined; message.ack(); this._deactivateRunConsumers(); const { @@ -321,9 +412,11 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } message.ack(); }; + +/** @internal */ Process.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[_constants.K_STATE_MESSAGE]; switch (stateMessage.fields.routingKey) { case 'run.enter': case 'run.start': @@ -338,6 +431,8 @@ Process.prototype._onResumeMessage = function onResumeMessage(message) { this._debug(`resume from ${this.status}`); return this.broker.publish('run', stateMessage.fields.routingKey, (0, _messageHelper.cloneContent)(stateMessage.content), stateMessage.properties); }; + +/** @internal */ Process.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) { const content = message.content; const messageType = message.properties.type; @@ -361,10 +456,13 @@ Process.prototype._onExecutionMessage = function onExecutionMessage(routingKey, this.broker.publish('run', 'run.end', content); } } - const executeMessage = this[kExecuteMessage]; - this[kExecuteMessage] = null; + const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; + +/** @internal */ Process.prototype._publishEvent = function publishEvent(state, content) { const eventContent = this._createMessage({ ...content, @@ -375,6 +473,12 @@ Process.prototype._publishEvent = function publishEvent(state, content) { mandatory: state === 'error' }); }; + +/** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. + * @param {import('types').ElementBrokerMessage} message + */ Process.prototype.sendMessage = function sendMessage(message) { const messageContent = message?.content; if (!messageContent) return; @@ -393,34 +497,62 @@ Process.prototype.sendMessage = function sendMessage(message) { delegate: true }); }; + +/** + * @param {string} childId + */ Process.prototype.getActivityById = function getActivityById(childId) { const execution = this.execution; if (execution) return execution.getActivityById(childId); return this.context.getActivityById(childId); }; + +/** + * Get every activity in the process scope. + */ Process.prototype.getActivities = function getActivities() { const execution = this.execution; if (execution) return execution.getActivities(); return this.context.getActivities(this.id); }; + +/** + * Get start activities, optionally filtered by referenced event definition. + * @param {import('types').startActivityFilterOptions} [filterOptions] + */ Process.prototype.getStartActivities = function getStartActivities(filterOptions) { return this.context.getStartActivities(filterOptions, this.id); }; + +/** + * Get sequence flows in the process scope. + */ Process.prototype.getSequenceFlows = function getSequenceFlows() { const execution = this.execution; if (execution) return execution.getSequenceFlows(); return this.context.getSequenceFlows(); }; + +/** + * @param {string} laneId + */ Process.prototype.getLaneById = function getLaneById(laneId) { - const lanes = this[kLanes]; + const lanes = this[K_LANES]; if (!lanes) return; return lanes.find(lane => lane.id === laneId); }; + +/** + * List currently postponed activities as Api wrappers. + * @param {import('types').filterPostponed} [filterFn] + */ Process.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; if (!execution) return []; return execution.getPostponed(...args); }; + +/** @internal */ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { const messageType = message.properties.type; switch (messageType) { @@ -432,11 +564,16 @@ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { } } }; + +/** @internal */ Process.prototype._onStop = function onStop() { - this[kStopped] = true; + /** @private */ + this[_constants.K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop'); }; + +/** @internal */ Process.prototype._createMessage = function createMessage(override) { return { id: this.id, @@ -449,6 +586,8 @@ Process.prototype._createMessage = function createMessage(override) { ...override }; }; + +/** @internal */ Process.prototype._debug = function debug(msg) { this.logger.debug(`<${this.id}> ${msg}`); }; \ No newline at end of file diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 1d4bf1cc..88451658 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -8,17 +8,19 @@ var _Api = require("../Api.js"); var _messageHelper = require("../messageHelper.js"); var _shared = require("../shared.js"); var _Tracker = require("../Tracker.js"); +var _constants = require("../constants.js"); var _default = exports.default = ProcessExecution; -const kActivated = Symbol.for('activated'); -const kActivityQ = Symbol.for('activityQ'); -const kCompleted = Symbol.for('completed'); -const kElements = Symbol.for('elements'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kParent = Symbol.for('parent'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); -const kTracker = Symbol.for('activity tracker'); +const K_ACTIVITY_Q = Symbol.for('activityQ'); +const K_ELEMENTS = Symbol.for('elements'); +const K_PARENT = Symbol.for('parent'); +const K_TRACKER = Symbol.for('activity tracker'); + +/** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * @param {import('types').Process | import('types').Activity} parentActivity + * @param {import('types').ContextInstance} context + */ function ProcessExecution(parentActivity, context) { const { id, @@ -27,7 +29,9 @@ function ProcessExecution(parentActivity, context) { isSubProcess, isTransaction } = parentActivity; - this[kParent] = parentActivity; + + /** @private */ + this[K_PARENT] = parentActivity; this.id = id; this.type = type; this.isSubProcess = isSubProcess; @@ -35,7 +39,9 @@ function ProcessExecution(parentActivity, context) { this.broker = broker; this.environment = context.environment; this.context = context; - this[kElements] = { + + /** @private */ + this[K_ELEMENTS] = { postponed: new Set(), children: context.getActivities(id), associations: context.getAssociations(id), @@ -52,13 +58,21 @@ function ProcessExecution(parentActivity, context) { autoDelete: false, durable: true }); - this[kCompleted] = false; - this[kStopped] = false; - this[kActivated] = false; - this[kStatus] = 'init'; - this[kTracker] = new _Tracker.ActivityTracker(id); + + /** @private */ + this[_constants.K_COMPLETED] = false; + /** @private */ + this[_constants.K_STOPPED] = false; + /** @private */ + this[_constants.K_ACTIVATED] = false; + /** @private */ + this[_constants.K_STATUS] = 'init'; + /** @private */ + this[K_TRACKER] = new _Tracker.ActivityTracker(id); this.executionId = undefined; - this[kMessageHandlers] = { + + /** @private */ + this[_constants.K_MESSAGE_HANDLERS] = { onActivityEvent: this._onActivityEvent.bind(this), onApiMessage: this._onApiMessage.bind(this), onChildMessage: this._onChildMessage.bind(this), @@ -68,46 +82,57 @@ function ProcessExecution(parentActivity, context) { Object.defineProperties(ProcessExecution.prototype, { stopped: { get() { - return this[kStopped]; + return this[_constants.K_STOPPED]; } }, completed: { get() { - return this[kCompleted]; + return this[_constants.K_COMPLETED]; } }, status: { get() { - return this[kStatus]; + return this[_constants.K_STATUS]; } }, postponedCount: { get() { - return this[kElements].postponed.size; + return this[K_ELEMENTS].postponed.size; } }, isRunning: { get() { - return this[kActivated]; + return this[_constants.K_ACTIVATED]; } }, activityStatus: { get() { - return this[kTracker].activityStatus; + return this[K_TRACKER].activityStatus; } } }); + +/** + * Activate children and start the process execution. Resumes if the message is redelivered. + * @param {import('types').ElementBrokerMessage} executeMessage + * @throws {Error} when message or executionId is missing + */ ProcessExecution.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new Error('Process execution requires message'); if (!executeMessage.content || !executeMessage.content.executionId) throw new Error('Process execution requires execution id'); const executionId = this.executionId = executeMessage.content.executionId; - this[kExecuteMessage] = (0, _messageHelper.cloneMessage)(executeMessage, { + + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage, { executionId, state: 'start' }); - this[kStopped] = false; + + /** @private */ + this[_constants.K_STOPPED] = false; this.environment.assignVariables(executeMessage); - this[kActivityQ] = this.broker.assertQueue(`execute-${executionId}-q`, { + /** @private */ + this[K_ACTIVITY_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); @@ -119,16 +144,21 @@ ProcessExecution.prototype.execute = function execute(executeMessage) { this._start(); return true; }; + +/** + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. + */ ProcessExecution.prototype.resume = function resume() { this._debug(`resume process execution at ${this.status}`); - if (this[kCompleted]) return this._complete('completed'); + if (this[_constants.K_COMPLETED]) return this._complete('completed'); this._activate(); const { startActivities, postponed, detachedActivities, convergingGateways - } = this[kElements]; + } = this[K_ELEMENTS]; if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); const skipDiscard = this.environment.settings.skipDiscard = result.settings.skipDiscard; @@ -136,14 +166,16 @@ ProcessExecution.prototype.resume = function resume() { } postponed.clear(); detachedActivities.clear(); - this[kActivityQ].consume(this[kMessageHandlers].onChildMessage, { + + /** @private */ + this[K_ACTIVITY_Q].consume(this[_constants.K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; const status = this.status; if (status === 'init') return this._start(); - const tracker = this[kTracker]; + const tracker = this[K_TRACKER]; for (const msg of new Set(postponed)) { const activity = this.getActivityById(msg.content.id); if (!activity) continue; @@ -156,16 +188,20 @@ ProcessExecution.prototype.resume = function resume() { tracker.track(msg.fields.routingKey, msg); activity.resume(); } - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; if (!postponed.size && status === 'executing') return this._complete('completed'); }; + +/** + * Snapshot execution state including children, flows, message flows, and associations. + */ ProcessExecution.prototype.getState = function getState() { const { children, flows, outboundMessageFlows, associations - } = this[kElements]; + } = this[K_ELEMENTS]; const flowStates = flows.reduce((result, flow) => { const elmState = flow.getState(); if (elmState) result.push(elmState); @@ -173,8 +209,8 @@ ProcessExecution.prototype.getState = function getState() { }, []); return { executionId: this.executionId, - stopped: this[kStopped], - completed: this[kCompleted], + stopped: this[_constants.K_STOPPED], + completed: this[_constants.K_COMPLETED], status: this.status, children: children.reduce((result, activity) => { if (activity.placeholder) return result; @@ -193,12 +229,22 @@ ProcessExecution.prototype.getState = function getState() { }) }; }; + +/** + * Restore execution state captured by getState. + * @param {import('types').ProcessExecutionState} [state] + * @returns {this} + */ ProcessExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - this[kStopped] = state.stopped; - this[kCompleted] = state.completed; - this[kStatus] = state.status; + + /** @private */ + this[_constants.K_STOPPED] = state.stopped; + /** @private */ + this[_constants.K_COMPLETED] = state.completed; + /** @private */ + this[_constants.K_STATUS] = state.status; this._debug(`recover process execution at ${this.status}`); if (state.messageFlows) { for (const flowState of state.messageFlows) { @@ -230,15 +276,29 @@ ProcessExecution.prototype.recover = function recover(state) { } return this; }; + +/** + * Walk activity graph from the given start id, or every start activity when omitted. + * @param {string} [fromId] + */ ProcessExecution.prototype.shake = function shake(fromId) { return Object.fromEntries(this._shakeElements(fromId).sequences); }; + +/** + * Stop the running process execution via the api. + */ ProcessExecution.prototype.stop = function stop() { this.getApi().stop(); }; + +/** + * List currently postponed children as Api wrappers. + * @param {import('types').filterPostponed} [filterFn] + */ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { const result = []; - for (const msg of this[kElements].postponed) { + for (const msg of this[K_ELEMENTS].postponed) { const api = this._getChildApi(msg); if (!api) continue; if (filterFn && !filterFn(api)) continue; @@ -246,9 +306,14 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { } return result; }; + +/** + * Queue a discard message that propagates to all running children. + */ ProcessExecution.prototype.discard = function discard() { - this[kStatus] = 'discard'; - return this[kActivityQ].queueMessage({ + /** @private */ + this[_constants.K_STATUS] = 'discard'; + return this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.discard' }, { id: this.id, @@ -258,8 +323,12 @@ ProcessExecution.prototype.discard = function discard() { type: 'discard' }); }; + +/** + * Queue a cancel message that propagates to all running children. + */ ProcessExecution.prototype.cancel = function discard() { - return this[kActivityQ].queueMessage({ + return this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.cancel' }, { id: this.id, @@ -269,26 +338,47 @@ ProcessExecution.prototype.cancel = function discard() { type: 'cancel' }); }; + +/** + * Get child activities in the process scope. + */ ProcessExecution.prototype.getActivities = function getActivities() { - return this[kElements].children.slice(); + return this[K_ELEMENTS].children.slice(); }; + +/** + * @param {string} activityId + */ ProcessExecution.prototype.getActivityById = function getActivityById(activityId) { - return this[kElements].children.find(child => child.id === activityId); + return this[K_ELEMENTS].children.find(child => child.id === activityId); }; + +/** + * Get sequence flows in the process scope. + */ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() { - return this[kElements].flows.slice(); + return this[K_ELEMENTS].flows.slice(); }; + +/** + * Get associations in the process scope. + */ ProcessExecution.prototype.getAssociations = function getAssociations() { - return this[kElements].associations.slice(); + return this[K_ELEMENTS].associations.slice(); }; + +/** + * Resolve a process or child Api for the given message. + * @param {import('types').ElementBrokerMessage} [message] + */ ProcessExecution.prototype.getApi = function getApi(message) { - if (!message) return (0, _Api.ProcessApi)(this.broker, this[kExecuteMessage]); + if (!message) return (0, _Api.ProcessApi)(this.broker, this[_constants.K_EXECUTE_MESSAGE]); const content = message.content; if (content.executionId !== this.executionId) { return this._getChildApi(message); } const api = (0, _Api.ProcessApi)(this.broker, message); - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const self = this; api.getExecuting = function getExecuting() { const result = []; @@ -300,13 +390,17 @@ ProcessExecution.prototype.getApi = function getApi(message) { }; return api; }; + +/** @internal */ ProcessExecution.prototype._start = function start() { - if (!this[kElements].children.length) { + if (!this[K_ELEMENTS].children.length) { return this._complete('completed'); } - this[kStatus] = 'start'; + + /** @private */ + this[_constants.K_STATUS] = 'start'; const executeContent = { - ...this[kExecuteMessage].content, + ...this[_constants.K_EXECUTE_MESSAGE].content, state: this.status }; this.broker.publish(this._exchangeName, 'execute.start', (0, _messageHelper.cloneContent)(executeContent)); @@ -315,33 +409,37 @@ ProcessExecution.prototype._start = function start() { postponed, detachedActivities, convergingGateways - } = this[kElements]; + } = this[K_ELEMENTS]; if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); const skipDiscard = this.environment.settings.skipDiscard = result.settings.skipDiscard; this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); } for (const a of startActivities) a.init(); - this[kStatus] = 'executing'; + /** @private */ + this[_constants.K_STATUS] = 'executing'; for (const a of startActivities) a.run(); if (!startActivities.size) { - for (const a of this[kElements].triggeredByEvent) { + for (const a of this[K_ELEMENTS].triggeredByEvent) { if (a.isCatching && !a.isRunning) a.run(); } } postponed.clear(); detachedActivities.clear(); - this[kActivityQ].assertConsumer(this[kMessageHandlers].onChildMessage, { + /** @private */ + this[K_ACTIVITY_Q].assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}` }); }; + +/** @internal */ ProcessExecution.prototype._activate = function activate() { const { onApiMessage, onMessageFlowEvent, onActivityEvent - } = this[kMessageHandlers]; + } = this[_constants.K_MESSAGE_HANDLERS]; if (!this.isSubProcess) { this.broker.consume('api-q', onApiMessage, { noAck: true, @@ -364,7 +462,8 @@ ProcessExecution.prototype._activate = function activate() { triggeredByEvent, convergingGateways, children - } = this[kElements]; + } = /** @private */ + this[K_ELEMENTS]; for (const flow of outboundMessageFlows) { flow.activate(); flow.broker.subscribeTmp('event', '#', onMessageFlowEvent, { @@ -408,8 +507,12 @@ ProcessExecution.prototype._activate = function activate() { startSequences.set(activity.id, new Set()); } } - this[kActivated] = true; + + /** @private */ + this[_constants.K_ACTIVATED] = true; }; + +/** @internal */ ProcessExecution.prototype._deactivate = function deactivate() { const broker = this.broker; const executionId = this.executionId; @@ -420,7 +523,7 @@ ProcessExecution.prototype._deactivate = function deactivate() { flows, associations, outboundMessageFlows - } = this[kElements]; + } = this[K_ELEMENTS]; for (const activity of children) { if (activity.placeholder) continue; activity.broker.cancel('_process-activity-consumer'); @@ -436,8 +539,12 @@ ProcessExecution.prototype._deactivate = function deactivate() { flow.deactivate(); flow.broker.cancel('_process-message-consumer'); } - this[kActivated] = false; + + /** @private */ + this[_constants.K_ACTIVATED] = false; }; + +/** @internal */ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { let executing = true; const id = this.id; @@ -446,7 +553,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { this.executionId = (0, _shared.getUniqueId)(id); this._activate(); } - const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; + const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[K_ELEMENTS].startActivities; const result = { settings: { skipDiscard: this.environment.settings.skipDiscard @@ -462,7 +569,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { switch (routingKey) { case 'activity.shake.link': { - for (const a of this[kElements].triggeredByEvent) { + for (const a of this[K_ELEMENTS].triggeredByEvent) { if (!a.isCatching) continue; a.broker.publish('api', routingKey, (0, _messageHelper.cloneContent)(content), { type: 'shake' @@ -519,6 +626,8 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { this.broker.cancel(consumerTag); return result; }; + +/** @internal */ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) { const eventType = message.properties.type; let delegate = true; @@ -528,7 +637,7 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) } else { this._debug(`delegate ${eventType} anonymous event`); } - for (const activity of this[kElements].triggeredByEvent) { + for (const activity of this[K_ELEMENTS].triggeredByEvent) { if (activity.isSubProcess && activity.getStartActivities({ referenceId: content.message?.id, referenceType: eventType @@ -542,9 +651,13 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) }); return delegate; }; + +/** @internal */ ProcessExecution.prototype._onMessageFlowEvent = function onMessageFlowEvent(routingKey, message) { this.broker.publish('message', routingKey, (0, _messageHelper.cloneContent)(message.content), message.properties); }; + +/** @internal */ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { const { fields, @@ -566,7 +679,9 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe }); } if (delegate) delegate = this._onDelegateEvent(message); - this[kTracker].track(routingKey, message); + + /** @private */ + this[K_TRACKER].track(routingKey, message); this.broker.publish('event', routingKey, content, { ...properties, delegate, @@ -576,7 +691,7 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe if (!isDirectChild) return; switch (routingKey) { case 'process.terminate': - return this[kActivityQ].queueMessage({ + return this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.terminate' }, (0, _messageHelper.cloneContent)(content), { type: 'terminate', @@ -585,11 +700,15 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe case 'activity.stop': return; } - this[kActivityQ].queueMessage(message.fields, (0, _messageHelper.cloneContent)(content), { + + /** @private */ + this[K_ACTIVITY_Q].queueMessage(message.fields, (0, _messageHelper.cloneContent)(content), { persistent: true, ...message.properties }); }; + +/** @internal */ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, message) { if (message.fields.redelivered && message.properties.persistent === false) return message.ack(); const content = message.content; @@ -606,7 +725,7 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, case 'execution.discard.detached': { message.ack(); - for (const detached of this[kElements].detachedActivities) { + for (const detached of this[K_ELEMENTS].detachedActivities) { this._getChildApi(detached).discard(); } return; @@ -617,7 +736,7 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, case 'activity.error.caught': { let prevMsg; - for (const msg of this[kElements].postponed) { + for (const msg of this[K_ELEMENTS].postponed) { if (msg.content.executionId === content.executionId) { prevMsg = msg; break; @@ -634,7 +753,8 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, switch (routingKey) { case 'activity.detach': { - this[kElements].detachedActivities.add((0, _messageHelper.cloneMessage)(message)); + /** @private */ + this[K_ELEMENTS].detachedActivities.add((0, _messageHelper.cloneMessage)(message)); break; } case 'activity.cancel': @@ -656,14 +776,15 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, case 'activity.error': { let eventCaughtBy; - for (const msg of this[kElements].postponed) { + for (const msg of this[K_ELEMENTS].postponed) { if (msg.fields.routingKey === 'activity.catch' && msg.content.source?.executionId === content.executionId) { eventCaughtBy = msg; break; } } if (eventCaughtBy) { - this[kActivityQ].queueMessage({ + /** @private */ + this[K_ACTIVITY_Q].queueMessage({ routingKey: 'activity.error.caught' }, (0, _messageHelper.cloneContent)(content), { persistent: true, @@ -677,16 +798,20 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, } } }; + +/** @internal */ ProcessExecution.prototype._stateChangeMessage = function stateChangeMessage(message, postponeMessage) { const previousMsg = this._popPostponed(message.content); if (previousMsg) previousMsg.ack(); - if (postponeMessage) this[kElements].postponed.add(message); + if (postponeMessage) this[K_ELEMENTS].postponed.add(message); }; + +/** @internal */ ProcessExecution.prototype._popPostponed = function popPostponed(byContent) { const { postponed, detachedActivities - } = this[kElements]; + } = this[K_ELEMENTS]; let postponedMsg; if (byContent.sequenceId) { for (const msg of postponed) { @@ -713,6 +838,8 @@ ProcessExecution.prototype._popPostponed = function popPostponed(byContent) { } return postponedMsg; }; + +/** @internal */ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message) { this._stateChangeMessage(message, false); if (message.fields.redelivered) return message.ack(); @@ -731,7 +858,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message postponed, detachedActivities, startActivities - } = this[kElements]; + } = this[K_ELEMENTS]; const postponedCount = postponed.size; if (!postponedCount) { this._debug(`left <${id}> (${type}), pending runs ${postponedCount}`); @@ -741,7 +868,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message message.ack(); this._debug(`left <${id}> (${type}), pending activities ${postponedCount} ${[...postponed].map(m => m.content.id)}`); if (postponedCount && postponedCount === detachedActivities.size) { - return this[kActivityQ].queueMessage({ + return this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.discard.detached' }, { id: this.id, @@ -752,7 +879,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message }); } if (isEnd && startActivities.size) { - const startSequences = this[kElements].startSequences; + const startSequences = this[K_ELEMENTS].startSequences; for (const msg of postponed) { const postponedId = msg.content.id; const startSequence = startSequences.get(postponedId); @@ -763,6 +890,8 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message } } }; + +/** @internal */ ProcessExecution.prototype._stopExecution = function stopExecution(message) { const postponedCount = this.postponedCount; this._debug(`stop process execution (stop child executions ${postponedCount})`); @@ -770,18 +899,21 @@ ProcessExecution.prototype._stopExecution = function stopExecution(message) { for (const api of this.getPostponed()) api.stop(); } this._deactivate(); - this[kStopped] = true; + /** @private */ + this[_constants.K_STOPPED] = true; return this.broker.publish(this._exchangeName, `execution.stopped.${this.executionId}`, { - ...this[kExecuteMessage].content, + ...this[_constants.K_EXECUTE_MESSAGE].content, ...(message && message.content) }, { type: 'stopped', persistent: false }); }; + +/** @internal */ ProcessExecution.prototype._onDiscard = function onDiscard() { this._deactivate(); - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const running = new Set(postponed); postponed.clear(); this._debug(`discard process execution (discard child executions ${running.size})`); @@ -792,17 +924,22 @@ ProcessExecution.prototype._onDiscard = function onDiscard() { for (const flow of this.getAssociations()) flow.stop(); for (const msg of running) this._getChildApi(msg).discard(); } - this[kActivityQ].purge(); + + /** @private */ + this[K_ACTIVITY_Q].purge(); return this._complete('discard'); }; + +/** @internal */ ProcessExecution.prototype._onCancel = function onCancel() { - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const running = new Set(postponed); const isTransaction = this.isTransaction; if (isTransaction) { this._debug(`cancel transaction execution (cancel child executions ${running.size})`); - this[kStatus] = 'cancel'; - this.broker.publish('event', 'transaction.cancel', (0, _messageHelper.cloneMessage)(this[kExecuteMessage], { + /** @private */ + this[_constants.K_STATUS] = 'cancel'; + this.broker.publish('event', 'transaction.cancel', (0, _messageHelper.cloneMessage)(this[_constants.K_EXECUTE_MESSAGE], { state: 'cancel' })); for (const msg of running) { @@ -819,6 +956,8 @@ ProcessExecution.prototype._onCancel = function onCancel() { } } }; + +/** @internal */ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, message) { if (message.properties.delegate) { return this._delegateApiMessage(routingKey, message); @@ -835,7 +974,8 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes case 'discard': return this.discard(message); case 'stop': - this[kActivityQ].queueMessage({ + /** @private */ + this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.stop' }, (0, _messageHelper.cloneContent)(message.content), { persistent: false @@ -843,6 +983,8 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes break; } }; + +/** @internal */ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(routingKey, message, continueOnConsumed) { const correlationId = message.properties.correlationId || (0, _shared.getUniqueId)(this.executionId); this._debug(`delegate api ${routingKey} message to children, with correlationId <${correlationId}>`); @@ -857,16 +999,19 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou consumerTag: `_ct-delegate-${correlationId}`, noAck: true }); - for (const child of this[kElements].children) { + for (const child of this[K_ELEMENTS].children) { if (child.placeholder) continue; child.broker.publish('api', routingKey, (0, _messageHelper.cloneContent)(message.content), message.properties); if (consumed && !continueOnConsumed) break; } return broker.cancel(`_ct-delegate-${correlationId}`); }; + +/** @internal */ ProcessExecution.prototype._complete = function complete(completionType, content) { this._deactivate(); - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; const status = this.status; switch (this.status) { case 'cancel': @@ -878,11 +1023,13 @@ ProcessExecution.prototype._complete = function complete(completionType, content break; default: this._debug(`process execution ${completionType}`); - this[kStatus] = completionType; + /** @private */ + this[_constants.K_STATUS] = completionType; } const broker = this.broker; - this[kActivityQ].delete(); - return broker.publish(this._exchangeName, `execution.${completionType}.${this.executionId}`, (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + /** @private */ + this[K_ACTIVITY_Q].delete(); + return broker.publish(this._exchangeName, `execution.${completionType}.${this.executionId}`, (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { output: { ...this.environment.output }, @@ -893,10 +1040,13 @@ ProcessExecution.prototype._complete = function complete(completionType, content mandatory: completionType === 'error' }); }; + +/** @internal */ ProcessExecution.prototype._terminate = function terminate(message) { - this[kStatus] = 'terminated'; + /** @private */ + this[_constants.K_STATUS] = 'terminated'; this._debug('terminating process execution'); - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const running = new Set(postponed); postponed.clear(); for (const flow of this.getSequenceFlows()) flow.stop(); @@ -912,20 +1062,32 @@ ProcessExecution.prototype._terminate = function terminate(message) { this._getChildApi(msg).stop(); msg.ack(); } - this[kActivityQ].purge(); + + /** @private */ + this[K_ACTIVITY_Q].purge(); }; + +/** @internal */ ProcessExecution.prototype._getFlowById = function getFlowById(flowId) { - return this[kElements].flows.find(f => f.id === flowId); + return this[K_ELEMENTS].flows.find(f => f.id === flowId); }; + +/** @internal */ ProcessExecution.prototype._getAssociationById = function getAssociationById(associationId) { - return this[kElements].associations.find(a => a.id === associationId); + return this[K_ELEMENTS].associations.find(a => a.id === associationId); }; + +/** @internal */ ProcessExecution.prototype._getMessageFlowById = function getMessageFlowById(flowId) { - return this[kElements].outboundMessageFlows.find(f => f.id === flowId); + return this[K_ELEMENTS].outboundMessageFlows.find(f => f.id === flowId); }; + +/** @internal */ ProcessExecution.prototype._getChildById = function getChildById(childId) { return this.getActivityById(childId) || this._getFlowById(childId); }; + +/** @internal */ ProcessExecution.prototype._getChildApi = function getChildApi(message) { const content = message.content; let child = this._getChildById(content.id); @@ -939,15 +1101,20 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { if (child) return child.getApi(message); } }; + +/** @internal */ ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { if (message.fields.routingKey !== 'activity.shake.end') return; let seq; - if (!(seq = this[kElements].startSequences.get(message.content.id))) return; + if (!(seq = this[K_ELEMENTS].startSequences.get(message.content.id))) return; for (const s of message.content.sequence) { if (s.isSequenceFlow) continue; seq.add(s.id); } }; + +/** @internal */ ProcessExecution.prototype._debug = function debugMessage(logMessage) { - this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); + /** @private */ + this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; \ No newline at end of file diff --git a/dist/tasks/ReceiveTask.js b/dist/tasks/ReceiveTask.js old mode 100755 new mode 100644 index f6650da7..bc4ce94e --- a/dist/tasks/ReceiveTask.js +++ b/dist/tasks/ReceiveTask.js @@ -7,11 +7,8 @@ exports.ReceiveTaskBehaviour = ReceiveTaskBehaviour; exports.default = ReceiveTask; var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _messageHelper = require("../messageHelper.js"); +var _constants = require("../constants.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); function ReceiveTask(activityDef, context) { const task = new _Activity.default(ReceiveTaskBehaviour, activityDef, context); task.broker.assertQueue('message', { @@ -39,7 +36,9 @@ function ReceiveTaskBehaviour(activity) { this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.broker = activity.broker; - this[kReferenceElement] = reference.id && activity.getActivityById(reference.id); + + /** @private */ + this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); } ReceiveTaskBehaviour.prototype.execute = function execute(executeMessage) { return new ReceiveTaskExecution(this).execute(executeMessage); @@ -56,18 +55,21 @@ function ReceiveTaskExecution(parent) { this.reference = reference; this.broker = broker; this.loopCharacteristics = loopCharacteristics; - this.referenceElement = parent[kReferenceElement]; - this[kCompleted] = false; + this.referenceElement = parent[_constants.K_REFERENCE_ELEMENT]; + + /** @private */ + this[_constants.K_COMPLETED] = false; } ReceiveTaskExecution.prototype.execute = function execute(executeMessage) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; const { executionId, isRootScope } = executeContent; this.executionId = executionId; - const info = this[kReferenceInfo] = this._getReferenceInfo(executeMessage); + const info = this[_constants.K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage); if (isRootScope) { this._setupMessageHandling(executionId); } @@ -80,7 +82,7 @@ ReceiveTaskExecution.prototype.execute = function execute(executeMessage) { noAck: true, consumerTag: `_onmessage-${executionId}` }); - if (this[kCompleted]) return; + if (this[_constants.K_COMPLETED]) return; broker.subscribeTmp('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { noAck: true, consumerTag: `_api-${executionId}`, @@ -102,7 +104,7 @@ ReceiveTaskExecution.prototype._onCatchMessage = function onCatchMessage(routing const { message: referenceMessage, description - } = this[kReferenceInfo]; + } = this[_constants.K_REFERENCE_INFO]; if (!referenceMessage.id && signalId || signalExecutionId) { if (this.loopCharacteristics && signalExecutionId !== this.executionId) return; if (signalId !== this.id && signalExecutionId !== this.executionId) return; @@ -115,7 +117,7 @@ ReceiveTaskExecution.prototype._onCatchMessage = function onCatchMessage(routing correlationId } = message.properties; const broker = this.broker; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[_constants.K_EXECUTE_MESSAGE].content; broker.publish('event', 'activity.consumed', (0, _messageHelper.cloneContent)(executeContent, { message: { ...message.content.message @@ -149,9 +151,10 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content), { + return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content), { correlationId }); } @@ -162,9 +165,10 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, } }; ReceiveTaskExecution.prototype._complete = function complete(output, options) { - this[kCompleted] = true; + /** @private */ + this[_constants.K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(this[kExecuteMessage].content, { + return this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { output }), options); }; diff --git a/dist/tasks/SubProcess.js b/dist/tasks/SubProcess.js index 00666150..be633ded 100644 --- a/dist/tasks/SubProcess.js +++ b/dist/tasks/SubProcess.js @@ -9,8 +9,8 @@ var _Activity = _interopRequireDefault(require("../activity/Activity.js")); var _ProcessExecution = _interopRequireDefault(require("../process/ProcessExecution.js")); var _messageHelper = require("../messageHelper.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -const kExecutions = Symbol.for('executions'); -const kOnExecutionCompleted = Symbol.for('execution completed handler'); +const K_EXECUTIONS = Symbol.for('executions'); +const K_ON_EXECUTION_COMPLETED = Symbol.for('execution completed handler'); function SubProcess(activityDef, context) { const triggeredByEvent = activityDef.behaviour && activityDef.behaviour.triggeredByEvent; const subProcess = new _Activity.default(SubProcessBehaviour, { @@ -54,18 +54,21 @@ function SubProcessBehaviour(activity, context) { this.environment = activity.environment; this.broker = activity.broker; this.executionId = undefined; - this[kExecutions] = new Set(); - this[kOnExecutionCompleted] = this._onExecutionCompleted.bind(this); + + /** @private */ + this[K_EXECUTIONS] = new Set(); + /** @private */ + this[K_ON_EXECUTION_COMPLETED] = this._onExecutionCompleted.bind(this); } Object.defineProperties(SubProcessBehaviour.prototype, { execution: { get() { - return [...this[kExecutions]][0]; + return [...this[K_EXECUTIONS]][0]; } }, executions: { get() { - return [...this[kExecutions]]; + return [...this[K_EXECUTIONS]]; } } }); @@ -86,7 +89,7 @@ SubProcessBehaviour.prototype.execute = function execute(executeMessage) { }; SubProcessBehaviour.prototype.getState = function getState() { const states = []; - for (const pe of this[kExecutions]) { + for (const pe of this[K_EXECUTIONS]) { const state = pe.getState(); state.environment = pe.environment.getState(); states.push(state); @@ -100,7 +103,7 @@ SubProcessBehaviour.prototype.getState = function getState() { }; SubProcessBehaviour.prototype.recover = function recover(state) { if (!state) return; - const executions = this[kExecutions]; + const executions = this[K_EXECUTIONS]; const loopCharacteristics = this.loopCharacteristics; if (loopCharacteristics && state.executions) { executions.clear(); @@ -120,7 +123,7 @@ SubProcessBehaviour.prototype.recover = function recover(state) { }; SubProcessBehaviour.prototype.getPostponed = function getPostponed() { let postponed = []; - for (const pe of this[kExecutions]) { + for (const pe of this[K_EXECUTIONS]) { postponed = postponed.concat(pe.getPostponed()); } return postponed; @@ -136,12 +139,13 @@ SubProcessBehaviour.prototype._upsertExecution = function upsertExecution(execut const subEnvironment = this.environment.clone(); const subContext = this.context.clone(subEnvironment, this.activity); execution = new _ProcessExecution.default(this.activity, subContext); - this[kExecutions].add(execution); + /** @private */ + this[K_EXECUTIONS].add(execution); this._addListeners(executionId); return execution; }; SubProcessBehaviour.prototype._addListeners = function addListeners(executionId) { - this.broker.subscribeTmp('subprocess-execution', `execution.#.${executionId}`, this[kOnExecutionCompleted], { + this.broker.subscribeTmp('subprocess-execution', `execution.#.${executionId}`, this[K_ON_EXECUTION_COMPLETED], { noAck: true, consumerTag: `_sub-process-execution-${executionId}` }); @@ -177,7 +181,8 @@ SubProcessBehaviour.prototype._onExecutionCompleted = function onExecutionComple SubProcessBehaviour.prototype._completeExecution = function completeExecution(completeRoutingKey, content) { if (this.loopCharacteristics) { const execution = this._getExecutionById(content.executionId); - this[kExecutions].delete(execution); + /** @private */ + this[K_EXECUTIONS].delete(execution); } this.broker.publish('execution', completeRoutingKey, (0, _messageHelper.cloneContent)(content)); }; @@ -194,7 +199,7 @@ SubProcessBehaviour.prototype.getApi = function getApi(apiMessage) { } }; SubProcessBehaviour.prototype._getExecutionById = function getExecutionById(executionId) { - for (const pe of this[kExecutions]) { + for (const pe of this[K_EXECUTIONS]) { if (pe.executionId === executionId) return pe; } }; \ No newline at end of file diff --git a/package.json b/package.json index 21cb04bc..321100fc 100644 --- a/package.json +++ b/package.json @@ -44,11 +44,12 @@ "test": "mocha -R @bonniernews/hot-bev -p -t 3000", "posttest": "npm run lint && npm run dist", "lint": "eslint . --cache && prettier . --check --cache", - "prepack": "npm run dist", + "prepack": "npm run dist && npm run types", "test:md": "texample ./docs/Examples.md,./docs/StartEvent.md,./docs/Extension.md,./docs/ConditionalEventDefinition.md", "cov:html": "c8 -r html -r text mocha -R @bonniernews/hot-bev -p -t 3000", "test:lcov": "c8 -r lcov mocha && npm run lint", - "dist": "babel src -d dist/" + "dist": "babel src -d dist/", + "types": "node scripts/build-types.js" }, "repository": { "type": "git", @@ -78,6 +79,14 @@ "src/**/*" ] }, + "overrides": { + "c8": { + "yargs": "^18.0.0" + }, + "mocha": { + "yargs": "^18.0.0" + } + }, "devDependencies": { "@aircall/expression-parser": "^1.0.4", "@babel/cli": "^7.24.1", @@ -85,6 +94,7 @@ "@babel/preset-env": "^7.24.4", "@babel/register": "^7.23.7", "@bonniernews/hot-bev": "^0.4.0", + "@eslint/js": "^10.0.1", "@types/bpmn-moddle": "^10.0.0", "@types/node": "^20.19.40", "bpmn-moddle": "^9.0.1", @@ -94,7 +104,7 @@ "chronokinesis": "^8.0.0", "debug": "^4.3.4", "dts-buddy": "^0.7.0", - "eslint": "^9.0.0", + "eslint": "^10.3.0", "globals": "^17.0.0", "mocha": "^11.0.1", "mocha-cakes-2": "^3.3.0", diff --git a/scripts/build-types.js b/scripts/build-types.js new file mode 100644 index 00000000..25b4374f --- /dev/null +++ b/scripts/build-types.js @@ -0,0 +1,27 @@ +import { readFileSync, appendFileSync } from 'node:fs'; +import { createBundle } from 'dts-buddy'; + +const output = 'types/index.d.ts'; +const augmentations = 'types/augmentations.d.ts'; + +createBundle({ + project: 'tsconfig.json', + output, + modules: { + 'bpmn-elements': 'src/index.js', + 'bpmn-elements/events': 'src/events/index.js', + 'bpmn-elements/eventDefinitions': 'src/eventDefinitions/index.js', + 'bpmn-elements/flows': 'src/flows/index.js', + 'bpmn-elements/gateways': 'src/gateways/index.js', + 'bpmn-elements/tasks': 'src/tasks/index.js', + }, +}) + .then(() => { + // Object.defineProperties getters can't be inferred from constructor functions, + // so the augmentation file declares them as interface members that merge with + // the dts-buddy-emitted classes. + appendFileSync(output, '\n' + readFileSync(augmentations, 'utf8')); + }) + .catch((err) => { + throw err; + }); diff --git a/src/Context.js b/src/Context.js index d134ee51..8925da72 100644 --- a/src/Context.js +++ b/src/Context.js @@ -1,9 +1,9 @@ import BpmnIO from './io/BpmnIO.js'; import Environment from './Environment.js'; import { getUniqueId } from './shared.js'; +import { K_ACTIVATED } from './constants.js'; -const kOwner = Symbol.for('owner'); -const kActivated = Symbol.for('activated'); +const K_OWNER = Symbol.for('owner'); /** * Build a runtime Context from a parsed BPMN definition. @@ -40,12 +40,14 @@ function ContextInstance(definitionContext, environment, owner) { ['dataObjectRefs', new Map()], ['dataStoreRefs', new Map()], ]); - this[kOwner] = owner; + /** @private */ + this[K_OWNER] = owner; } Object.defineProperty(ContextInstance.prototype, 'owner', { + /** @returns {import('types').Process | import('types').Activity | undefined} Process or sub-process activity that owns this context */ get() { - return this[kOwner]; + return this[K_OWNER]; }, }); @@ -193,7 +195,7 @@ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const bpContext = this.clone(this.environment.clone()); bp = new processDefinition.Behaviour(processDefinition, bpContext); processRefs.set(processId, bp); - bpContext[kOwner] = bp; + bpContext[K_OWNER] = bp; return bp; }; @@ -208,7 +210,7 @@ ContextInstance.prototype.getNewProcessById = function getNewProcessById(process const bpContext = this.clone(this.environment.clone()); const bp = new bpDef.Behaviour(bpDef, bpContext); - bpContext[kOwner] = bp; + bpContext[K_OWNER] = bp; return bp; }; @@ -334,7 +336,7 @@ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { * @param {string} activityId */ ContextInstance.prototype.getActivityParentById = function getActivityParentById(activityId) { - const owner = this[kOwner]; + const owner = this[K_OWNER]; if (owner) return owner; const activity = this.getActivityById(activityId); const parentId = activity.parent.id; @@ -362,7 +364,8 @@ function Extensions(activity, context, extensions) { const extension = Extension(activity, context); if (extension) result.push(extension); } - this[kActivated] = false; + /** @private */ + this[K_ACTIVATED] = false; } Object.defineProperty(Extensions.prototype, 'count', { @@ -372,13 +375,15 @@ Object.defineProperty(Extensions.prototype, 'count', { }); Extensions.prototype.activate = function activate(message) { - if (this[kActivated]) return; - this[kActivated] = true; + if (this[K_ACTIVATED]) return; + /** @private */ + this[K_ACTIVATED] = true; for (const extension of this.extensions) extension.activate(message); }; Extensions.prototype.deactivate = function deactivate(message) { - if (!this[kActivated]) return; - this[kActivated] = false; + if (!this[K_ACTIVATED]) return; + /** @private */ + this[K_ACTIVATED] = false; for (const extension of this.extensions) extension.deactivate(message); }; diff --git a/src/Environment.js b/src/Environment.js index 6b989354..43c3db60 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -2,8 +2,8 @@ import Expressions from './Expressions.js'; import { Scripts } from './Scripts.js'; import { Timers } from './Timers.js'; -const kServices = Symbol.for('services'); -const kVariables = Symbol.for('variables'); +const K_SERVICES = Symbol.for('services'); +const K_VARIABLES = Symbol.for('variables'); const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', 'scripts', 'services', 'settings', 'timers', 'variables']); @@ -22,22 +22,24 @@ export default function Environment(options = {}) { this.timers = options.timers || new Timers(); this.settings = { skipDiscard: true, ...options.settings }; this.Logger = options.Logger || DummyLogger; - this[kServices] = options.services || {}; - this[kVariables] = options.variables || {}; + /** @private */ + this[K_SERVICES] = options.services || {}; + /** @private */ + this[K_VARIABLES] = options.variables || {}; } Object.defineProperties(Environment.prototype, { variables: { get() { - return this[kVariables]; + return this[K_VARIABLES]; }, }, services: { get() { - return this[kServices]; + return this[K_SERVICES]; }, set(value) { - const services = this[kServices]; + const services = this[K_SERVICES]; for (const name in services) { if (!(name in value)) delete services[name]; } @@ -52,7 +54,7 @@ Object.defineProperties(Environment.prototype, { Environment.prototype.getState = function getState() { return { settings: { ...this.settings }, - variables: { ...this[kVariables] }, + variables: { ...this[K_VARIABLES] }, output: { ...this.output }, }; }; @@ -61,13 +63,13 @@ Environment.prototype.getState = function getState() { * Restore environment state captured by getState. Merges into the existing settings, * variables, and output rather than replacing them. * @param {import('types').EnvironmentState} [state] - * @returns this + * @returns {this} */ Environment.prototype.recover = function recover(state) { if (!state) return this; if (state.settings) Object.assign(this.settings, state.settings); - if (state.variables) Object.assign(this[kVariables], state.variables); + if (state.variables) Object.assign(this[K_VARIABLES], state.variables); if (state.output) Object.assign(this.output, state.output); return this; @@ -79,10 +81,10 @@ Environment.prototype.recover = function recover(state) { * @param {import('types').EnvironmentOptions} [overrideOptions] */ Environment.prototype.clone = function clone(overrideOptions) { - const services = this[kServices]; + const services = this[K_SERVICES]; const newOptions = { settings: { ...this.settings }, - variables: { ...this[kVariables] }, + variables: { ...this[K_VARIABLES] }, Logger: this.Logger, extensions: this.extensions, scripts: this.scripts, @@ -105,7 +107,8 @@ Environment.prototype.clone = function clone(overrideOptions) { Environment.prototype.assignVariables = function assignVariables(newVars) { if (!newVars || typeof newVars !== 'object') return; - this[kVariables] = { + /** @private */ + this[K_VARIABLES] = { ...this.variables, ...newVars, }; @@ -114,7 +117,7 @@ Environment.prototype.assignVariables = function assignVariables(newVars) { /** * Merge settings into the environment. Non-objects are ignored. * @param {import('types').EnvironmentSettings} newSettings - * @returns this + * @returns {this} */ Environment.prototype.assignSettings = function assignSettings(newSettings) { if (!newSettings || typeof newSettings !== 'object') return this; @@ -149,7 +152,7 @@ Environment.prototype.registerScript = function registerScript(...args) { * @param {string} serviceName */ Environment.prototype.getServiceByName = function getServiceByName(serviceName) { - return this[kServices][serviceName]; + return this[K_SERVICES][serviceName]; }; /** @@ -173,7 +176,8 @@ Environment.prototype.resolveExpression = function resolveExpression(expression, * @param {CallableFunction} fn */ Environment.prototype.addService = function addService(name, fn) { - this[kServices][name] = fn; + /** @private */ + this[K_SERVICES][name] = fn; }; function validateOptions(input) { diff --git a/src/MessageFormatter.js b/src/MessageFormatter.js index 7061c313..890e87c6 100644 --- a/src/MessageFormatter.js +++ b/src/MessageFormatter.js @@ -2,9 +2,9 @@ import { cloneMessage } from './messageHelper.js'; import { getUniqueId } from './shared.js'; import { ActivityError } from './error/Errors.js'; import { getRoutingKeyPattern } from 'smqp'; +import { K_EXECUTION } from './constants.js'; -const kOnMessage = Symbol.for('onMessage'); -const kExecution = Symbol.for('execution'); +const K_ON_MESSAGE = Symbol.for('onMessage'); const EXEC_ROUTING_KEY = 'run._formatting.exec'; @@ -19,7 +19,8 @@ export function Formatter(element) { this.id = id; this.broker = broker; this.logger = logger; - this[kOnMessage] = this._onMessage.bind(this); + /** @private */ + this[K_ON_MESSAGE] = this._onMessage.bind(this); } /** @@ -35,7 +36,8 @@ Formatter.prototype.format = function format(message, callback) { broker.publish('format', EXEC_ROUTING_KEY, {}, { correlationId, persistent: false }); - this[kExecution] = { + /** @private */ + this[K_EXECUTION] = { correlationId, formatKey: message.fields.routingKey, runMessage: cloneMessage(message), @@ -45,7 +47,7 @@ Formatter.prototype.format = function format(message, callback) { executeMessage: null, }; - broker.consume('format-run-q', this[kOnMessage], { + broker.consume('format-run-q', this[K_ON_MESSAGE], { consumerTag, prefetch: 100, }); @@ -53,7 +55,7 @@ Formatter.prototype.format = function format(message, callback) { /** @internal */ Formatter.prototype._onMessage = function onMessage(routingKey, message) { - const { formatKey, correlationId, pending, executeMessage } = this[kExecution]; + const { formatKey, correlationId, pending, executeMessage } = this[K_EXECUTION]; const asyncFormatting = pending.size; if (routingKey === EXEC_ROUTING_KEY) { @@ -62,7 +64,8 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { if (!asyncFormatting) { return this._complete(message); } - this[kExecution].executeMessage = message; + /** @private */ + this[K_EXECUTION].executeMessage = message; } else { message.ack(); @@ -93,8 +96,9 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { /** @internal */ Formatter.prototype._complete = function complete(message, isError) { - const { runMessage, formatKey, callback, formatted, executeMessage } = this[kExecution]; - this[kExecution] = null; + const { runMessage, formatKey, callback, formatted, executeMessage } = this[K_EXECUTION]; + /** @private */ + this[K_EXECUTION] = null; if (executeMessage) executeMessage.ack(); this.broker.cancel(message.fields.consumerTag); @@ -111,7 +115,7 @@ Formatter.prototype._complete = function complete(message, isError) { /** @internal */ Formatter.prototype._enrich = function enrich(withContent) { - const content = this[kExecution].runMessage.content; + const content = this[K_EXECUTION].runMessage.content; for (const key in withContent) { switch (key) { case 'id': @@ -128,7 +132,8 @@ Formatter.prototype._enrich = function enrich(withContent) { break; default: { content[key] = withContent[key]; - this[kExecution].formatted = true; + /** @private */ + this[K_EXECUTION].formatted = true; } } } diff --git a/src/Timers.js b/src/Timers.js index caa2da28..20be0244 100644 --- a/src/Timers.js +++ b/src/Timers.js @@ -1,5 +1,5 @@ -const kExecuting = Symbol.for('executing'); -const kTimerApi = Symbol.for('timers api'); +const K_EXECUTING = Symbol.for('executing'); +const K_TIMER_API = Symbol.for('timers api'); const MAX_DELAY = 2147483647; @@ -10,14 +10,15 @@ export function Timers(options) { clearTimeout, ...options, }; - this[kExecuting] = new Set(); + /** @private */ + this[K_EXECUTING] = new Set(); this.setTimeout = this.setTimeout.bind(this); this.clearTimeout = this.clearTimeout.bind(this); } Object.defineProperty(Timers.prototype, 'executing', { get() { - return [...this[kExecuting]]; + return [...this[K_EXECUTING]]; }, }); @@ -30,7 +31,7 @@ Timers.prototype.setTimeout = function wrappedSetTimeout(callback, delay, ...arg }; Timers.prototype.clearTimeout = function wrappedClearTimeout(ref) { - if (this[kExecuting].delete(ref)) { + if (this[K_EXECUTING].delete(ref)) { ref.timerRef = this.options.clearTimeout(ref.timerRef); return; } @@ -38,7 +39,7 @@ Timers.prototype.clearTimeout = function wrappedClearTimeout(ref) { }; Timers.prototype._setTimeout = function setTimeout(owner, callback, delay, ...args) { - const executing = this[kExecuting]; + const executing = this[K_EXECUTING]; const ref = this._getReference(owner, callback, delay, args); executing.add(ref); if (delay < MAX_DELAY) { @@ -57,19 +58,21 @@ Timers.prototype._getReference = function getReference(owner, callback, delay, a }; function RegisteredTimers(timersApi, owner) { - this[kTimerApi] = timersApi; + /** @private */ + this[K_TIMER_API] = timersApi; this.owner = owner; this.setTimeout = this.setTimeout.bind(this); this.clearTimeout = this.clearTimeout.bind(this); } RegisteredTimers.prototype.setTimeout = function registeredSetTimeout(callback, delay, ...args) { - const timersApi = this[kTimerApi]; + const timersApi = this[K_TIMER_API]; return timersApi._setTimeout(this.owner, callback, delay, ...args); }; RegisteredTimers.prototype.clearTimeout = function registeredClearTimeout(ref) { - this[kTimerApi].clearTimeout(ref); + /** @private */ + this[K_TIMER_API].clearTimeout(ref); }; function Timer(owner, timerId, callback, delay, args) { diff --git a/src/activity/Activity.js b/src/activity/Activity.js index c51af2e6..337880f3 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -6,21 +6,23 @@ import { Formatter } from '../MessageFormatter.js'; import { cloneContent, cloneParent, cloneMessage } from '../messageHelper.js'; import { makeErrorFromMessage, ActivityError } from '../error/Errors.js'; import { OutboundEvaluator, formatFlowAction } from './outbound-evaluator.js'; - -const kActivityDef = Symbol.for('activityDefinition'); -const kConsuming = Symbol.for('consuming'); -const kConsumingRunQ = Symbol.for('run queue consumer'); -const kCounters = Symbol.for('counters'); -const kEventDefinitions = Symbol.for('eventDefinitions'); -const kExec = Symbol.for('exec'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kExtensions = Symbol.for('extensions'); -const kFlags = Symbol.for('flags'); -const kFlows = Symbol.for('flows'); -const kFormatter = Symbol.for('formatter'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kStateMessage = Symbol.for('stateMessage'); -const kActivated = Symbol.for('activated'); +import { + K_ACTIVATED, + K_CONSUMING, + K_COUNTERS, + K_EXECUTE_MESSAGE, + K_EXTENSIONS, + K_MESSAGE_HANDLERS, + K_STATE_MESSAGE, +} from '../constants.js'; + +const K_ACTIVITY_DEF = Symbol.for('activityDefinition'); +const K_CONSUMING_RUN_Q = Symbol.for('run queue consumer'); +const K_EVENT_DEFINITIONS = Symbol.for('eventDefinitions'); +const K_EXEC = Symbol.for('exec'); +const K_FLAGS = Symbol.for('flags'); +const K_FLOWS = Symbol.for('flows'); +const K_FORMATTER = Symbol.for('formatter'); export default Activity; @@ -30,11 +32,12 @@ export default Activity; * @param {import('moddle-context-serializer').SerializableElement} activityDef Parsed BPMN element definition * @param {import('types').ContextInstance} context Per-execution registry and factory */ -function Activity(Behaviour, activityDef, context) { +export function Activity(Behaviour, activityDef, context) { const { id, type = 'activity', name, behaviour = {} } = activityDef; const { attachedTo: attachedToRef, eventDefinitions } = behaviour; - this[kActivityDef] = activityDef; + /** @private */ + this[K_ACTIVITY_DEF] = activityDef; this.id = id; this.type = type; this.name = name; @@ -44,7 +47,8 @@ function Activity(Behaviour, activityDef, context) { this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; - this[kCounters] = { + /** @private */ + this[K_COUNTERS] = { taken: 0, discarded: 0, }; @@ -79,7 +83,8 @@ function Activity(Behaviour, activityDef, context) { const inboundSourceIds = new Set(inboundSequenceFlows.map(({ sourceId }) => sourceId)); const isParallelJoin = activityDef.isParallelGateway && inboundSourceIds.size > 1; - this[kFlows] = { + /** @private */ + this[K_FLOWS] = { inboundSequenceFlows, inboundAssociations, inboundTriggers, @@ -87,7 +92,8 @@ function Activity(Behaviour, activityDef, context) { outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows), }; - this[kFlags] = { + /** @private */ + this[K_FLAGS] = { isEnd: !outboundSequenceFlows.length, isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, @@ -101,133 +107,139 @@ function Activity(Behaviour, activityDef, context) { isCatching: activityDef.isCatching, lane: activityDef.lane?.id, }; - this[kExec] = new Map(); + /** @private */ + this[K_EXEC] = new Map(); - this[kMessageHandlers] = { + /** @private */ + this[K_MESSAGE_HANDLERS] = { onInbound: this._onInbound.bind(this), onRunMessage: this._onRunMessage.bind(this), onApiMessage: this._onApiMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this), }; - this[kEventDefinitions] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); - this[kExtensions] = context.loadExtensions(this); - this[kConsuming] = false; - this[kConsumingRunQ] = undefined; + /** @private */ + this[K_EVENT_DEFINITIONS] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); + /** @private */ + this[K_EXTENSIONS] = context.loadExtensions(this); + /** @private */ + this[K_CONSUMING] = false; + /** @private */ + this[K_CONSUMING_RUN_Q] = undefined; } Object.defineProperties(Activity.prototype, { counters: { get() { - return { ...this[kCounters] }; + return { ...this[K_COUNTERS] }; }, }, execution: { get() { - return this[kExec].get('execution'); + return this[K_EXEC].get('execution'); }, }, executionId: { get() { - return this[kExec].get('executionId'); + return this[K_EXEC].get('executionId'); }, }, extensions: { get() { - return this[kExtensions]; + return this[K_EXTENSIONS]; }, }, bpmnIo: { get() { - const extensions = this[kExtensions]; + const extensions = this[K_EXTENSIONS]; return extensions?.extensions.find((e) => e.type === 'bpmnio'); }, }, formatter: { get() { - let formatter = this[kFormatter]; + let formatter = this[K_FORMATTER]; if (formatter) return formatter; - formatter = this[kFormatter] = new Formatter(this); + formatter = this[K_FORMATTER] = new Formatter(this); return formatter; }, }, isRunning: { get() { - if (!this[kConsuming]) return false; + if (!this[K_CONSUMING]) return false; return !!this.status; }, }, outbound: { get() { - return this[kFlows].outboundSequenceFlows; + return this[K_FLOWS].outboundSequenceFlows; }, }, inbound: { get() { - return this[kFlows].inboundSequenceFlows; + return this[K_FLOWS].inboundSequenceFlows; }, }, isEnd: { get() { - return this[kFlags].isEnd; + return this[K_FLAGS].isEnd; }, }, isStart: { get() { - return this[kFlags].isStart; + return this[K_FLAGS].isStart; }, }, isSubProcess: { get() { - return this[kFlags].isSubProcess; + return this[K_FLAGS].isSubProcess; }, }, isTransaction: { get() { - return this[kFlags].isTransaction; + return this[K_FLAGS].isTransaction; }, }, isMultiInstance: { get() { - return this[kFlags].isMultiInstance; + return this[K_FLAGS].isMultiInstance; }, }, isThrowing: { get() { - return this[kFlags].isThrowing; + return this[K_FLAGS].isThrowing; }, }, isCatching: { get() { - return this[kFlags].isCatching; + return this[K_FLAGS].isCatching; }, }, isForCompensation: { get() { - return this[kFlags].isForCompensation; + return this[K_FLAGS].isForCompensation; }, }, isParallelJoin: { get() { - return this[kFlags].isParallelJoin; + return this[K_FLAGS].isParallelJoin; }, }, triggeredByEvent: { get() { - return this[kActivityDef].triggeredByEvent; + return this[K_ACTIVITY_DEF].triggeredByEvent; }, }, attachedTo: { get() { - const attachedToId = this[kFlags].attachedTo; + const attachedToId = this[K_FLAGS].attachedTo; if (!attachedToId) return null; return this.getActivityById(attachedToId); }, }, lane: { get() { - const laneId = this[kFlags].lane; + const laneId = this[K_FLAGS].lane; if (!laneId) return undefined; const parent = this.parentElement; return parent.getLaneById && parent.getLaneById(laneId); @@ -235,18 +247,17 @@ Object.defineProperties(Activity.prototype, { }, eventDefinitions: { get() { - return this[kEventDefinitions]; + return this[K_EVENT_DEFINITIONS]; }, }, parentElement: { - /** Parent process or sub process reference */ get() { return this.context.getActivityParentById(this.id); }, }, initialized: { get() { - return !!this[kExec]?.get('initExecutionId'); + return !!this[K_EXEC]?.get('initExecutionId'); }, }, }); @@ -255,8 +266,9 @@ Object.defineProperties(Activity.prototype, { * Subscribe to inbound flows and start consuming the inbound queue. */ Activity.prototype.activate = function activate() { - if (this[kActivated]) return; - this[kActivated] = true; + if (this[K_ACTIVATED]) return; + /** @private */ + this[K_ACTIVATED] = true; return this.addInboundListeners() && this._consumeInbound(); }; @@ -264,7 +276,8 @@ Activity.prototype.activate = function activate() { * Cancel inbound subscriptions and any pending run/format consumers. */ Activity.prototype.deactivate = function deactivate() { - this[kActivated] = false; + /** @private */ + this[K_ACTIVATED] = false; const broker = this.broker; this.removeInboundListeners(); broker.cancel('_run-on-inbound'); @@ -277,7 +290,7 @@ Activity.prototype.deactivate = function deactivate() { */ Activity.prototype.init = function init(initContent) { const id = this.id; - const exec = this[kExec]; + const exec = this[K_EXEC]; const executionId = exec.has('initExecutionId') ? exec.get('initExecutionId') : getUniqueId(id); exec.set('initExecutionId', executionId); this.logger.debug(`<${id}> initialized with executionId <${executionId}>`); @@ -293,7 +306,7 @@ Activity.prototype.run = function run(runContent) { const id = this.id; if (this.isRunning) throw new Error(`activity <${id}> is already running`); - const exec = this[kExec]; + const exec = this[K_EXEC]; const executionId = exec.get('initExecutionId') || getUniqueId(id); exec.set('executionId', executionId); exec.delete('initExecutionId'); @@ -306,7 +319,8 @@ Activity.prototype.run = function run(runContent) { broker.publish('run', 'run.enter', content); broker.publish('run', 'run.start', cloneContent(content)); - this[kConsuming] = true; + /** @private */ + this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -316,7 +330,7 @@ Activity.prototype.run = function run(runContent) { */ Activity.prototype.getState = function getState() { const status = this.status; - const exec = this[kExec]; + const exec = this[K_EXEC]; const execution = exec.get('execution'); const executionId = exec.get('executionId'); const brokerState = this.broker.getState(true); @@ -337,7 +351,7 @@ Activity.prototype.getState = function getState() { /** * Restore activity state captured by getState. Cannot be called while running. * @param {import('types').ActivityState} [state] - * @returns this when state was applied + * @returns {this} this when state was applied * @throws {Error} when activity is currently running */ Activity.prototype.recover = function recover(state) { @@ -346,10 +360,11 @@ Activity.prototype.recover = function recover(state) { this.stopped = state.stopped; this.status = state.status; - const exec = this[kExec]; + const exec = this[K_EXEC]; exec.set('executionId', state.executionId); - this[kCounters] = { ...this[kCounters], ...state.counters }; + /** @private */ + this[K_COUNTERS] = { ...this[K_COUNTERS], ...state.counters }; if (state.execution) { exec.set('execution', new ActivityExecution(this, this.context).recover(state.execution)); @@ -365,7 +380,7 @@ Activity.prototype.recover = function recover(state) { * @throws {Error} when called on a running activity */ Activity.prototype.resume = function resume() { - if (this[kConsuming]) { + if (this[K_CONSUMING]) { throw new Error(`cannot resume running activity <${this.id}>`); } if (!this.status) return this.activate(); @@ -377,7 +392,8 @@ Activity.prototype.resume = function resume() { const content = this._createMessage(); this.broker.publish('run', 'run.resume', content, { persistent: false }); - this[kConsuming] = true; + /** @private */ + this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -387,14 +403,15 @@ Activity.prototype.resume = function resume() { */ Activity.prototype.discard = function discard(discardContent) { if (!this.status) return this._runDiscard(discardContent); - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (execution && !execution.completed) return execution.discard(); this._deactivateRunConsumers(); const broker = this.broker; broker.getQueue('run-q').purge(); - broker.publish('run', 'run.discard', cloneContent(this[kStateMessage].content)); - this[kConsuming] = true; + broker.publish('run', 'run.discard', cloneContent(this[K_STATE_MESSAGE].content)); + /** @private */ + this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -403,7 +420,7 @@ Activity.prototype.discard = function discard(discardContent) { * @returns count of subscribed triggers */ Activity.prototype.addInboundListeners = function addInboundListeners() { - const triggers = this[kFlows].inboundTriggers; + const triggers = this[K_FLOWS].inboundTriggers; if (triggers.length) { const onInboundEvent = this._onInboundEvent.bind(this); const triggerConsumerTag = `_inbound-${this.id}`; @@ -425,7 +442,7 @@ Activity.prototype.addInboundListeners = function addInboundListeners() { */ Activity.prototype.removeInboundListeners = function removeInboundListeners() { const triggerConsumerTag = `_inbound-${this.id}`; - for (const trigger of this[kFlows].inboundTriggers) { + for (const trigger of this[K_FLOWS].inboundTriggers) { trigger.broker.cancel(triggerConsumerTag); } }; @@ -434,8 +451,8 @@ Activity.prototype.removeInboundListeners = function removeInboundListeners() { * Stop the activity. If not currently running, just cancels the inbound consumer. */ Activity.prototype.stop = function stop() { - if (!this[kConsuming]) return this.broker.cancel('_run-on-inbound'); - return this.getApi(this[kStateMessage]).stop(); + if (!this[K_CONSUMING]) return this.broker.cancel('_run-on-inbound'); + return this.getApi(this[K_STATE_MESSAGE]).stop(); }; /** @@ -443,7 +460,7 @@ Activity.prototype.stop = function stop() { */ Activity.prototype.next = function next() { if (!this.environment.settings.step) return; - const stateMessage = this[kStateMessage]; + const stateMessage = this[K_STATE_MESSAGE]; if (!stateMessage) return; if (this.status === 'executing') return false; if (this.status === 'formatting') return false; @@ -466,7 +483,7 @@ Activity.prototype.shake = function shake() { * @param {(err: Error, evaluationResult: any) => void} callback */ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) { - return this[kFlows].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); + return this[K_FLOWS].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); }; /** @@ -474,9 +491,9 @@ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, dis * @param {import('types').ElementBrokerMessage} [message] */ Activity.prototype.getApi = function getApi(message) { - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (execution && !execution.completed) return execution.getApi(message); - return ActivityApi(this.broker, message || this[kStateMessage]); + return ActivityApi(this.broker, message || this[K_STATE_MESSAGE]); }; /** @@ -489,7 +506,7 @@ Activity.prototype.getActivityById = function getActivityById(elementId) { /** @internal */ Activity.prototype._runDiscard = function runDiscard(discardContent) { - const exec = this[kExec]; + const exec = this[K_EXEC]; const executionId = exec.get('initExecutionId') || getUniqueId(this.id); exec.set('executionId', executionId); exec.delete('initExecutionId'); @@ -499,7 +516,8 @@ Activity.prototype._runDiscard = function runDiscard(discardContent) { const content = this._createMessage({ ...discardContent, executionId }); this.broker.publish('run', 'run.discard', content); - this[kConsuming] = true; + /** @private */ + this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -508,7 +526,7 @@ Activity.prototype._discardRun = function discardRun() { const status = this.status; if (!status) return; - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (execution && !execution.completed) return; let discardRoutingKey = 'run.discard'; @@ -526,20 +544,21 @@ Activity.prototype._discardRun = function discardRun() { this._deactivateRunConsumers(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[K_STATE_MESSAGE]; if (this.extensions) this.extensions.deactivate(cloneMessage(stateMessage)); const broker = this.broker; broker.getQueue('run-q').purge(); broker.publish('run', discardRoutingKey, cloneContent(stateMessage.content), { correlationId: stateMessage.properties.correlationId }); - this[kConsuming] = true; + /** @private */ + this[K_CONSUMING] = true; this._consumeRunQ(); }; /** @internal */ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { - if (this[kFlags].isParallelGateway) { + if (this[K_FLAGS].isParallelGateway) { const message = cloneMessage(sourceMessage, { join: this.id }); message.content.sequence.push({ id: this.id, type: this.type }); return this.broker.publish('event', 'activity.shake.join', message.content, { @@ -562,13 +581,13 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { this.broker.publish('api', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); - if (this[kFlags].isEnd) { + if (this[K_FLAGS].isEnd) { return this.broker.publish('event', 'activity.shake.end', cloneContent(message.content), { persistent: false, type: 'shake' }); } const targets = new Map(); - for (const outboundFlow of this[kFlows].outboundSequenceFlows) { + for (const outboundFlow of this[K_FLOWS].outboundSequenceFlows) { const prevTarget = targets.get(outboundFlow.targetId); if (!prevTarget) { targets.set(outboundFlow.targetId, outboundFlow); @@ -580,12 +599,12 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { /** @internal */ Activity.prototype._consumeInbound = function consumeInbound() { - if (!this[kActivated]) return; + if (!this[K_ACTIVATED]) return; - if (this.status || !this[kFlows].inboundTriggers.length) return; + if (this.status || !this[K_FLOWS].inboundTriggers.length) return; const inboundQ = this.broker.getQueue('inbound-q'); - const onInbound = this[kMessageHandlers].onInbound; + const onInbound = this[K_MESSAGE_HANDLERS].onInbound; return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); }; @@ -613,7 +632,7 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { let discardSequence; if (content.discardSequence) discardSequence = content.discardSequence.slice(); const context = { inbound, discardSequence }; - return this[kFlags].isParallelGateway ? this.run(context) : this._runDiscard(context); + return this[K_FLAGS].isParallelGateway ? this.run(context) : this._runDiscard(context); } } }; @@ -626,7 +645,7 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message switch (routingKey) { case 'activity.enter': case 'activity.discard': { - if (content.id === this[kFlags].attachedTo) { + if (content.id === this[K_FLAGS].attachedTo) { inboundQ.queueMessage(fields, cloneContent(content), properties); } break; @@ -643,15 +662,17 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message /** @internal */ Activity.prototype._consumeRunQ = function consumeRunQ() { - this[kConsumingRunQ] = true; - this.broker.getQueue('run-q').assertConsumer(this[kMessageHandlers].onRunMessage, { exclusive: true, consumerTag: '_activity-run' }); + /** @private */ + this[K_CONSUMING_RUN_Q] = true; + this.broker.getQueue('run-q').assertConsumer(this[K_MESSAGE_HANDLERS].onRunMessage, { exclusive: true, consumerTag: '_activity-run' }); }; /** @internal */ Activity.prototype._pauseRunQ = function pauseRunQ() { - if (!this[kConsumingRunQ]) return; + if (!this[K_CONSUMING_RUN_Q]) return; - this[kConsumingRunQ] = false; + /** @private */ + this[K_CONSUMING_RUN_Q] = false; this.broker.cancel('_activity-run'); }; @@ -689,7 +710,8 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, const id = this.id; const step = this.environment.settings.step; - this[kStateMessage] = message; + /** @private */ + this[K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { @@ -697,7 +719,8 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, this.status = 'entered'; if (!isRedelivered) { - this[kExec].delete('execution'); + /** @private */ + this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate(cloneMessage(message)); this._publishEvent('enter', content, { correlationId }); } @@ -707,7 +730,8 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, this.logger.debug(`<${id}> discard`, isRedelivered ? 'redelivered' : ''); this.status = 'discard'; - this[kExec].delete('execution'); + /** @private */ + this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate(cloneMessage(message)); @@ -727,20 +751,22 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, break; } case 'run.execute.passthrough': { - const execution = this[kExec].get('execution'); + const execution = this[K_EXEC].get('execution'); if (!isRedelivered && execution) { if (execution.completed) return message.ack(); - this[kExecuteMessage] = message; + /** @private */ + this[K_EXECUTE_MESSAGE] = message; return execution.passthrough(message); } } case 'run.execute': { this.status = 'executing'; - this[kExecuteMessage] = message; + /** @private */ + this[K_EXECUTE_MESSAGE] = message; if (isRedelivered && this.extensions) this.extensions.activate(cloneMessage(message)); - const exec = this[kExec]; + const exec = this[K_EXEC]; let execution = exec.get('execution'); if (!execution) { execution = new ActivityExecution(this, this.context); @@ -749,14 +775,15 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, this.broker .getQueue('execution-q') - .assertConsumer(this[kMessageHandlers].onExecutionMessage, { exclusive: true, consumerTag: '_activity-execution' }); + .assertConsumer(this[K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, consumerTag: '_activity-execution' }); return execution.execute(message); } case 'run.end': { this.logger.debug(`<${id}> end`, isRedelivered ? 'redelivered' : ''); if (isRedelivered) break; - this[kCounters].taken++; + /** @private */ + this[K_COUNTERS].taken++; this.status = 'end'; @@ -778,7 +805,8 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, } case 'run.discarded': { this.logger.debug(`<${content.executionId} (${id})> discarded`); - this[kCounters].discarded++; + /** @private */ + this[K_COUNTERS].discarded++; this.status = 'discarded'; content.outbound = undefined; @@ -824,7 +852,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, /** @internal */ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) { - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[K_EXECUTE_MESSAGE]; const content = cloneContent({ ...executeMessage.content, ...message.content, @@ -871,7 +899,7 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, /** @internal */ Activity.prototype._ackRunExecuteMessage = function ackRunExecuteMessage() { if (this.environment.settings.step) return; - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[K_EXECUTE_MESSAGE]; executeMessage.ack(); }; @@ -904,13 +932,13 @@ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOut /** @internal */ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) { - const outboundSequenceFlows = this[kFlows].outboundSequenceFlows; + const outboundSequenceFlows = this[K_FLOWS].outboundSequenceFlows; if (!outboundSequenceFlows.length) return callback(null, []); const fromContent = fromMessage.content; let discardSequence = fromContent.discardSequence; - if (isDiscarded && !discardSequence && this[kFlags].attachedTo && fromContent.inbound?.[0]) { + if (isDiscarded && !discardSequence && this[K_FLAGS].attachedTo && fromContent.inbound?.[0]) { discardSequence = [fromContent.inbound[0].id]; } @@ -983,7 +1011,7 @@ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlo Activity.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[K_STATE_MESSAGE]; const fields = stateMessage.fields; if (!fields.redelivered) return; @@ -1016,11 +1044,12 @@ Activity.prototype._publishEvent = function publishEvent(state, content, propert /** @internal */ Activity.prototype._onStop = function onStop(message) { - const running = this[kConsuming]; + const running = this[K_CONSUMING]; this.stopped = true; - this[kConsuming] = false; + /** @private */ + this[K_CONSUMING] = false; const broker = this.broker; this._pauseRunQ(); broker.cancel('_activity-api'); @@ -1037,11 +1066,11 @@ Activity.prototype._onStop = function onStop(message) { /** @internal */ Activity.prototype._consumeApi = function consumeApi() { - const executionId = this[kExec].get('executionId'); + const executionId = this[K_EXEC].get('executionId'); if (!executionId) return; const broker = this.broker; broker.cancel('_activity-api'); - broker.subscribeTmp('api', `activity.*.${executionId}`, this[kMessageHandlers].onApiMessage, { + broker.subscribeTmp('api', `activity.*.${executionId}`, this[K_MESSAGE_HANDLERS].onApiMessage, { noAck: true, consumerTag: '_activity-api', priority: 100, @@ -1076,7 +1105,7 @@ Activity.prototype._createMessage = function createMessage(override) { ...(parent && { parent: cloneParent(parent) }), }; - for (const [flag, value] of Object.entries(this[kFlags])) { + for (const [flag, value] of Object.entries(this[K_FLAGS])) { if (value) result[flag] = value; } @@ -1085,7 +1114,7 @@ Activity.prototype._createMessage = function createMessage(override) { /** @internal */ Activity.prototype._getOutboundSequenceFlowById = function getOutboundSequenceFlowById(flowId) { - return this[kFlows].outboundSequenceFlows.find((flow) => flow.id === flowId); + return this[K_FLOWS].outboundSequenceFlows.find((flow) => flow.id === flowId); }; /** @internal */ @@ -1094,5 +1123,6 @@ Activity.prototype._deactivateRunConsumers = function _deactivateRunConsumers() broker.cancel('_activity-api'); this._pauseRunQ(); broker.cancel('_activity-execution'); - this[kConsuming] = false; + /** @private */ + this[K_CONSUMING] = false; }; diff --git a/src/activity/ActivityExecution.js b/src/activity/ActivityExecution.js index 0a17138f..27285af5 100644 --- a/src/activity/ActivityExecution.js +++ b/src/activity/ActivityExecution.js @@ -1,11 +1,9 @@ import { ActivityApi } from '../Api.js'; import { cloneContent, cloneMessage } from '../messageHelper.js'; +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS } from '../constants.js'; -const kCompleted = Symbol.for('completed'); -const kExecuteQ = Symbol.for('executeQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kPostponed = Symbol.for('postponed'); +const K_EXECUTE_Q = Symbol.for('executeQ'); +const K_POSTPONED = Symbol.for('postponed'); export default ActivityExecution; @@ -20,19 +18,24 @@ function ActivityExecution(activity, context) { this.context = context; this.id = activity.id; this.broker = activity.broker; - this[kPostponed] = new Set(); - this[kCompleted] = false; - this[kExecuteQ] = this.broker.assertQueue('execute-q', { durable: true, autoDelete: false }); - - this[kMessageHandlers] = { + /** @private */ + this[K_POSTPONED] = new Set(); + /** @private */ + this[K_COMPLETED] = false; + /** @private */ + this[K_EXECUTE_Q] = this.broker.assertQueue('execute-q', { durable: true, autoDelete: false }); + + /** @private */ + this[K_MESSAGE_HANDLERS] = { onParentApiMessage: this._onParentApiMessage.bind(this), onExecuteMessage: this._onExecuteMessage.bind(this), }; } Object.defineProperty(ActivityExecution.prototype, 'completed', { + /** @returns {boolean} */ get() { - return this[kCompleted]; + return this[K_COMPLETED]; }, }); @@ -47,14 +50,15 @@ ActivityExecution.prototype.execute = function execute(executeMessage) { if (!executionId) throw new Error('Execution requires execution id'); this.executionId = executionId; - const initMessage = (this[kExecuteMessage] = cloneMessage(executeMessage, { + const initMessage = (this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage, { executionId, state: 'start', isRootScope: true, })); if (executeMessage.fields.redelivered) { - this[kPostponed].clear(); + /** @private */ + this[K_POSTPONED].clear(); this._debug('resume execution'); if (!this.source) this.source = new this.activity.Behaviour(this.activity, this.context); @@ -73,21 +77,22 @@ ActivityExecution.prototype.execute = function execute(executeMessage) { * Bind the execute queue and start consuming execute and api messages. */ ActivityExecution.prototype.activate = function activate() { - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; const broker = this.broker; const batchSize = this.activity.environment.settings.batchSize || 50; broker.bindQueue('execute-q', 'execution', 'execute.#', { priority: 100 }); - const { onExecuteMessage, onParentApiMessage } = this[kMessageHandlers]; - this[kExecuteQ].assertConsumer(onExecuteMessage, { + const { onExecuteMessage, onParentApiMessage } = this[K_MESSAGE_HANDLERS]; + /** @private */ + this[K_EXECUTE_Q].assertConsumer(onExecuteMessage, { exclusive: true, prefetch: batchSize * 2, priority: 100, consumerTag: '_activity-execute', }); - if (this[kCompleted]) return this.deactivate(); + if (this[K_COMPLETED]) return this.deactivate(); broker.subscribeTmp('api', `activity.*.${this.executionId}`, onParentApiMessage, { noAck: true, @@ -110,8 +115,8 @@ ActivityExecution.prototype.deactivate = function deactivate() { * Discard the running execution. */ ActivityExecution.prototype.discard = function discard() { - if (this[kCompleted]) return; - const initMessage = this[kExecuteMessage]; + if (this[K_COMPLETED]) return; + const initMessage = this[K_EXECUTE_MESSAGE]; if (!initMessage) return this.activity.logger.warn(`<${this.id}> is not executing`); this.getApi(initMessage).discard(); }; @@ -122,7 +127,7 @@ ActivityExecution.prototype.discard = function discard() { */ ActivityExecution.prototype.getApi = function getApi(apiMessage) { const self = this; - if (!apiMessage) apiMessage = this[kExecuteMessage]; + if (!apiMessage) apiMessage = this[K_EXECUTE_MESSAGE]; if (self.source.getApi) { const sourceApi = self.source.getApi(apiMessage); @@ -133,7 +138,7 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { api.getExecuting = function getExecuting() { const result = []; - for (const msg of self[kPostponed]) { + for (const msg of self[K_POSTPONED]) { if (msg.content.executionId === apiMessage.content.executionId) continue; result.push(self.getApi(msg)); } @@ -157,7 +162,7 @@ ActivityExecution.prototype.passthrough = function passthrough(executeMessage) { */ ActivityExecution.prototype.getPostponed = function getPostponed() { let apis = []; - for (const msg of this[kPostponed]) { + for (const msg of this[K_POSTPONED]) { apis.push(this.getApi(msg)); } if (!this.activity.isSubProcess || !this.source) return apis; @@ -169,7 +174,7 @@ ActivityExecution.prototype.getPostponed = function getPostponed() { * Snapshot execution state, merging behaviour-specific state when the source provides it. */ ActivityExecution.prototype.getState = function getState() { - const result = { completed: this[kCompleted] }; + const result = { completed: this[K_COMPLETED] }; const source = this.source; if (!source || !source.getState) return result; @@ -179,13 +184,14 @@ ActivityExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. * @param {import('types').ActivityExecutionState} [state] - * @returns this + * @returns {this} */ ActivityExecution.prototype.recover = function recover(state) { - this[kPostponed].clear(); + /** @private */ + this[K_POSTPONED].clear(); if (!state) return this; - if ('completed' in state) this[kCompleted] = state.completed; + if ('completed' in state) this[K_COMPLETED] = state.completed; const source = (this.source = new this.activity.Behaviour(this.activity, this.context)); if (source.recover) { @@ -199,7 +205,7 @@ ActivityExecution.prototype.recover = function recover(state) { * Stop the execution via the activity api. */ ActivityExecution.prototype.stop = function stop() { - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[K_EXECUTE_MESSAGE]; if (!executeMessage) return; this.getApi(executeMessage).stop(); }; @@ -222,7 +228,7 @@ ActivityExecution.prototype._onExecuteMessage = function onExecuteMessage(routin switch (routingKey) { case 'execute.resume.execution': { - if (!this[kPostponed].size) return this.broker.publish('execution', 'execute.start', cloneContent(this[kExecuteMessage].content)); + if (!this[K_POSTPONED].size) return this.broker.publish('execution', 'execute.start', cloneContent(this[K_EXECUTE_MESSAGE].content)); break; } case 'execute.cancel': @@ -263,7 +269,7 @@ ActivityExecution.prototype._onExecuteMessage = function onExecuteMessage(routin /** @internal */ ActivityExecution.prototype._onStateChangeMessage = function onStateChangeMessage(message) { const { ignoreIfExecuting, executionId } = message.content; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; let previousMsg; for (const msg of postponed) { @@ -291,7 +297,7 @@ ActivityExecution.prototype._onStateChangeMessage = function onStateChangeMessag ActivityExecution.prototype._onExecutionCompleted = function onExecutionCompleted(message) { const postponedMsg = this._ackPostponed(message); if (!postponedMsg) return; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; const { executionId, keep, isRootScope } = message.content; if (!isRootScope) { @@ -307,7 +313,8 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete } this._debug('completed execution', executionId); - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; message.ack(true); @@ -326,7 +333,7 @@ ActivityExecution.prototype._onExecutionDiscarded = function onExecutionDiscarde const { isRootScope, error } = message.content; if (!isRootScope && !postponedMsg) return; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; const correlationId = message.properties.correlationId; if (!error && !isRootScope) { message.ack(); @@ -356,7 +363,8 @@ ActivityExecution.prototype._publishExecutionCompleted = function publishExecuti completeContent, correlationId ) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this.broker.publish( 'execution', @@ -373,7 +381,7 @@ ActivityExecution.prototype._publishExecutionCompleted = function publishExecuti ActivityExecution.prototype._ackPostponed = function ackPostponed(completeMessage) { const { executionId: eid } = completeMessage.content; - const postponed = this[kPostponed]; + const postponed = this[K_POSTPONED]; for (const msg of postponed) { if (msg.content.executionId === eid) { postponed.delete(msg); @@ -387,9 +395,9 @@ ActivityExecution.prototype._ackPostponed = function ackPostponed(completeMessag ActivityExecution.prototype._onParentApiMessage = function onParentApiMessage(routingKey, message) { switch (message.properties.type) { case 'error': - return this[kExecuteQ].queueMessage({ routingKey: 'execute.error' }, { error: message.content.error }); + return this[K_EXECUTE_Q].queueMessage({ routingKey: 'execute.error' }, { error: message.content.error }); case 'discard': - return this[kExecuteQ].queueMessage({ routingKey: 'execute.discard' }, cloneContent(this[kExecuteMessage].content)); + return this[K_EXECUTE_Q].queueMessage({ routingKey: 'execute.discard' }, cloneContent(this[K_EXECUTE_MESSAGE].content)); case 'stop': { return this._onStop(message); } diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 00000000..177110d1 --- /dev/null +++ b/src/constants.js @@ -0,0 +1,15 @@ +export const K_ACTIVATED = Symbol.for('activated'); +export const K_COMPLETED = Symbol.for('completed'); +export const K_CONSUMING = Symbol.for('consuming'); +export const K_COUNTERS = Symbol.for('counters'); +export const K_EXECUTE_MESSAGE = Symbol.for('executeMessage'); +export const K_EXECUTION = Symbol.for('execution'); +export const K_EXTENSIONS = Symbol.for('extensions'); +export const K_MESSAGE_HANDLERS = Symbol.for('messageHandlers'); +export const K_MESSAGE_Q = Symbol.for('messageQ'); +export const K_REFERENCE_ELEMENT = Symbol.for('referenceElement'); +export const K_REFERENCE_INFO = Symbol.for('referenceInfo'); +export const K_STATE_MESSAGE = Symbol.for('stateMessage'); +export const K_STATUS = Symbol.for('status'); +export const K_STOPPED = Symbol.for('stopped'); +export const K_TARGETS = Symbol.for('targets'); diff --git a/src/definition/Definition.js b/src/definition/Definition.js index 00e4e11c..a43ecaca 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -4,15 +4,16 @@ import { DefinitionBroker } from '../EventBroker.js'; import { getUniqueId, getOptionsAndCallback } from '../shared.js'; import { makeErrorFromMessage } from '../error/Errors.js'; import { cloneMessage, cloneContent } from '../messageHelper.js'; - -const kConsuming = Symbol.for('consuming'); -const kCounters = Symbol.for('counters'); -const kExec = Symbol.for('execution'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kStateMessage = Symbol.for('stateMessage'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); +import { + K_CONSUMING, + K_COUNTERS, + K_EXECUTE_MESSAGE, + K_EXECUTION, + K_MESSAGE_HANDLERS, + K_STATE_MESSAGE, + K_STATUS, + K_STOPPED, +} from '../constants.js'; export default Definition; @@ -41,16 +42,20 @@ export function Definition(context, options) { this.context = context; } - this[kCounters] = { + /** @private */ + this[K_COUNTERS] = { completed: 0, discarded: 0, }; - this[kStopped] = false; - this[kExec] = new Map(); + /** @private */ + this[K_STOPPED] = false; + /** @private */ + this[K_EXECUTION] = new Map(); const onBrokerReturn = this._onBrokerReturnFn.bind(this); - this[kMessageHandlers] = { + /** @private */ + this[K_MESSAGE_HANDLERS] = { onBrokerReturn, onApiMessage: this._onApiMessage.bind(this), onRunMessage: this._onRunMessage.bind(this), @@ -72,38 +77,38 @@ export function Definition(context, options) { Object.defineProperties(Definition.prototype, { counters: { get() { - return { ...this[kCounters] }; + return { ...this[K_COUNTERS] }; }, }, execution: { get() { - return this[kExec].get('execution'); + return this[K_EXECUTION].get('execution'); }, }, executionId: { get() { - return this[kExec].get('executionId'); + return this[K_EXECUTION].get('executionId'); }, }, isRunning: { get() { - if (!this[kConsuming]) return false; + if (!this[K_CONSUMING]) return false; return !!this.status; }, }, status: { get() { - return this[kStatus]; + return this[K_STATUS]; }, }, stopped: { get() { - return this[kStopped]; + return this[K_STOPPED]; }, }, activityStatus: { get() { - const execution = this[kExec].get('execution'); + const execution = this[K_EXECUTION].get('execution'); return execution?.activityStatus || 'idle'; }, }, @@ -114,7 +119,7 @@ Object.defineProperties(Definition.prototype, { * The callback fires once on leave, stop, or error. * @param {Record | import('types').runCallback} [optionsOrCallback] * @param {import('types').runCallback} [optionalCallback] - * @returns this + * @returns {this} * @throws {Error} when already running and no callback is supplied */ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { @@ -129,7 +134,7 @@ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { addConsumerCallbacks(this, callback); } - const exec = this[kExec]; + const exec = this[K_EXECUTION]; const executionId = getUniqueId(this.id); exec.set('executionId', executionId); const content = this._createMessage({ ...runOptions }); @@ -150,7 +155,7 @@ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { * Resume after recover by republishing the last run message. The callback fires once on * leave, stop, or error. * @param {import('types').runCallback} [callback] - * @returns this + * @returns {this} */ Definition.prototype.resume = function resume(callback) { if (this.isRunning) { @@ -159,7 +164,8 @@ Definition.prototype.resume = function resume(callback) { throw err; } - this[kStopped] = false; + /** @private */ + this[K_STOPPED] = false; if (!this.status) return this; if (callback) { @@ -191,20 +197,23 @@ Definition.prototype.getState = function getState() { /** * Restore definition state captured by getState. * @param {import('types').DefinitionState} [state] - * @returns this + * @returns {this} * @throws {Error} when called on a running definition */ Definition.prototype.recover = function recover(state) { if (this.isRunning) throw new Error('cannot recover running definition'); if (!state) return this; - this[kStopped] = !!state.stopped; - this[kStatus] = state.status; + /** @private */ + this[K_STOPPED] = !!state.stopped; + /** @private */ + this[K_STATUS] = state.status; - const exec = this[kExec]; + const exec = this[K_EXECUTION]; exec.set('executionId', state.executionId); if (state.counters) { - this[kCounters] = { ...this[kCounters], ...state.counters }; + /** @private */ + this[K_COUNTERS] = { ...this[K_COUNTERS], ...state.counters }; } this.environment.recover(state.environment); @@ -337,7 +346,7 @@ Definition.prototype.getPostponed = function getPostponed(...args) { Definition.prototype.getApi = function getApi(message) { const execution = this.execution; if (execution) return execution.getApi(message); - message = message || this[kStateMessage]; + message = message || this[K_STATE_MESSAGE]; if (!message) throw new Error('Definition is not running'); return DefinitionApi(this.broker, message); }; @@ -386,9 +395,10 @@ Definition.prototype.stop = function stop() { /** @internal */ Definition.prototype._activateRunConsumers = function activateRunConsumers() { - this[kConsuming] = true; + /** @private */ + this[K_CONSUMING] = true; const broker = this.broker; - const { onApiMessage, onRunMessage } = this[kMessageHandlers]; + const { onApiMessage, onRunMessage } = this[K_MESSAGE_HANDLERS]; broker.subscribeTmp('api', `definition.*.${this.executionId}`, onApiMessage, { noAck: true, consumerTag: '_definition-api', @@ -405,7 +415,8 @@ Definition.prototype._deactivateRunConsumers = function deactivateRunConsumers() broker.cancel('_definition-api'); broker.cancel('_definition-run'); broker.cancel('_definition-execution'); - this[kConsuming] = false; + /** @private */ + this[K_CONSUMING] = false; }; /** @internal */ @@ -426,14 +437,16 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) return this._onResumeMessage(message); } - const exec = this[kExec]; - this[kStateMessage] = message; + const exec = this[K_EXECUTION]; + /** @private */ + this[K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this.logger.debug(`<${this.executionId} (${this.id})> enter`); - this[kStatus] = 'entered'; + /** @private */ + this[K_STATUS] = 'entered'; if (fields.redelivered) break; exec.delete('execution'); @@ -442,19 +455,22 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) } case 'run.start': { this.logger.debug(`<${this.executionId} (${this.id})> start`); - this[kStatus] = 'start'; + /** @private */ + this[K_STATUS] = 'start'; this._publishEvent('start', content); break; } case 'run.execute': { - this[kStatus] = 'executing'; + /** @private */ + this[K_STATUS] = 'executing'; const executeMessage = cloneMessage(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - this[kExecuteMessage] = message; - this.broker.getQueue('execution-q').assertConsumer(this[kMessageHandlers].onExecutionMessage, { + /** @private */ + this[K_EXECUTE_MESSAGE] = message; + this.broker.getQueue('execution-q').assertConsumer(this[K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, consumerTag: '_definition-execution', }); @@ -471,12 +487,14 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) return execution.execute(executeMessage); } case 'run.end': { - if (this[kStatus] === 'end') break; + if (this[K_STATUS] === 'end') break; - this[kCounters].completed++; + /** @private */ + this[K_COUNTERS].completed++; this.logger.debug(`<${this.executionId} (${this.id})> completed`); - this[kStatus] = 'end'; + /** @private */ + this[K_STATUS] = 'end'; this.broker.publish('run', 'run.leave', content); this._publishEvent('end', content); break; @@ -493,17 +511,20 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) break; } case 'run.discarded': { - if (this[kStatus] === 'discarded') break; + if (this[K_STATUS] === 'discarded') break; - this[kCounters].discarded++; + /** @private */ + this[K_COUNTERS].discarded++; - this[kStatus] = 'discarded'; + /** @private */ + this[K_STATUS] = 'discarded'; this.broker.publish('run', 'run.leave', content); break; } case 'run.leave': { message.ack(); - this[kStatus] = undefined; + /** @private */ + this[K_STATUS] = undefined; this._deactivateRunConsumers(); this._publishEvent('leave', this._createMessage()); @@ -518,7 +539,7 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) Definition.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[K_STATE_MESSAGE]; switch (stateMessage.fields.routingKey) { case 'run.discarded': @@ -557,8 +578,9 @@ Definition.prototype._onExecutionMessage = function onExecutionMessage(routingKe } } - const executeMessage = this[kExecuteMessage]; - this[kExecuteMessage] = null; + const executeMessage = this[K_EXECUTE_MESSAGE]; + /** @private */ + this[K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; @@ -583,7 +605,8 @@ Definition.prototype._publishEvent = function publishEvent(action, content, msgO /** @internal */ Definition.prototype._onStop = function onStop() { - this[kStopped] = true; + /** @private */ + this[K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop', this._createMessage()); }; @@ -599,7 +622,8 @@ Definition.prototype._onBrokerReturnFn = function onBrokerReturn(message) { /** @internal */ Definition.prototype._reset = function reset() { - this[kExec].delete('executionId'); + /** @private */ + this[K_EXECUTION].delete('executionId'); this._deactivateRunConsumers(); this.broker.purgeQueue('run-q'); this.broker.purgeQueue('execution-q'); diff --git a/src/definition/DefinitionExecution.js b/src/definition/DefinitionExecution.js index 93df105f..7a99bc4a 100644 --- a/src/definition/DefinitionExecution.js +++ b/src/definition/DefinitionExecution.js @@ -1,16 +1,11 @@ import { DefinitionApi } from '../Api.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, cloneMessage, pushParent, cloneParent } from '../messageHelper.js'; +import { K_ACTIVATED, K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS, K_STATUS, K_STOPPED } from '../constants.js'; -const kActivated = Symbol.for('activated'); -const kProcessesQ = Symbol.for('processesQ'); -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kParent = Symbol.for('definition'); -const kProcesses = Symbol.for('processes'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); +const K_PROCESSES_Q = Symbol.for('processesQ'); +const K_PARENT = Symbol.for('definition'); +const K_PROCESSES = Symbol.for('processes'); /** * Drives the execution of a Definition. Activates executable processes, routes inter-process @@ -21,7 +16,8 @@ const kStopped = Symbol.for('stopped'); export default function DefinitionExecution(definition, context) { const broker = definition.broker; - this[kParent] = definition; + /** @private */ + this[K_PARENT] = definition; this.id = definition.id; this.type = definition.type; this.broker = broker; @@ -40,7 +36,8 @@ export default function DefinitionExecution(definition, context) { if (bp.isExecutable) executable.add(bp); } - this[kProcesses] = { + /** @private */ + this[K_PROCESSES] = { /** @type {import('../process/Process.js').Process[]} */ processes, ids, @@ -54,13 +51,19 @@ export default function DefinitionExecution(definition, context) { broker.assertExchange('execution', 'topic', { autoDelete: false, durable: true }); this.executionId = undefined; - this[kCompleted] = false; - this[kStopped] = false; - this[kActivated] = false; - this[kStatus] = 'init'; - this[kProcessesQ] = undefined; - - this[kMessageHandlers] = { + /** @private */ + this[K_COMPLETED] = false; + /** @private */ + this[K_STOPPED] = false; + /** @private */ + this[K_ACTIVATED] = false; + /** @private */ + this[K_STATUS] = 'init'; + /** @private */ + this[K_PROCESSES_Q] = undefined; + + /** @private */ + this[K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onCallActivity: this._onCallActivity.bind(this), onCancelCallActivity: this._onCancelCallActivity.bind(this), @@ -74,38 +77,38 @@ export default function DefinitionExecution(definition, context) { Object.defineProperties(DefinitionExecution.prototype, { stopped: { get() { - return this[kStopped]; + return this[K_STOPPED]; }, }, completed: { get() { - return this[kCompleted]; + return this[K_COMPLETED]; }, }, status: { get() { - return this[kStatus]; + return this[K_STATUS]; }, }, processes: { get() { - return [...this[kProcesses].running]; + return [...this[K_PROCESSES].running]; }, }, postponedCount: { get() { - return this[kProcesses].postponed.size; + return this[K_PROCESSES].postponed.size; }, }, isRunning: { get() { - return this[kActivated]; + return this[K_ACTIVATED]; }, }, activityStatus: { get() { let status = 'idle'; - const running = this[kProcesses].running; + const running = this[K_PROCESSES].running; if (!running.size) return status; for (const bp of running) { @@ -141,20 +144,23 @@ DefinitionExecution.prototype.execute = function execute(executeMessage) { const executionId = (this.executionId = content.executionId); if (!executionId) throw new Error('Definition execution requires execution id'); - this[kExecuteMessage] = cloneMessage(executeMessage, { + /** @private */ + this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage, { executionId, state: 'start', }); - this[kStopped] = false; + /** @private */ + this[K_STOPPED] = false; - this[kProcessesQ] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); + /** @private */ + this[K_PROCESSES_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); if (executeMessage.fields.redelivered) { return this.resume(); } - const { running, executable } = this[kProcesses]; + const { running, executable } = this[K_PROCESSES]; if (content.processId) { const startWithProcess = this.getProcessById(content.processId); @@ -177,19 +183,20 @@ DefinitionExecution.prototype.execute = function execute(executeMessage) { * Resume after recover by reactivating running processes. */ DefinitionExecution.prototype.resume = function resume() { - this._debug(`resume ${this[kStatus]} definition execution`); + this._debug(`resume ${this[K_STATUS]} definition execution`); - if (this[kCompleted]) return this._complete('completed'); + if (this[K_COMPLETED]) return this._complete('completed'); - const { running, postponed } = this[kProcesses]; + const { running, postponed } = this[K_PROCESSES]; this._activate(running); postponed.clear(); - this[kProcessesQ].consume(this[kMessageHandlers].onProcessMessage, { + /** @private */ + this[K_PROCESSES_Q].consume(this[K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; for (const bp of running) bp.resume(); }; @@ -197,19 +204,22 @@ DefinitionExecution.prototype.resume = function resume() { /** * Restore execution state captured by getState. Reinstates running processes from the snapshot. * @param {import('types').DefinitionExecutionState} [state] - * @returns this + * @returns {this} */ DefinitionExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - this[kStopped] = state.stopped; - this[kCompleted] = state.completed; - this[kStatus] = state.status; + /** @private */ + this[K_STOPPED] = state.stopped; + /** @private */ + this[K_COMPLETED] = state.completed; + /** @private */ + this[K_STATUS] = state.status; - this._debug(`recover ${this[kStatus]} definition execution`); + this._debug(`recover ${this[K_STATUS]} definition execution`); - const running = this[kProcesses].running; + const running = this[K_PROCESSES].running; running.clear(); const ids = new Set(); @@ -242,7 +252,7 @@ DefinitionExecution.prototype.stop = function stop() { * Get every process in the definition (running first, then any non-running by id). */ DefinitionExecution.prototype.getProcesses = function getProcesses() { - const { running, processes } = this[kProcesses]; + const { running, processes } = this[K_PROCESSES]; const result = [...running]; for (const bp of processes) { if (!result.find((runningBp) => bp.id === runningBp.id)) result.push(bp); @@ -269,7 +279,7 @@ DefinitionExecution.prototype.getProcessesById = function getProcessesById(proce * @param {string} processExecutionId */ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExecutionId(processExecutionId) { - for (const bp of this[kProcesses].running) { + for (const bp of this[K_PROCESSES].running) { if (bp.executionId === processExecutionId) return bp; } }; @@ -278,14 +288,14 @@ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExe * Get processes that have an executionId, i.e. are currently running. */ DefinitionExecution.prototype.getRunningProcesses = function getRunningProcesses() { - return [...this[kProcesses].running].filter((bp) => bp.executionId); + return [...this[K_PROCESSES].running].filter((bp) => bp.executionId); }; /** * Get processes flagged executable in the definition. */ DefinitionExecution.prototype.getExecutableProcesses = function getExecutableProcesses() { - return [...this[kProcesses].executable]; + return [...this[K_PROCESSES].executable]; }; /** @@ -293,15 +303,15 @@ DefinitionExecution.prototype.getExecutableProcesses = function getExecutablePro */ DefinitionExecution.prototype.getState = function getState() { const processes = []; - for (const bp of this[kProcesses].running) { + for (const bp of this[K_PROCESSES].running) { processes.push(bp.getState()); } return { executionId: this.executionId, - stopped: this[kStopped], - completed: this[kCompleted], - status: this[kStatus], + stopped: this[K_STOPPED], + completed: this[K_COMPLETED], + status: this[K_STATUS], processes, }; }; @@ -311,7 +321,7 @@ DefinitionExecution.prototype.getState = function getState() { * @param {import('types').ElementBrokerMessage} [apiMessage] */ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { - if (!apiMessage) apiMessage = this[kExecuteMessage] || { content: this._createMessage() }; + if (!apiMessage) apiMessage = this[K_EXECUTE_MESSAGE] || { content: this._createMessage() }; const content = apiMessage.content; if (content.executionId !== this.executionId) { @@ -319,7 +329,7 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { } const api = DefinitionApi(this.broker, apiMessage); - const postponed = this[kProcesses].postponed; + const postponed = this[K_PROCESSES].postponed; const self = this; api.getExecuting = function getExecuting() { @@ -340,7 +350,7 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { */ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { let result = []; - for (const bp of this[kProcesses].running) { + for (const bp of this[K_PROCESSES].running) { result = result.concat(bp.getPostponed(...args)); } return result; @@ -348,7 +358,7 @@ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { /** @internal */ DefinitionExecution.prototype._start = function start() { - const { ids, executable, postponed } = this[kProcesses]; + const { ids, executable, postponed } = this[K_PROCESSES]; if (!ids.size) { return this._complete('completed'); } @@ -357,13 +367,15 @@ DefinitionExecution.prototype._start = function start() { return this._complete('error', { error: new Error('No executable process') }); } - this[kStatus] = 'start'; + /** @private */ + this[K_STATUS] = 'start'; for (const bp of executable) bp.init(); for (const bp of executable) bp.run(); postponed.clear(); - this[kProcessesQ].assertConsumer(this[kMessageHandlers].onProcessMessage, { + /** @private */ + this[K_PROCESSES_Q].assertConsumer(this[K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}`, }); @@ -371,17 +383,18 @@ DefinitionExecution.prototype._start = function start() { /** @internal */ DefinitionExecution.prototype._activate = function activate(processList) { - this.broker.subscribeTmp('api', '#', this[kMessageHandlers].onApiMessage, { + this.broker.subscribeTmp('api', '#', this[K_MESSAGE_HANDLERS].onApiMessage, { noAck: true, consumerTag: '_definition-api-consumer', }); for (const bp of processList) this._activateProcess(bp); - this[kActivated] = true; + /** @private */ + this[K_ACTIVATED] = true; }; /** @internal */ DefinitionExecution.prototype._activateProcess = function activateProcess(bp) { - const handlers = this[kMessageHandlers]; + const handlers = this[K_MESSAGE_HANDLERS]; const broker = bp.broker; broker.subscribeTmp('message', 'message.outbound', handlers.onMessageOutbound, { @@ -417,7 +430,7 @@ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, const content = message.content; const parent = (content.parent = content.parent || {}); - const isDirectChild = this[kProcesses].ids.has(content.id); + const isDirectChild = this[K_PROCESSES].ids.has(content.id); if (isDirectChild) { parent.executionId = this.executionId; } else { @@ -427,15 +440,17 @@ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, this.broker.publish('event', routingKey, content, { ...message.properties, mandatory: false }); if (!isDirectChild) return; - this[kProcessesQ].queueMessage(message.fields, cloneContent(content), message.properties); + /** @private */ + this[K_PROCESSES_Q].queueMessage(message.fields, cloneContent(content), message.properties); }; /** @internal */ DefinitionExecution.prototype._deactivate = function deactivate() { this.broker.cancel('_definition-api-consumer'); this.broker.cancel(`_definition-activity-${this.executionId}`); - for (const bp of this[kProcesses].running) this._deactivateProcess(bp); - this[kActivated] = false; + for (const bp of this[K_PROCESSES].running) this._deactivateProcess(bp); + /** @private */ + this[K_ACTIVATED] = false; }; /** @internal */ @@ -469,7 +484,8 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout switch (routingKey) { case 'process.enter': - this[kStatus] = 'executing'; + /** @private */ + this[K_STATUS] = 'executing'; break; case 'process.discarded': { if (inbound?.length) { @@ -506,7 +522,7 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout { mandatory: true, type: 'error' } ); } else { - for (const bp of new Set(this[kProcesses].running)) { + for (const bp of new Set(this[K_PROCESSES].running)) { if (bp.id !== childId) bp.stop(); } @@ -522,7 +538,7 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout /** @internal */ DefinitionExecution.prototype._stateChangeMessage = function stateChangeMessage(message, postponeMessage) { let previousMsg; - const postponed = this[kProcesses].postponed; + const postponed = this[K_PROCESSES].postponed; for (const msg of postponed) { if (msg.content.executionId === message.content.executionId) { previousMsg = msg; @@ -556,17 +572,19 @@ DefinitionExecution.prototype._onProcessCompleted = function onProcessCompleted( /** @internal */ DefinitionExecution.prototype._onStopped = function onStopped(message) { - const running = this[kProcesses].running; + const running = this[K_PROCESSES].running; this._debug(`stop definition execution (stop process executions ${running.size})`); - this[kProcessesQ].close(); + /** @private */ + this[K_PROCESSES_Q].close(); for (const bp of new Set(running)) bp.stop(); this._deactivate(); - this[kStopped] = true; + /** @private */ + this[K_STOPPED] = true; return this.broker.publish( 'execution', `execution.stopped.${this.executionId}`, - cloneContent(this[kExecuteMessage].content, { + cloneContent(this[K_EXECUTE_MESSAGE].content, { ...message.content, }), { type: 'stopped', persistent: false } @@ -584,7 +602,7 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, } if (delegate) { - for (const bp of new Set(this[kProcesses].running)) { + for (const bp of new Set(this[K_PROCESSES].running)) { bp.broker.publish('api', routingKey, cloneContent(message.content), message.properties); } } @@ -592,13 +610,14 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, if (this.executionId !== message.content.executionId) return; if (messageType === 'stop') { - this[kProcessesQ].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false }); + /** @private */ + this[K_PROCESSES_Q].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false }); } }; /** @internal */ DefinitionExecution.prototype._startProcessesByMessage = function startProcessesByMessage(reference) { - const { processes: bps, running } = this[kProcesses]; + const { processes: bps, running } = this[K_PROCESSES]; if (bps.length < 2) return; for (const bp of bps) { @@ -654,7 +673,8 @@ DefinitionExecution.prototype._onMessageOutbound = function onMessageOutbound(ro targetProcess = targetProcess || this.context.getNewProcessById(target.processId); this._activateProcess(targetProcess); - this[kProcesses].running.add(targetProcess); + /** @private */ + this[K_PROCESSES].running.add(targetProcess); targetProcess.init(); targetProcess.run(); targetProcess.sendMessage(message); @@ -687,7 +707,8 @@ DefinitionExecution.prototype._onCallActivity = function onCallActivity(routingK this._debug(`call from <${fromParent.id}.${fromId}> to <${calledElement}>`); this._activateProcess(targetProcess); - this[kProcesses].running.add(targetProcess); + /** @private */ + this[K_PROCESSES].running.add(targetProcess); targetProcess.init(bpExecutionId); targetProcess.run({ inbound: [cloneContent(content)] }); }; @@ -758,19 +779,21 @@ DefinitionExecution.prototype._onDelegateMessage = function onDelegateMessage(ro /** @internal */ DefinitionExecution.prototype._removeProcessByExecutionId = function removeProcessByExecutionId(processExecutionId) { const bp = this.getProcessByExecutionId(processExecutionId); - if (bp) this[kProcesses].running.delete(bp); + if (bp) this[K_PROCESSES].running.delete(bp); return bp; }; /** @internal */ DefinitionExecution.prototype._complete = function complete(completionType, content, options) { this._deactivate(); - const stateMessage = this[kExecuteMessage]; + const stateMessage = this[K_EXECUTE_MESSAGE]; this._debug(`definition execution ${completionType} in ${Date.now() - stateMessage.properties.timestamp}ms`); if (!content) content = this._createMessage(); - this[kCompleted] = true; - this[kStatus] = completionType; - this.broker.deleteQueue(this[kProcessesQ].name); + /** @private */ + this[K_COMPLETED] = true; + /** @private */ + this[K_STATUS] = completionType; + this.broker.deleteQueue(this[K_PROCESSES_Q].name); return this.broker.publish( 'execution', @@ -791,7 +814,7 @@ DefinitionExecution.prototype._createMessage = function createMessage(content) { id: this.id, type: this.type, executionId: this.executionId, - status: this[kStatus], + status: this[K_STATUS], ...content, }; }; @@ -824,5 +847,6 @@ DefinitionExecution.prototype._getProcessApiByExecutionId = function getProcessA /** @internal */ DefinitionExecution.prototype._debug = function debug(logMessage) { - this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); + /** @private */ + this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; diff --git a/src/eventDefinitions/CancelEventDefinition.js b/src/eventDefinitions/CancelEventDefinition.js index 9307a4c9..1b00cc9a 100644 --- a/src/eventDefinitions/CancelEventDefinition.js +++ b/src/eventDefinitions/CancelEventDefinition.js @@ -1,7 +1,5 @@ import { cloneContent, shiftParent } from '../messageHelper.js'; - -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); +import { K_COMPLETED, K_EXECUTE_MESSAGE } from '../constants.js'; export default function CancelEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; @@ -19,7 +17,7 @@ export default function CancelEventDefinition(activity, eventDefinition) { Object.defineProperty(CancelEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -28,8 +26,10 @@ CancelEventDefinition.prototype.execute = function execute(executeMessage) { }; CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; @@ -94,10 +94,11 @@ CancelEventDefinition.prototype._onCatchMessage = function onCatchMessage(_, mes }; CancelEventDefinition.prototype._complete = function complete(output) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); this._debug('completed'); - const content = cloneContent(this[kExecuteMessage].content, { + const content = cloneContent(this[K_EXECUTE_MESSAGE].content, { output, state: 'cancel', }); @@ -107,9 +108,10 @@ CancelEventDefinition.prototype._complete = function complete(output) { CancelEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { switch (message.properties.type) { case 'discard': { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - const content = cloneContent(this[kExecuteMessage].content); + const content = cloneContent(this[K_EXECUTE_MESSAGE].content); return this.broker.publish('execution', 'execute.discard', content); } case 'stop': { diff --git a/src/eventDefinitions/CompensateEventDefinition.js b/src/eventDefinitions/CompensateEventDefinition.js index fcbbc7a2..3a4f3f27 100644 --- a/src/eventDefinitions/CompensateEventDefinition.js +++ b/src/eventDefinitions/CompensateEventDefinition.js @@ -1,11 +1,9 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, cloneMessage, shiftParent } from '../messageHelper.js'; +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q } from '../constants.js'; -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageQ = Symbol.for('messageQ'); -const kCompensateQ = Symbol.for('compensateQ'); -const kAssociations = Symbol.for('associations'); +const K_COMPENSATE_Q = Symbol.for('compensateQ'); +const K_ASSOCIATIONS = Symbol.for('associations'); export default function CompensateEventDefinition(activity, eventDefinition, context) { const { id, broker, environment, isThrowing } = activity; @@ -19,18 +17,22 @@ export default function CompensateEventDefinition(activity, eventDefinition, con this.logger = environment.Logger(type.toLowerCase()); if (!isThrowing) { - this[kCompleted] = false; - this[kAssociations] = context.getOutboundAssociations(id); + /** @private */ + this[K_COMPLETED] = false; + /** @private */ + this[K_ASSOCIATIONS] = context.getOutboundAssociations(id); const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - this[kCompensateQ] = broker.assertQueue('compensate-q', { autoDelete: false, durable: true }); + /** @private */ + this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); + /** @private */ + this[K_COMPENSATE_Q] = broker.assertQueue('compensate-q', { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 400 }); } } Object.defineProperty(CompensateEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -39,11 +41,14 @@ CompensateEventDefinition.prototype.execute = function execute(executeMessage) { }; CompensateEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[K_COMPLETED] = false; if (executeMessage.fields.routingKey === 'execute.compensating') { this._debug('resumed at compensating'); - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; return this._compensate(); } @@ -60,12 +65,13 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute consumerTag: '_oncollect-messages', }); - this[kMessageQ].consume(this._onCompensateApiMessage.bind(this), { + /** @private */ + this[K_MESSAGE_Q].consume(this._onCompensateApiMessage.bind(this), { noAck: true, consumerTag: `_oncompensate-${executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; broker.subscribeTmp('api', `activity.#.${parent.executionId}#`, this._onApiMessage.bind(this), { noAck: true, @@ -105,16 +111,17 @@ CompensateEventDefinition.prototype._onCollect = function onCollect(routingKey, switch (routingKey) { case 'execute.error': case 'execute.completed': { - return this[kCompensateQ].queueMessage(message.fields, cloneContent(message.content), message.properties); + return this[K_COMPENSATE_Q].queueMessage(message.fields, cloneContent(message.content), message.properties); } } }; CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompensateApiMessage(routingKey, message) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; const output = message.content.message; const broker = this.broker; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[K_EXECUTE_MESSAGE].content; this._stopCollect(); @@ -126,7 +133,8 @@ CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompens }); catchContent.parent = shiftParent(catchContent.parent); - this[kCompensateQ].queueMessage({ routingKey: 'execute.compensated' }, cloneContent(executeContent)); + /** @private */ + this[K_COMPENSATE_Q].queueMessage({ routingKey: 'execute.compensated' }, cloneContent(executeContent)); broker.publish('execution', 'execute.compensating', cloneContent(executeContent, { message: { ...output } })); broker.publish('event', 'activity.catch', catchContent, { type: 'catch' }); @@ -135,7 +143,7 @@ CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompens }; CompensateEventDefinition.prototype._compensate = function compensate() { - return this[kCompensateQ].consume(this._onCollected.bind(this), { noAck: true, consumerTag: '_convey-messages' }); + return this[K_COMPENSATE_Q].consume(this._onCollected.bind(this), { noAck: true, consumerTag: '_convey-messages' }); }; CompensateEventDefinition.prototype._onCollected = function onCollected(routingKey, message) { @@ -144,15 +152,17 @@ CompensateEventDefinition.prototype._onCollected = function onCollected(routingK broker.cancel('_convey-messages'); return this.broker.publish('execution', 'execute.completed', cloneContent(message.content, { cancelActivity: false })); } - for (const association of this[kAssociations]) association.take(cloneMessage(message)); + for (const association of this[K_ASSOCIATIONS]) association.take(cloneMessage(message)); }; CompensateEventDefinition.prototype._onDiscardApiMessage = function onDiscardApiMessage(routingKey, message) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - this[kCompensateQ].purge(); - for (const association of this[kAssociations]) association.discard(cloneMessage(message)); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content)); + /** @private */ + this[K_COMPENSATE_Q].purge(); + for (const association of this[K_ASSOCIATIONS]) association.discard(cloneMessage(message)); + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content)); }; CompensateEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { @@ -176,7 +186,8 @@ CompensateEventDefinition.prototype._stopCollect = function stopCollect() { broker.cancel(`_api-${executionId}`); broker.cancel(`_oncompensate-${executionId}`); broker.cancel('_oncollect-messages'); - this[kMessageQ].purge(); + /** @private */ + this[K_MESSAGE_Q].purge(); }; CompensateEventDefinition.prototype._stop = function stop() { diff --git a/src/eventDefinitions/ConditionalEventDefinition.js b/src/eventDefinitions/ConditionalEventDefinition.js index 8ad1ac2d..023cc856 100644 --- a/src/eventDefinitions/ConditionalEventDefinition.js +++ b/src/eventDefinitions/ConditionalEventDefinition.js @@ -1,8 +1,7 @@ import { cloneContent, shiftParent } from '../messageHelper.js'; import { ActivityError } from '../error/Errors.js'; import { ScriptCondition, ExpressionCondition } from '../condition.js'; - -const kExecuteMessage = Symbol.for('executeMessage'); +import { K_EXECUTE_MESSAGE } from '../constants.js'; export default function ConditionalEventDefinition(activity, eventDefinition, _context, index) { const { id, broker, environment } = activity; @@ -20,12 +19,13 @@ export default function ConditionalEventDefinition(activity, eventDefinition, _c Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); ConditionalEventDefinition.prototype.execute = function execute(executeMessage) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; if (!this.condition) return this._setup(executeMessage); @@ -88,7 +88,7 @@ ConditionalEventDefinition.prototype.evaluate = function evaluate(message, callb */ ConditionalEventDefinition.prototype.evaluateCallback = function evaluateCallback(err, result) { const broker = this.broker; - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[K_EXECUTE_MESSAGE]; const executeContent = executeMessage.content; if (err) { @@ -104,7 +104,7 @@ ConditionalEventDefinition.prototype.evaluateCallback = function evaluateCallbac this.broker.publish( 'event', 'activity.condition', - cloneContent(this[kExecuteMessage].content, { + cloneContent(this[K_EXECUTE_MESSAGE].content, { conditionResult: result, }) ); @@ -164,7 +164,7 @@ ConditionalEventDefinition.prototype._onApiMessage = function onApiMessage(routi case 'discard': { this._stop(); this._debug('discarded'); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content, { state: 'discard' })); + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content, { state: 'discard' })); } case 'stop': { this._stop(); diff --git a/src/eventDefinitions/ErrorEventDefinition.js b/src/eventDefinitions/ErrorEventDefinition.js index 95be6965..f108ec45 100644 --- a/src/eventDefinitions/ErrorEventDefinition.js +++ b/src/eventDefinitions/ErrorEventDefinition.js @@ -1,11 +1,6 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; - -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; export default function ErrorEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; @@ -26,19 +21,21 @@ export default function ErrorEventDefinition(activity, eventDefinition) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[kReferenceElement] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing) { - this[kCompleted] = false; + /** @private */ + this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); + /** @private */ + this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 300 }); } } Object.defineProperty(ErrorEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -47,21 +44,24 @@ ErrorEventDefinition.prototype.execute = function execute(executeMessage) { }; ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent?.executionId; - const info = (this[kReferenceInfo] = this._getReferenceInfo(executeMessage)); + const info = (this[K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage)); - this[kMessageQ].consume(this._onThrowApiMessage.bind(this), { + /** @private */ + this[K_MESSAGE_Q].consume(this._onThrowApiMessage.bind(this), { noAck: true, consumerTag: `_onthrow-${executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; this._debug(`expect ${info.description}`); @@ -88,7 +88,7 @@ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessa }) ); - if (this[kCompleted]) return this._stop(); + if (this[K_COMPLETED]) return this._stop(); } const waitContent = cloneContent(executeContent, { @@ -129,11 +129,11 @@ ErrorEventDefinition.prototype.executeThrow = function executeThrow(executeMessa ErrorEventDefinition.prototype._onErrorMessage = function onErrorMessage(routingKey, message) { const error = message.content.error; - if (!this[kReferenceElement]) return this._catchError(routingKey, message, error); + if (!this[K_REFERENCE_ELEMENT]) return this._catchError(routingKey, message, error); if (!error) return; - const info = this[kReferenceInfo]; + const info = this[K_REFERENCE_INFO]; if ('' + error.code !== '' + info.message.code) return; return this._catchError(routingKey, message, error); @@ -141,21 +141,22 @@ ErrorEventDefinition.prototype._onErrorMessage = function onErrorMessage(routing ErrorEventDefinition.prototype._onThrowApiMessage = function onThrowApiMessage(routingKey, message) { const error = message.content.message; - if (!this[kReferenceElement]) return this._catchError(routingKey, message, error); + if (!this[K_REFERENCE_ELEMENT]) return this._catchError(routingKey, message, error); - const info = this[kReferenceInfo]; + const info = this[K_REFERENCE_INFO]; if (info.message.id !== error?.id) return; return this._catchError(routingKey, message, error); }; ErrorEventDefinition.prototype._catchError = function catchError(routingKey, message, error) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - this._debug(`caught ${this[kReferenceInfo].description}`); + this._debug(`caught ${this[K_REFERENCE_INFO].description}`); - const executeContent = this[kExecuteMessage].content; + const executeContent = this[K_EXECUTE_MESSAGE].content; const parent = executeContent.parent; const catchContent = cloneContent(executeContent, { source: { @@ -187,9 +188,10 @@ ErrorEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, switch (messageType) { case 'discard': { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content)); + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content)); } case 'stop': { this._stop(); @@ -204,11 +206,12 @@ ErrorEventDefinition.prototype._stop = function stop() { broker.cancel(`_onthrow-${executionId}`); broker.cancel(`_onerror-${executionId}`); broker.cancel(`_api-${executionId}`); - this[kMessageQ].purge(); + /** @private */ + this[K_MESSAGE_Q].purge(); }; ErrorEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { ...this.reference }, diff --git a/src/eventDefinitions/EscalationEventDefinition.js b/src/eventDefinitions/EscalationEventDefinition.js index bab3a9d6..fbedae95 100644 --- a/src/eventDefinitions/EscalationEventDefinition.js +++ b/src/eventDefinitions/EscalationEventDefinition.js @@ -1,12 +1,9 @@ import getPropertyValue from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT } from '../constants.js'; -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReference = Symbol.for('reference'); +const K_REFERENCE = Symbol.for('reference'); export default function EscalationEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; @@ -26,19 +23,21 @@ export default function EscalationEventDefinition(activity, eventDefinition) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[kReferenceElement] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing) { - this[kCompleted] = false; + /** @private */ + this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); + /** @private */ + this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 400 }); } } Object.defineProperty(EscalationEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -47,20 +46,23 @@ EscalationEventDefinition.prototype.execute = function execute(executeMessage) { }; EscalationEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; - const info = (this[kReference] = this._getReferenceInfo(executeMessage)); + const info = (this[K_REFERENCE] = this._getReferenceInfo(executeMessage)); const broker = this.broker; - this[kMessageQ].consume(this._onCatchMessage.bind(this), { + /** @private */ + this[K_MESSAGE_Q].consume(this._onCatchMessage.bind(this), { noAck: true, consumerTag: `_onescalate-${executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; broker.subscribeTmp('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { noAck: true, @@ -100,17 +102,18 @@ EscalationEventDefinition.prototype.executeThrow = function executeThrow(execute }; EscalationEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { - const info = this[kReference]; + const info = this[K_REFERENCE]; if (getPropertyValue(message, 'content.message.id') !== info.message.id) return; const output = message.content.message; - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); this._debug(`caught ${info.description}`); - const executeContent = this[kExecuteMessage].content; + const executeContent = this[K_EXECUTE_MESSAGE].content; const { parent, ...content } = executeContent; const catchContent = cloneContent(content, { message: { ...output }, @@ -130,9 +133,10 @@ EscalationEventDefinition.prototype._onApiMessage = function onApiMessage(routin return this._onCatchMessage(routingKey, message); } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content)); + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content)); } case 'stop': { this._stop(); @@ -149,7 +153,7 @@ EscalationEventDefinition.prototype._stop = function stop() { }; EscalationEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { ...this.reference }, diff --git a/src/eventDefinitions/EventDefinitionExecution.js b/src/eventDefinitions/EventDefinitionExecution.js index 655adcdc..f6d8f72d 100644 --- a/src/eventDefinitions/EventDefinitionExecution.js +++ b/src/eventDefinitions/EventDefinitionExecution.js @@ -1,8 +1,5 @@ import { cloneContent, unshiftParent, shiftParent, cloneParent } from '../messageHelper.js'; - -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kStopped = Symbol.for('stopped'); +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_STOPPED } from '../constants.js'; export default function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKey = 'execute.completed') { this.id = activity.id; @@ -10,20 +7,23 @@ export default function EventDefinitionExecution(activity, eventDefinitions, com this.broker = activity.broker; this.eventDefinitions = eventDefinitions; this.completedRoutingKey = completedRoutingKey; - this[kCompleted] = false; - this[kStopped] = false; - this[kExecuteMessage] = null; + /** @private */ + this[K_COMPLETED] = false; + /** @private */ + this[K_STOPPED] = false; + /** @private */ + this[K_EXECUTE_MESSAGE] = null; } Object.defineProperties(EventDefinitionExecution.prototype, { completed: { get() { - return this[kCompleted]; + return this[K_COMPLETED]; }, }, stopped: { get() { - return this[kStopped]; + return this[K_STOPPED]; }, }, }); @@ -36,7 +36,8 @@ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { const broker = this.broker; - this[kExecuteMessage] = executeMessage; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; const executionId = content.executionId; broker.subscribeTmp('execution', 'execute.#', this._onExecuteMessage.bind(this), { @@ -58,8 +59,8 @@ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { const eventDefinitions = this.eventDefinitions; for (let index = 0; index < eventDefinitions.length; ++index) { - if (this[kCompleted]) break; - if (this[kStopped]) break; + if (this[K_COMPLETED]) break; + if (this[K_STOPPED]) break; const ed = eventDefinitions[index]; const edExecutionId = `${executionId}_${index}`; @@ -110,12 +111,13 @@ EventDefinitionExecution.prototype._onExecuteMessage = function onExecuteMessage EventDefinitionExecution.prototype._complete = function complete(message) { const { executionId, type, index, parent } = message.content; - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._debug(executionId, `event definition ${type} completed, index ${index}`); const completeContent = cloneContent(message.content, { - executionId: this[kExecuteMessage].content.executionId, + executionId: this[K_EXECUTE_MESSAGE].content.executionId, isRootScope: true, isDefinitionScope: undefined, }); @@ -133,7 +135,8 @@ EventDefinitionExecution.prototype._executeDefinition = function executeDefiniti }; EventDefinitionExecution.prototype._stop = function stop() { - this[kStopped] = true; + /** @private */ + this[K_STOPPED] = true; this.broker.cancel('_eventdefinition-execution-execute-tag'); this.broker.cancel('_eventdefinition-execution-api-tag'); }; diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index f2b67836..07330065 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -1,7 +1,6 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; - -const kExecuteMessage = Symbol.for('executeMessage'); +import { K_EXECUTE_MESSAGE } from '../constants.js'; export default function LinkEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; @@ -52,7 +51,7 @@ export default function LinkEventDefinition(activity, eventDefinition) { Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -61,7 +60,8 @@ LinkEventDefinition.prototype.execute = function execute(executeMessage) { }; LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; diff --git a/src/eventDefinitions/MessageEventDefinition.js b/src/eventDefinitions/MessageEventDefinition.js index a754a457..f52d9d29 100644 --- a/src/eventDefinitions/MessageEventDefinition.js +++ b/src/eventDefinitions/MessageEventDefinition.js @@ -1,12 +1,7 @@ import getPropertyValue from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; - -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; export default function MessageEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; @@ -26,19 +21,21 @@ export default function MessageEventDefinition(activity, eventDefinition) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[kReferenceElement] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing) { - this[kCompleted] = false; + /** @private */ + this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); + /** @private */ + this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); } } Object.defineProperty(MessageEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -47,24 +44,27 @@ MessageEventDefinition.prototype.execute = function execute(executeMessage) { }; MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent?.executionId; - const info = (this[kReferenceInfo] = this._getReferenceInfo(executeMessage)); + const info = (this[K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage)); this._debug(`expect ${info.description}`); const broker = this.broker; const onCatchMessage = this._onCatchMessage.bind(this); - this[kMessageQ].consume(onCatchMessage, { + /** @private */ + this[K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-message-${executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; const onApiMessage = this._onApiMessage.bind(this); broker.subscribeTmp('api', `activity.#.${executionId}`, onApiMessage, { @@ -112,13 +112,13 @@ MessageEventDefinition.prototype.executeThrow = function executeThrow(executeMes }; MessageEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { - if (getPropertyValue(message, 'content.message.id') !== this[kReferenceInfo].message.id) return; + if (getPropertyValue(message, 'content.message.id') !== this[K_REFERENCE_INFO].message.id) return; const { type, correlationId } = message.properties; this.broker.publish( 'event', 'activity.consumed', - cloneContent(this[kExecuteMessage].content, { + cloneContent(this[K_EXECUTE_MESSAGE].content, { message: { ...message.content.message }, }), { @@ -138,9 +138,10 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe return this._complete('got signal with', message.content.message, { correlationId }); } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content), { correlationId }); + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content), { correlationId }); } case 'stop': { return this._stop(); @@ -149,13 +150,14 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe }; MessageEventDefinition.prototype._complete = function complete(verb, output, options) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - this._debug(`${verb} ${this[kReferenceInfo].description}`); + this._debug(`${verb} ${this[K_REFERENCE_INFO].description}`); const broker = this.broker; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[K_EXECUTE_MESSAGE].content; const catchContent = cloneContent(executeContent, { message: { ...output }, executionId: executeContent.parent.executionId, @@ -182,11 +184,12 @@ MessageEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-${executionId}`); broker.cancel(`_api-parent-${executionId}`); broker.cancel(`_api-delegated-${executionId}`); - this[kMessageQ].purge(); + /** @private */ + this[K_MESSAGE_Q].purge(); }; MessageEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { ...this.reference }, diff --git a/src/eventDefinitions/SignalEventDefinition.js b/src/eventDefinitions/SignalEventDefinition.js index a2f6efd0..5cb144eb 100644 --- a/src/eventDefinitions/SignalEventDefinition.js +++ b/src/eventDefinitions/SignalEventDefinition.js @@ -1,12 +1,7 @@ import getPropertyValue from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; - -const kCompleted = Symbol.for('completed'); -const kMessageQ = Symbol.for('messageQ'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; export default function SignalEventDefinition(activity, eventDefinition) { const { id, broker, environment, isStart, isThrowing } = activity; @@ -26,19 +21,21 @@ export default function SignalEventDefinition(activity, eventDefinition) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[kReferenceElement] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing && isStart) { - this[kCompleted] = false; + /** @private */ + this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - this[kMessageQ] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); + /** @private */ + this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); } } Object.defineProperty(SignalEventDefinition.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -47,23 +44,26 @@ SignalEventDefinition.prototype.execute = function execute(executeMessage) { }; SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - this[kExecuteMessage] = executeMessage; - this[kCompleted] = false; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; + /** @private */ + this[K_COMPLETED] = false; const executeContent = executeMessage.content; const { executionId, parent } = executeContent; const parentExecutionId = parent?.executionId; - const info = (this[kReferenceInfo] = this._getReferenceInfo(executeMessage)); + const info = (this[K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage)); const broker = this.broker; const onCatchMessage = this._onCatchMessage.bind(this); if (this.activity.isStart) { - this[kMessageQ].consume(onCatchMessage, { + /** @private */ + this[K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-signal-${executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; } const onApiMessage = this._onApiMessage.bind(this); @@ -113,16 +113,17 @@ SignalEventDefinition.prototype.executeThrow = function executeThrow(executeMess }; SignalEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { - const info = this[kReferenceInfo]; + const info = this[K_REFERENCE_INFO]; if (getPropertyValue(message, 'content.message.id') !== info.message.id) return; - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); const { type, correlationId } = message.properties; this.broker.publish( 'event', 'activity.consumed', - cloneContent(this[kExecuteMessage].content, { + cloneContent(this[K_EXECUTE_MESSAGE].content, { message: { ...message.content.message }, }), { @@ -142,9 +143,10 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey return this._complete(message.content.message, { correlationId }); } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content), { correlationId }); + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content), { correlationId }); } case 'stop': { this._stop(); @@ -154,13 +156,14 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey }; SignalEventDefinition.prototype._complete = function complete(output, options) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - this._debug(`signaled with ${this[kReferenceInfo].description}`); + this._debug(`signaled with ${this[K_REFERENCE_INFO].description}`); return this.broker.publish( 'execution', 'execute.completed', - cloneContent(this[kExecuteMessage].content, { + cloneContent(this[K_EXECUTE_MESSAGE].content, { output, state: 'signal', }), @@ -175,11 +178,11 @@ SignalEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-parent-${executionId}`); broker.cancel(`_api-${executionId}`); broker.cancel(`_api-delegated-${executionId}`); - if (this.activity.isStart) this[kMessageQ].purge(); + if (this.activity.isStart) this[K_MESSAGE_Q].purge(); }; SignalEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { - const referenceElement = this[kReferenceElement]; + const referenceElement = this[K_REFERENCE_ELEMENT]; if (!referenceElement) { return { message: { ...this.reference }, diff --git a/src/eventDefinitions/TimerEventDefinition.js b/src/eventDefinitions/TimerEventDefinition.js index 7e1fa1dc..341743bb 100644 --- a/src/eventDefinitions/TimerEventDefinition.js +++ b/src/eventDefinitions/TimerEventDefinition.js @@ -1,10 +1,10 @@ import { ISOInterval, getDate } from '@0dep/piso'; import { cloneContent } from '../messageHelper.js'; import { RunError } from '../error/Errors.js'; +import { K_STOPPED } from '../constants.js'; -const kStopped = Symbol.for('stopped'); -const kTimerContent = Symbol.for('timerContent'); -const kTimer = Symbol.for('timer'); +const K_TIMER_CONTENT = Symbol.for('timerContent'); +const K_TIMER = Symbol.for('timer'); const timerTypes = new Set(['timeDuration', 'timeDate', 'timeCycle']); @@ -22,37 +22,40 @@ export default function TimerEventDefinition(activity, eventDefinition) { this.broker = activity.broker; this.logger = environment.Logger(type.toLowerCase()); - this[kStopped] = false; - this[kTimer] = null; + /** @private */ + this[K_STOPPED] = false; + /** @private */ + this[K_TIMER] = null; } Object.defineProperties(TimerEventDefinition.prototype, { executionId: { get() { - return this[kTimerContent]?.executionId; + return this[K_TIMER_CONTENT]?.executionId; }, }, stopped: { get() { - return this[kStopped]; + return this[K_STOPPED]; }, }, timer: { get() { - return this[kTimer]; + return this[K_TIMER]; }, }, }); TimerEventDefinition.prototype.execute = function execute(executeMessage) { const { routingKey: executeKey, redelivered: isResumed } = executeMessage.fields; - const timer = this[kTimer]; + const timer = this[K_TIMER]; if (timer && executeKey === 'execute.timer') { return; } - if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer); - this[kStopped] = false; + if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); + /** @private */ + this[K_STOPPED] = false; const content = executeMessage.content; const executionId = content.executionId; @@ -66,7 +69,7 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { throw new RunError(err.message, executeMessage, err); } - const timerContent = (this[kTimerContent] = cloneContent(content, { + const timerContent = (this[K_TIMER_CONTENT] = cloneContent(content, { ...resolvedTimer, ...(isResumed && { isResumed }), startedAt, @@ -93,7 +96,8 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { const timers = this.environment.timers.register(timerContent); const delay = timerContent.timeout; - this[kTimer] = timers.setTimeout(this._completed.bind(this), delay, { + /** @private */ + this[K_TIMER] = timers.setTimeout(this._completed.bind(this), delay, { id: content.id, type: this.type, executionId, @@ -103,8 +107,8 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { }; TimerEventDefinition.prototype.stop = function stopTimer() { - const timer = this[kTimer]; - if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer); + const timer = this[K_TIMER]; + if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); }; TimerEventDefinition.prototype._completed = function completed(completeContent, options) { @@ -115,7 +119,7 @@ TimerEventDefinition.prototype._completed = function completed(completeContent, const runningTime = stoppedAt.getTime() - this.startedAt.getTime(); this._debug(`completed in ${runningTime}ms`); - const timerContent = this[kTimerContent]; + const timerContent = this[K_TIMER_CONTENT]; const content = { stoppedAt, runningTime, state: 'timeout', ...completeContent }; const broker = this.broker; @@ -148,7 +152,7 @@ TimerEventDefinition.prototype._onDelegatedApiMessage = function onDelegatedApiM this.broker.publish( 'event', 'activity.consumed', - cloneContent(this[kTimerContent], { + cloneContent(this[K_TIMER_CONTENT], { message: { ...content.message, }, @@ -180,7 +184,7 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, case 'discard': { this._stop(); this._debug('discarded'); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kTimerContent], { state: 'discard' }), { + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_TIMER_CONTENT], { state: 'discard' }), { correlationId, }); } @@ -188,9 +192,10 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, }; TimerEventDefinition.prototype._stop = function stop() { - this[kStopped] = true; - const timer = this[kTimer]; - if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer); + /** @private */ + this[K_STOPPED] = true; + const timer = this[K_TIMER]; + if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); const broker = this.broker; broker.cancel(`_api-${this.executionId}`); broker.cancel(`_api-delegated-${this.executionId}`); diff --git a/src/events/BoundaryEvent.js b/src/events/BoundaryEvent.js index b537648e..55479855 100644 --- a/src/events/BoundaryEvent.js +++ b/src/events/BoundaryEvent.js @@ -2,12 +2,11 @@ import Activity from '../activity/Activity.js'; import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent, cloneMessage } from '../messageHelper.js'; import { brokerSafeId } from '../shared.js'; +import { K_EXECUTE_MESSAGE, K_EXECUTION } from '../constants.js'; -const kAttachedTags = Symbol.for('attachedConsumers'); -const kCompleteContent = Symbol.for('completeContent'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kExecution = Symbol.for('execution'); -const kShovels = Symbol.for('shovels'); +const K_ATTACHED_TAGS = Symbol.for('attachedConsumers'); +const K_COMPLETE_CONTENT = Symbol.for('completeContent'); +const K_SHOVELS = Symbol.for('shovels'); export default function BoundaryEvent(activityDef, context) { return new Activity(BoundaryEventBehaviour, activityDef, context); @@ -20,16 +19,19 @@ export function BoundaryEventBehaviour(activity) { this.activity = activity; this.environment = activity.environment; this.broker = activity.broker; - this[kExecution] = + /** @private */ + this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions, 'execute.bound.completed'); - this[kShovels] = new Set(); - this[kAttachedTags] = new Set(); + /** @private */ + this[K_SHOVELS] = new Set(); + /** @private */ + this[K_ATTACHED_TAGS] = new Set(); } Object.defineProperties(BoundaryEventBehaviour.prototype, { executionId: { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }, cancelActivity: { @@ -43,9 +45,10 @@ Object.defineProperties(BoundaryEventBehaviour.prototype, { BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { const { isRootScope, executionId } = executeMessage.content; - const eventDefinitionExecution = this[kExecution]; + const eventDefinitionExecution = this[K_EXECUTION]; if (isRootScope && executeMessage.content.id === this.id) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; const broker = this.broker; if (executeMessage.fields.routingKey === 'execute.bound.completed') { @@ -59,7 +62,8 @@ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { consumerTag, priority: 300, }); - this[kAttachedTags].add(consumerTag); + /** @private */ + this[K_ATTACHED_TAGS].add(consumerTag); broker.subscribeOnce('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { consumerTag: `_api-${executionId}`, @@ -109,9 +113,10 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, { conten ); } - this[kCompleteContent] = content; + /** @private */ + this[K_COMPLETE_CONTENT] = content; - const { inbound, executionId } = this[kExecuteMessage].content; + const { inbound, executionId } = this[K_EXECUTE_MESSAGE].content; const attachedToContent = inbound?.[0]; const attachedTo = this.attachedTo; @@ -121,7 +126,8 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, { conten if (content.isRecovered && !attachedTo.isRunning) { const attachedExecuteTag = `_on-attached-execute-${executionId}`; - this[kAttachedTags].add(attachedExecuteTag); + /** @private */ + this[K_ATTACHED_TAGS].add(attachedExecuteTag); attachedTo.broker.subscribeOnce( 'execution', '#', @@ -139,8 +145,8 @@ BoundaryEventBehaviour.prototype._onAttachedLeave = function onAttachedLeave(_, if (content.id !== this.attachedTo.id) return; this._stop(); - const completeContent = this[kCompleteContent]; - if (!completeContent) return this.broker.publish('execution', 'execute.discard', this[kExecuteMessage].content); + const completeContent = this[K_COMPLETE_CONTENT]; + if (!completeContent) return this.broker.publish('execution', 'execute.discard', this[K_EXECUTE_MESSAGE].content); return this.broker.publish('execution', 'execute.completed', cloneContent(completeContent)); }; @@ -149,7 +155,8 @@ BoundaryEventBehaviour.prototype._onExpectMessage = function onExpectMessage(_, const attachedTo = this.attachedTo; const errorConsumerTag = `_bound-error-listener-${executionId}`; - this[kAttachedTags].add(errorConsumerTag); + /** @private */ + this[K_ATTACHED_TAGS].add(errorConsumerTag); attachedTo.broker.subscribeTmp( 'event', @@ -171,7 +178,7 @@ BoundaryEventBehaviour.prototype._onExpectMessage = function onExpectMessage(_, BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_, message) { const content = message.content; - const { executionId, parent } = this[kExecuteMessage].content; + const { executionId, parent } = this[K_EXECUTE_MESSAGE].content; const id = this.id, attachedTo = this.attachedTo; this.activity.logger.debug(`<${executionId} (${id})> detach from activity <${attachedTo.id}>`); @@ -180,7 +187,8 @@ BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_, const { executionId: detachId, bindExchange, sourceExchange, sourcePattern } = content; const shovelName = `_detached-${brokerSafeId(id)}_${detachId}`; - this[kShovels].add(shovelName); + /** @private */ + this[K_SHOVELS].add(shovelName); const broker = this.broker; attachedTo.broker.createShovel( @@ -229,7 +237,7 @@ BoundaryEventBehaviour.prototype._onApiMessage = function onApiMessage(_, messag }; BoundaryEventBehaviour.prototype._onRepeatMessage = function onRepeatMessage(_, message) { - const executeMessage = this[kExecuteMessage]; + const executeMessage = this[K_EXECUTE_MESSAGE]; const repeat = message.content.repeat; this.broker .getQueue('inbound-q') @@ -240,10 +248,12 @@ BoundaryEventBehaviour.prototype._stop = function stop(detach) { const attachedTo = this.attachedTo, broker = this.broker, executionId = this.executionId; - for (const tag of this[kAttachedTags]) attachedTo.broker.cancel(tag); - this[kAttachedTags].clear(); - for (const shovelName of this[kShovels]) attachedTo.broker.closeShovel(shovelName); - this[kShovels].clear(); + for (const tag of this[K_ATTACHED_TAGS]) attachedTo.broker.cancel(tag); + /** @private */ + this[K_ATTACHED_TAGS].clear(); + for (const shovelName of this[K_SHOVELS]) attachedTo.broker.closeShovel(shovelName); + /** @private */ + this[K_SHOVELS].clear(); broker.cancel('_execution-tag'); broker.cancel(`_execution-completed-${executionId}`); diff --git a/src/events/EndEvent.js b/src/events/EndEvent.js index cf27c811..2890981e 100644 --- a/src/events/EndEvent.js +++ b/src/events/EndEvent.js @@ -1,8 +1,7 @@ import Activity from '../activity/Activity.js'; import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; - -const kExecution = Symbol.for('execution'); +import { K_EXECUTION } from '../constants.js'; export default function EndEvent(activityDef, context) { return new Activity(EndEventBehaviour, { ...activityDef, isThrowing: true }, context); @@ -12,11 +11,12 @@ export function EndEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); + /** @private */ + this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } EndEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } diff --git a/src/events/IntermediateCatchEvent.js b/src/events/IntermediateCatchEvent.js index a8b1d012..d72e3219 100644 --- a/src/events/IntermediateCatchEvent.js +++ b/src/events/IntermediateCatchEvent.js @@ -1,8 +1,7 @@ import Activity from '../activity/Activity.js'; import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; - -const kExecution = Symbol.for('execution'); +import { K_EXECUTION } from '../constants.js'; export default function IntermediateCatchEvent(activityDef, context) { return new Activity(IntermediateCatchEventBehaviour, { ...activityDef, isCatching: true }, context); @@ -12,11 +11,12 @@ export function IntermediateCatchEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); + /** @private */ + this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } IntermediateCatchEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } diff --git a/src/events/IntermediateThrowEvent.js b/src/events/IntermediateThrowEvent.js index ca338560..d32381a1 100644 --- a/src/events/IntermediateThrowEvent.js +++ b/src/events/IntermediateThrowEvent.js @@ -1,8 +1,7 @@ import Activity from '../activity/Activity.js'; import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; - -const kExecution = Symbol.for('execution'); +import { K_EXECUTION } from '../constants.js'; export default function IntermediateThrowEvent(activityDef, context) { return new Activity(IntermediateThrowEventBehaviour, { ...activityDef, isThrowing: true }, context); @@ -12,11 +11,12 @@ export function IntermediateThrowEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); + /** @private */ + this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } IntermediateThrowEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } diff --git a/src/events/StartEvent.js b/src/events/StartEvent.js index 9cd9f198..68fba97e 100644 --- a/src/events/StartEvent.js +++ b/src/events/StartEvent.js @@ -1,9 +1,7 @@ import Activity from '../activity/Activity.js'; import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; - -const kExecuteMessage = Symbol.for('executeMessage'); -const kExecution = Symbol.for('execution'); +import { K_EXECUTE_MESSAGE, K_EXECUTION } from '../constants.js'; export default function StartEvent(activityDef, context) { return new Activity(StartEventBehaviour, activityDef, context); @@ -14,17 +12,18 @@ export function StartEventBehaviour(activity) { this.type = activity.type; this.activity = activity; this.broker = activity.broker; - this[kExecution] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); + /** @private */ + this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } Object.defineProperty(StartEventBehaviour.prototype, 'executionId', { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); StartEventBehaviour.prototype.execute = function execute(executeMessage) { - const execution = this[kExecution]; + const execution = this[K_EXECUTION]; if (execution) { return execution.execute(executeMessage); } @@ -36,7 +35,8 @@ StartEventBehaviour.prototype.execute = function execute(executeMessage) { } const executionId = content.executionId; - this[kExecuteMessage] = executeMessage; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; broker.subscribeTmp('api', `activity.#.${executionId}`, (...args) => this._onApiMessage(...args), { noAck: true, consumerTag: `_api-${executionId}`, @@ -56,7 +56,7 @@ StartEventBehaviour.prototype._onApiMessage = function onApiMessage(routingKey, return this._stop(); case 'signal': { this._stop(); - const content = this[kExecuteMessage].content; + const content = this[K_EXECUTE_MESSAGE].content; return this.broker.publish( 'execution', 'execute.completed', @@ -69,7 +69,7 @@ StartEventBehaviour.prototype._onApiMessage = function onApiMessage(routingKey, } case 'discard': { this._stop(); - const content = this[kExecuteMessage].content; + const content = this[K_EXECUTE_MESSAGE].content; return this.broker.publish('execution', 'execute.discard', cloneContent(content), { correlationId }); } } @@ -85,7 +85,7 @@ StartEventBehaviour.prototype._onDelegatedApiMessage = function onDelegatedApiMe if (signalId !== this.id && signalExecutionId !== this.executionId) return; const { type, correlationId } = message.properties; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[K_EXECUTE_MESSAGE].content; this.broker.publish( 'event', 'activity.consumed', diff --git a/src/flows/Association.js b/src/flows/Association.js index 6e05301c..ed6460a1 100644 --- a/src/flows/Association.js +++ b/src/flows/Association.js @@ -2,9 +2,14 @@ import { cloneParent } from '../messageHelper.js'; import { EventBroker } from '../EventBroker.js'; import { Api } from '../Api.js'; import { getUniqueId } from '../shared.js'; - -const kCounters = Symbol.for('counters'); - +import { K_COUNTERS } from '../constants.js'; + +/** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * @param {import('moddle-context-serializer').SerializableElement} associationDef + * @param {import('types').ContextInstance} context + */ export default function Association(associationDef, { environment }) { const { id, type = 'association', name, parent, targetId, sourceId, behaviour = {} } = associationDef; @@ -19,7 +24,8 @@ export default function Association(associationDef, { environment }) { this.environment = environment; const logger = (this.logger = environment.Logger(type.toLowerCase())); - this[kCounters] = { + /** @private */ + this[K_COUNTERS] = { take: 0, discard: 0, }; @@ -34,29 +40,43 @@ export default function Association(associationDef, { environment }) { } Object.defineProperty(Association.prototype, 'counters', { + /** @returns {{ take: number, discard: number }} */ get() { - return { ...this[kCounters] }; + return { ...this[K_COUNTERS] }; }, }); +/** + * Take the association and publish association.take. + * @param {Record} [content] + */ Association.prototype.take = function take(content) { this.logger.debug(`<${this.id}> take target <${this.targetId}>`); - ++this[kCounters].take; + ++this[K_COUNTERS].take; this._publishEvent('take', content); return true; }; +/** + * Discard the association and publish association.discard. + * @param {Record} [content] + */ Association.prototype.discard = function discard(content) { this.logger.debug(`<${this.id}> discard target <${this.targetId}>`); - ++this[kCounters].discard; + ++this[K_COUNTERS].discard; this._publishEvent('discard', content); return true; }; +/** + * Snapshot association state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * @returns {import('types').AssociationState | undefined} + */ Association.prototype.getState = function getState() { const brokerState = this.broker.getState(true); if (!brokerState && this.environment.settings.disableTrackState) return; @@ -69,19 +89,31 @@ Association.prototype.getState = function getState() { }; }; +/** + * Restore association state captured by getState. + * @param {import('types').AssociationState} state + */ Association.prototype.recover = function recover(state) { - Object.assign(this[kCounters], state.counters); + Object.assign(this[K_COUNTERS], state.counters); this.broker.recover(state.broker); }; +/** + * Resolve an association-scoped Api wrapper. + * @param {import('types').ElementBrokerMessage} [message] + */ Association.prototype.getApi = function getApi(message) { return new Api('association', this.broker, message || { content: this._createMessageContent() }); }; +/** + * Stop the association's broker. + */ Association.prototype.stop = function stop() { this.broker.stop(); }; +/** @internal */ Association.prototype._publishEvent = function publishEvent(action, content) { const eventContent = this._createMessageContent({ action, @@ -92,6 +124,7 @@ Association.prototype._publishEvent = function publishEvent(action, content) { this.broker.publish('event', `association.${action}`, eventContent, { type: action }); }; +/** @internal */ Association.prototype._createMessageContent = function createMessageContent(override) { return { ...override, diff --git a/src/flows/MessageFlow.js b/src/flows/MessageFlow.js index d79f51b4..83f055d6 100644 --- a/src/flows/MessageFlow.js +++ b/src/flows/MessageFlow.js @@ -2,10 +2,17 @@ import { brokerSafeId } from '../shared.js'; import { cloneParent } from '../messageHelper.js'; import { MessageFlowBroker } from '../EventBroker.js'; import { Api } from '../Api.js'; +import { K_COUNTERS } from '../constants.js'; -const kCounters = Symbol.for('counters'); -const kSourceElement = Symbol.for('sourceElement'); +const K_SOURCE_ELEMENT = Symbol.for('sourceElement'); +/** + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('types').ContextInstance} context + */ export default function MessageFlow(flowDef, context) { const { id, type = 'messageflow', name, target, source, behaviour, parent } = flowDef; @@ -19,7 +26,8 @@ export default function MessageFlow(flowDef, context) { this.environment = context.environment; this.context = context; - this[kCounters] = { + /** @private */ + this[K_COUNTERS] = { messages: 0, }; @@ -30,16 +38,23 @@ export default function MessageFlow(flowDef, context) { this.emit = emit; this.waitFor = waitFor; - this[kSourceElement] = context.getActivityById(source.id) || context.getProcessById(source.processId); + /** @private */ + this[K_SOURCE_ELEMENT] = context.getActivityById(source.id) || context.getProcessById(source.processId); this.logger = context.environment.Logger(type.toLowerCase()); } Object.defineProperty(MessageFlow.prototype, 'counters', { + /** @returns {{ messages: number }} */ get() { - return { ...this[kCounters] }; + return { ...this[K_COUNTERS] }; }, }); +/** + * Snapshot message-flow state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * @returns {import('types').MessageFlowState | undefined} + */ MessageFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); if (!brokerState && this.environment.settings.disableTrackState) return; @@ -52,31 +67,46 @@ MessageFlow.prototype.getState = function getState() { }; }; +/** + * Restore message-flow state captured by getState. + * @param {import('types').MessageFlowState} state + */ MessageFlow.prototype.recover = function recover(state) { - Object.assign(this[kCounters], state.counters); + Object.assign(this[K_COUNTERS], state.counters); this.broker.recover(state.broker); }; +/** + * Resolve a message-scoped Api wrapper. + * @param {import('types').ElementBrokerMessage} [message] + */ MessageFlow.prototype.getApi = function getApi(message) { return new Api('message', this.broker, message || { content: this._createMessageContent() }); }; +/** + * Subscribe to the source element's message and end events to bridge the message across. + */ MessageFlow.prototype.activate = function activate() { - const sourceElement = this[kSourceElement]; + const sourceElement = this[K_SOURCE_ELEMENT]; const safeId = brokerSafeId(this.id); sourceElement.on('message', this.deactivate.bind(this), { consumerTag: `_message-on-message-${safeId}` }); sourceElement.on('end', this._onSourceEnd.bind(this), { consumerTag: `_message-on-end-${safeId}` }); }; +/** + * Cancel the source element subscriptions added by activate. + */ MessageFlow.prototype.deactivate = function deactivate() { - const sourceElement = this[kSourceElement]; + const sourceElement = this[K_SOURCE_ELEMENT]; const safeId = brokerSafeId(this.id); sourceElement.broker.cancel(`_message-on-end-${safeId}`); sourceElement.broker.cancel(`_message-on-message-${safeId}`); }; +/** @internal */ MessageFlow.prototype._onSourceEnd = function onSourceEnd({ content }) { - ++this[kCounters].messages; + ++this[K_COUNTERS].messages; const source = this.source; const target = this.target; this.logger.debug( @@ -85,6 +115,7 @@ MessageFlow.prototype._onSourceEnd = function onSourceEnd({ content }) { this.broker.publish('event', 'message.outbound', this._createMessageContent(content.message)); }; +/** @internal */ MessageFlow.prototype._createMessageContent = function createMessage(message) { return { id: this.id, diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index 1539bf99..99157fe3 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -3,12 +3,17 @@ import { getUniqueId } from '../shared.js'; import { EventBroker } from '../EventBroker.js'; import { FlowApi } from '../Api.js'; import { ScriptCondition, ExpressionCondition } from '../condition.js'; - -const kCounters = Symbol.for('counters'); +import { K_COUNTERS } from '../constants.js'; export default SequenceFlow; -function SequenceFlow(flowDef, { environment }) { +/** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('types').ContextInstance} context + */ +export function SequenceFlow(flowDef, { environment }) { const { id, type = 'sequenceflow', name, parent, targetId, sourceId, isDefault, behaviour = {} } = flowDef; this.id = id; @@ -23,7 +28,8 @@ function SequenceFlow(flowDef, { environment }) { this.environment = environment; const logger = (this.logger = environment.Logger(type.toLowerCase())); - this[kCounters] = { + /** @private */ + this[K_COUNTERS] = { looped: 0, take: 0, discard: 0, @@ -42,27 +48,37 @@ function SequenceFlow(flowDef, { environment }) { } Object.defineProperty(SequenceFlow.prototype, 'counters', { + /** @returns {{ take: number, discard: number, looped: number }} */ get() { - return { ...this[kCounters] }; + return { ...this[K_COUNTERS] }; }, }); +/** + * Take the flow and publish flow.take. + * @param {Record} [content] + */ SequenceFlow.prototype.take = function take(content) { const sequenceId = content?.sequenceId; this.logger.debug(`<${sequenceId} (${this.id})> take, target <${this.targetId}>`); - ++this[kCounters].take; + ++this[K_COUNTERS].take; this._publishEvent('take', content); return true; }; +/** + * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits + * flow.looped instead when the target id is already in the sequence. + * @param {Record} [content] + */ SequenceFlow.prototype.discard = function discard(content = {}) { const sequenceId = content?.sequenceId ?? getUniqueId(this.id); const discardSequence = (content.discardSequence = content.discardSequence?.slice() || []); if (discardSequence.indexOf(this.targetId) > -1) { - ++this[kCounters].looped; + ++this[K_COUNTERS].looped; this.logger.debug(`<${this.id}> discard loop detected <${this.sourceId}> -> <${this.targetId}>. Stop.`); return this._publishEvent('looped', content); } @@ -70,10 +86,15 @@ SequenceFlow.prototype.discard = function discard(content = {}) { discardSequence.push(this.sourceId); this.logger.debug(`<${sequenceId} (${this.id})> discard, target <${this.targetId}>`); - ++this[kCounters].discard; + ++this[K_COUNTERS].discard; this._publishEvent('discard', content); }; +/** + * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` + * is set. + * @returns {import('types').SequenceFlowState | undefined} + */ SequenceFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); if (!brokerState && this.environment.settings.disableTrackState) return; @@ -86,19 +107,35 @@ SequenceFlow.prototype.getState = function getState() { }; }; +/** + * Restore flow state captured by getState. + * @param {import('types').SequenceFlowState} state + */ SequenceFlow.prototype.recover = function recover(state) { - Object.assign(this[kCounters], state.counters); + Object.assign(this[K_COUNTERS], state.counters); this.broker.recover(state.broker); }; +/** + * Resolve a Flow Api wrapper. + * @param {import('types').ElementBrokerMessage} [message] + */ SequenceFlow.prototype.getApi = function getApi(message) { return FlowApi(this.broker, message || { content: this.createMessage() }); }; +/** + * Stop the flow's broker. + */ SequenceFlow.prototype.stop = function stop() { this.broker.stop(); }; +/** + * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop + * when the target was already visited, otherwise flow.shake. + * @param {import('types').ElementBrokerMessage} message + */ SequenceFlow.prototype.shake = function shake(message) { const content = cloneContent(message.content); @@ -123,6 +160,11 @@ SequenceFlow.prototype.shake = function shake(message) { } }; +/** + * Resolve the flow's condition (script or expression). Returns null when no condition is set. + * Emits a fatal error when the script language is missing or unsupported. + * @returns {import('types').ISequenceFlowCondition | null} + */ SequenceFlow.prototype.getCondition = function getCondition() { const conditionExpression = this.behaviour.conditionExpression; if (!conditionExpression) return null; @@ -143,6 +185,10 @@ SequenceFlow.prototype.getCondition = function getCondition() { return new ExpressionCondition(this, conditionExpression.body); }; +/** + * Build a flow event message body, optionally merging override content. + * @param {Record} [override] + */ SequenceFlow.prototype.createMessage = function createMessage(override) { return { ...override, @@ -157,6 +203,11 @@ SequenceFlow.prototype.createMessage = function createMessage(override) { }; }; +/** + * Evaluate the flow's condition for the source activity message. Default flows are always taken. + * @param {import('types').ElementBrokerMessage} fromMessage Source activity message + * @param {(err: Error | null, result?: boolean | object) => void} callback Callback with truthy result if flow should be taken + */ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { if (this.isDefault) { return callback(null, true); @@ -170,6 +221,7 @@ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { flowCondition.execute(fromMessage, callback); }; +/** @internal */ SequenceFlow.prototype._publishEvent = function publishEvent(action, content) { const eventContent = this.createMessage({ action, diff --git a/src/gateways/EventBasedGateway.js b/src/gateways/EventBasedGateway.js index b803da4e..8fd21c3e 100644 --- a/src/gateways/EventBasedGateway.js +++ b/src/gateways/EventBasedGateway.js @@ -1,8 +1,6 @@ import Activity from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; - -const kCompleted = Symbol.for('completed'); -const kTargets = Symbol.for('targets'); +import { K_COMPLETED, K_TARGETS } from '../constants.js'; export default function EventBasedGateway(activityDef, context) { return new Activity(EventBasedGatewayBehaviour, activityDef, context); @@ -14,27 +12,29 @@ export function EventBasedGatewayBehaviour(activity, context) { this.activity = activity; this.broker = activity.broker; this.context = context; - this[kTargets] = new Set(activity.outbound.map((flow) => context.getActivityById(flow.targetId))); + /** @private */ + this[K_TARGETS] = new Set(activity.outbound.map((flow) => context.getActivityById(flow.targetId))); } EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const { executionId, outbound = [], outboundTaken } = executeContent; - const targets = this[kTargets]; - this[kCompleted] = false; + const targets = this[K_TARGETS]; + /** @private */ + this[K_COMPLETED] = false; if (!targets.size) return this._complete(executeContent); for (const flow of this.activity.outbound) { outbound.push({ id: flow.id, action: 'take' }); } - if (!this[kCompleted] && outboundTaken) return; + if (!this[K_COMPLETED] && outboundTaken) return; const targetConsumerTag = `_gateway-listener-${this.id}`; const onTargetCompleted = this._onTargetCompleted.bind(this, executeMessage); - for (const target of this[kTargets]) { + for (const target of this[K_TARGETS]) { target.broker.subscribeOnce('event', 'activity.end', onTargetCompleted, { consumerTag: targetConsumerTag }); } @@ -43,7 +43,8 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) consumerTag: '_api-stop-execution', }); - this[kCompleted] = false; + /** @private */ + this[K_COMPLETED] = false; if (!executeMessage.fields.redelivered) { return broker.publish('execution', 'execute.outbound.take', cloneContent(executeContent, { outboundTaken: true })); @@ -57,7 +58,7 @@ EventBasedGatewayBehaviour.prototype._onTargetCompleted = function onTargetCompl this.activity.logger.debug(`<${executionId} (${this.id})> <${targetExecutionId}> completed run, discarding the rest`); this._stop(); - for (const target of this[kTargets]) { + for (const target of this[K_TARGETS]) { if (target === owner) continue; target.discard(); } @@ -74,12 +75,13 @@ EventBasedGatewayBehaviour.prototype._onTargetCompleted = function onTargetCompl }; EventBasedGatewayBehaviour.prototype._complete = function complete(completedContent) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this.broker.publish('execution', 'execute.completed', cloneContent(completedContent)); }; EventBasedGatewayBehaviour.prototype._stop = function stop() { const targetConsumerTag = `_gateway-listener-${this.id}`; - for (const target of this[kTargets]) target.broker.cancel(targetConsumerTag); + for (const target of this[K_TARGETS]) target.broker.cancel(targetConsumerTag); this.broker.cancel('_api-stop-execution'); }; diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index f0a7ee9d..030ca306 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -1,13 +1,12 @@ import Activity from '../activity/Activity.js'; import { cloneContent, cloneMessage } from '../messageHelper.js'; +import { K_EXECUTE_MESSAGE, K_TARGETS } from '../constants.js'; const STATE_MONTITORING = 'monitoring'; const STATE_SETUP = 'setup'; -const kPeers = Symbol.for('peers'); -const kInboundSourceIds = Symbol.for('inbound peers'); -const kTargets = Symbol.for('targets'); -const kExecuteMessage = Symbol.for('executeMessage'); +const K_PEERS = Symbol.for('peers'); +const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); export default function ParallelGateway(activityDef, context) { const activity = new Activity(ParallelGatewayBehaviour, { ...activityDef, isParallelGateway: true }, context); @@ -17,7 +16,7 @@ export default function ParallelGateway(activityDef, context) { activity.broker.cancel('_api-shake'); activity.broker.subscribeTmp('api', 'activity.shake.continue', onApiShake, { noAck: true, consumerTag: '_api-shake', priority: 1000 }); - const peers = (activity[kPeers] = new Map(activity.inbound.map(({ id: flowId, sourceId }) => [flowId, new Set([sourceId])]))); + const peers = (activity[K_PEERS] = new Map(activity.inbound.map(({ id: flowId, sourceId }) => [flowId, new Set([sourceId])]))); return activity; @@ -53,13 +52,14 @@ export function ParallelGatewayBehaviour(activity) { this.inbound = new Set(); this.isConverging = new Set(activity.inbound.map(({ sourceId }) => sourceId)).size > 1; - this[kExecuteMessage] = undefined; + /** @private */ + this[K_EXECUTE_MESSAGE] = undefined; } Object.defineProperties(ParallelGatewayBehaviour.prototype, { executionId: { get() { - return this[kExecuteMessage]?.content.executionId; + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }, }); @@ -70,7 +70,8 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; if (executeContent.isRootScope) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; switch (routingKey) { case 'execute.start': { @@ -87,12 +88,13 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { }; ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { - const peerIds = new Set([...this.activity[kPeers].values()].map((v) => [...v]).flat()); - this[kTargets] = new Map([...peerIds].map((pid) => [pid, this.activity.getActivityById(pid)])); + const peerIds = new Set([...this.activity[K_PEERS].values()].map((v) => [...v]).flat()); + /** @private */ + this[K_TARGETS] = new Map([...peerIds].map((pid) => [pid, this.activity.getActivityById(pid)])); - this.peerMonitor = new PeerMonitor(this.activity, this.activity[kInboundSourceIds], this[kTargets]); + this.peerMonitor = new PeerMonitor(this.activity, this.activity[K_INBOUND_SOURCE_IDS], this[K_TARGETS]); - const message = (this[kExecuteMessage] = cloneMessage(executeMessage)); + const message = (this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage)); const executeContent = message.content; const { executionId } = executeContent; @@ -161,7 +163,7 @@ ParallelGatewayBehaviour.prototype._complete = function complete() { this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring with state: ${state}`); - const content = cloneContent(this[kExecuteMessage].content, { isRootScope: true, state }); + const content = cloneContent(this[K_EXECUTE_MESSAGE].content, { isRootScope: true, state }); content.inbound = this.peerMonitor.inbound; return this.broker.publish('execution', `execute.${state}`, content); diff --git a/src/io/InputOutputSpecification.js b/src/io/InputOutputSpecification.js index 5e759942..f4fe7f2a 100644 --- a/src/io/InputOutputSpecification.js +++ b/src/io/InputOutputSpecification.js @@ -1,7 +1,6 @@ import getPropertyValue from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; - -const kConsuming = Symbol.for('consuming'); +import { K_CONSUMING } from '../constants.js'; export default function IoSpecification(activity, ioSpecificationDef, context) { const { id, type = 'iospecification', behaviour = {} } = ioSpecificationDef; @@ -14,18 +13,19 @@ export default function IoSpecification(activity, ioSpecificationDef, context) { } IoSpecification.prototype.activate = function activate(message) { - if (this[kConsuming]) return; + if (this[K_CONSUMING]) return; if (message?.fields.redelivered && message.fields.routingKey === 'run.start') { this._onFormatEnter(); } if (message?.fields.redelivered && message.fields.routingKey === 'run.end') { this._onFormatComplete(message); } - this[kConsuming] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); + /** @private */ + this[K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); }; IoSpecification.prototype.deactivate = function deactivate() { - if (this[kConsuming]) this[kConsuming] = this[kConsuming].cancel(); + if (this[K_CONSUMING]) this[K_CONSUMING] = this[K_CONSUMING].cancel(); }; IoSpecification.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { diff --git a/src/io/Properties.js b/src/io/Properties.js index 69bb0190..050e122b 100644 --- a/src/io/Properties.js +++ b/src/io/Properties.js @@ -1,13 +1,13 @@ import getPropertyValue from '../getPropertyValue.js'; +import { K_CONSUMING } from '../constants.js'; -const kProperties = Symbol.for('properties'); -const kConsuming = Symbol.for('consuming'); +const K_PROPERTIES = Symbol.for('properties'); export default function Properties(activity, propertiesDef, context) { this.activity = activity; this.broker = activity.broker; - const props = (this[kProperties] = { + const props = (this[K_PROPERTIES] = { properties: new Set(), dataInputObjects: new Set(), dataOutputObjects: new Set(), @@ -58,7 +58,7 @@ export default function Properties(activity, propertiesDef, context) { } Properties.prototype.activate = function activate(message) { - if (this[kConsuming]) return; + if (this[K_CONSUMING]) return; if (message.fields.redelivered && message.fields.routingKey === 'run.start') { this._onActivityEvent('activity.enter', message); } @@ -67,11 +67,12 @@ Properties.prototype.activate = function activate(message) { this._onActivityEvent('activity.extension.resume', message); } - this[kConsuming] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); + /** @private */ + this[K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); }; Properties.prototype.deactivate = function deactivate() { - if (this[kConsuming]) this[kConsuming] = this[kConsuming].cancel(); + if (this[K_CONSUMING]) this[K_CONSUMING] = this[K_CONSUMING].cancel(); }; Properties.prototype._onActivityEvent = function onActivityEvent(routingKey, message) { @@ -87,7 +88,7 @@ Properties.prototype._onActivityEvent = function onActivityEvent(routingKey, mes Properties.prototype._formatOnEnter = function formatOnEnter(message) { const startRoutingKey = 'run.enter.bpmn-properties'; - const dataInputObjects = this[kProperties].dataInputObjects; + const dataInputObjects = this[K_PROPERTIES].dataInputObjects; const broker = this.broker; if (!dataInputObjects.size) { return broker.getQueue('format-run-q').queueMessage( @@ -120,7 +121,7 @@ Properties.prototype._formatOnComplete = function formatOnComplete(message) { const messageOutput = getPropertyValue(message, 'content.output.properties') || {}; const outputProperties = this._getProperties(message, messageOutput); - const dataOutputObjects = this[kProperties].dataOutputObjects; + const dataOutputObjects = this[K_PROPERTIES].dataOutputObjects; const broker = this.broker; if (!dataOutputObjects.size) { return broker.getQueue('format-run-q').queueMessage( @@ -154,7 +155,7 @@ Properties.prototype._getProperties = function getProperties(message, values) { response = { ...message.content.properties }; } - for (const { id, type, name } of this[kProperties].properties) { + for (const { id, type, name } of this[K_PROPERTIES].properties) { if (!(id in response)) { response[id] = { id, type, name }; } diff --git a/src/process/Lane.js b/src/process/Lane.js index 3739c6d4..0630ff67 100644 --- a/src/process/Lane.js +++ b/src/process/Lane.js @@ -1,10 +1,17 @@ -const kProcess = Symbol.for('process'); +const K_PROCESS = Symbol.for('process'); +/** + * Process lane. Wraps a `` definition and points back to its owning process; + * activities reference their lane through `Activity.lane`. + * @param {import('types').Process} process + * @param {import('moddle-context-serializer').SerializableElement} laneDefinition + */ export default function Lane(process, laneDefinition) { const { broker, environment } = process; const { id, type, behaviour } = laneDefinition; - this[kProcess] = process; + /** @private */ + this[K_PROCESS] = process; this.id = id; this.type = type; @@ -21,7 +28,8 @@ export default function Lane(process, laneDefinition) { } Object.defineProperty(Lane.prototype, 'process', { + /** @returns {import('types').Process} */ get() { - return this[kProcess]; + return this[K_PROCESS]; }, }); diff --git a/src/process/Process.js b/src/process/Process.js index 44982107..371b9243 100644 --- a/src/process/Process.js +++ b/src/process/Process.js @@ -4,17 +4,19 @@ import { ProcessApi } from '../Api.js'; import { ProcessBroker } from '../EventBroker.js'; import { cloneMessage, cloneContent, cloneParent } from '../messageHelper.js'; import { makeErrorFromMessage } from '../error/Errors.js'; - -const kConsuming = Symbol.for('consuming'); -const kCounters = Symbol.for('counters'); -const kExec = Symbol.for('execution'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kExtensions = Symbol.for('extensions'); -const kLanes = Symbol.for('lanes'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kStateMessage = Symbol.for('stateMessage'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); +import { + K_CONSUMING, + K_COUNTERS, + K_EXECUTE_MESSAGE, + K_EXECUTION, + K_EXTENSIONS, + K_MESSAGE_HANDLERS, + K_STATE_MESSAGE, + K_STATUS, + K_STOPPED, +} from '../constants.js'; + +const K_LANES = Symbol.for('lanes'); export default Process; @@ -37,14 +39,19 @@ export function Process(processDef, context) { const environment = (this.environment = context.environment); this.context = context; - this[kCounters] = { + /** @private */ + this[K_COUNTERS] = { completed: 0, discarded: 0, }; - this[kConsuming] = false; - this[kExec] = new Map(); - this[kStatus] = undefined; - this[kStopped] = false; + /** @private */ + this[K_CONSUMING] = false; + /** @private */ + this[K_EXECUTION] = new Map(); + /** @private */ + this[K_STATUS] = undefined; + /** @private */ + this[K_STOPPED] = false; const { broker, on, once, waitFor } = ProcessBroker(this); this.broker = broker; @@ -52,7 +59,8 @@ export function Process(processDef, context) { this.once = once; this.waitFor = waitFor; - this[kMessageHandlers] = { + /** @private */ + this[K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onRunMessage: this._onRunMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this), @@ -61,57 +69,59 @@ export function Process(processDef, context) { this.logger = environment.Logger(type.toLowerCase()); if (behaviour.lanes) { - this[kLanes] = behaviour.lanes.map((lane) => new lane.Behaviour(this, lane)); + /** @private */ + this[K_LANES] = behaviour.lanes.map((lane) => new lane.Behaviour(this, lane)); } - this[kExtensions] = context.loadExtensions(this); + /** @private */ + this[K_EXTENSIONS] = context.loadExtensions(this); } Object.defineProperties(Process.prototype, { counters: { get() { - return { ...this[kCounters] }; + return { ...this[K_COUNTERS] }; }, }, lanes: { get() { - return this[kLanes]?.slice(); + return this[K_LANES]?.slice(); }, }, extensions: { get() { - return this[kExtensions]; + return this[K_EXTENSIONS]; }, }, stopped: { get() { - return this[kStopped]; + return this[K_STOPPED]; }, }, isRunning: { get() { - if (!this[kConsuming]) return false; + if (!this[K_CONSUMING]) return false; return !!this.status; }, }, executionId: { get() { - const exec = this[kExec]; + const exec = this[K_EXECUTION]; return exec.get('executionId') || exec.get('initExecutionId'); }, }, execution: { get() { - return this[kExec].get('execution'); + return this[K_EXECUTION].get('execution'); }, }, status: { get() { - return this[kStatus]; + return this[K_STATUS]; }, }, activityStatus: { get() { - return this[kExec].get('execution')?.activityStatus || 'idle'; + return this[K_EXECUTION].get('execution')?.activityStatus || 'idle'; }, }, }); @@ -122,7 +132,8 @@ Object.defineProperties(Process.prototype, { */ Process.prototype.init = function init(useAsExecutionId) { const initExecutionId = useAsExecutionId || getUniqueId(this.id); - this[kExec].set('initExecutionId', initExecutionId); + /** @private */ + this[K_EXECUTION].set('initExecutionId', initExecutionId); this._debug(`initialized with executionId <${initExecutionId}>`); this._publishEvent('init', this._createMessage({ executionId: initExecutionId })); @@ -136,7 +147,7 @@ Process.prototype.init = function init(useAsExecutionId) { Process.prototype.run = function run(runContent) { if (this.isRunning) throw new Error(`process <${this.id}> is already running`); - const exec = this[kExec]; + const exec = this[K_EXECUTION]; const executionId = exec.get('initExecutionId') || getUniqueId(this.id); exec.delete('initExecutionId'); exec.set('executionId', executionId); @@ -153,14 +164,15 @@ Process.prototype.run = function run(runContent) { /** * Resume after recover by republishing the last run message. - * @returns this + * @returns {this} * @throws {Error} when called on a running process */ Process.prototype.resume = function resume() { if (this.isRunning) throw new Error(`cannot resume running process <${this.id}>`); if (!this.status) return this; - this[kStopped] = false; + /** @private */ + this[K_STOPPED] = false; const content = this._createMessage(); this.broker.publish('run', 'run.resume', content, { persistent: false }); @@ -188,18 +200,21 @@ Process.prototype.getState = function getState() { /** * Restore process state captured by getState. * @param {import('types').ProcessState} [state] - * @returns this + * @returns {this} * @throws {Error} when called on a running process */ Process.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running process <${this.id}>`); if (!state) return this; - this[kStopped] = !!state.stopped; - this[kStatus] = state.status; - const exec = this[kExec]; + /** @private */ + this[K_STOPPED] = !!state.stopped; + /** @private */ + this[K_STATUS] = state.status; + const exec = this[K_EXECUTION]; exec.set('executionId', state.executionId); - this[kCounters] = { ...this[kCounters], ...state.counters }; + /** @private */ + this[K_COUNTERS] = { ...this[K_COUNTERS], ...state.counters }; this.environment.recover(state.environment); if (state.execution) { @@ -235,7 +250,7 @@ Process.prototype.stop = function stop() { Process.prototype.getApi = function getApi(message) { const execution = this.execution; if (execution) return execution.getApi(message); - return ProcessApi(this.broker, message || this[kStateMessage]); + return ProcessApi(this.broker, message || this[K_STATE_MESSAGE]); }; /** @@ -256,9 +271,10 @@ Process.prototype.cancelActivity = function cancelActivity(message) { /** @internal */ Process.prototype._activateRunConsumers = function activateRunConsumers() { - this[kConsuming] = true; + /** @private */ + this[K_CONSUMING] = true; const broker = this.broker; - const { onApiMessage, onRunMessage } = this[kMessageHandlers]; + const { onApiMessage, onRunMessage } = this[K_MESSAGE_HANDLERS]; broker.subscribeTmp('api', `process.*.${this.executionId}`, onApiMessage, { noAck: true, consumerTag: '_process-api', priority: 100 }); broker.getQueue('run-q').assertConsumer(onRunMessage, { exclusive: true, consumerTag: '_process-run' }); }; @@ -269,7 +285,8 @@ Process.prototype._deactivateRunConsumers = function deactivateRunConsumers() { broker.cancel('_process-api'); broker.cancel('_process-run'); broker.cancel('_process-execution'); - this[kConsuming] = false; + /** @private */ + this[K_CONSUMING] = false; }; /** @internal */ @@ -280,37 +297,43 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { return this._onResumeMessage(message); } - this[kStateMessage] = message; + /** @private */ + this[K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this._debug('enter'); - this[kStatus] = 'entered'; + /** @private */ + this[K_STATUS] = 'entered'; if (fields.redelivered) break; - this[kExec].delete('execution'); + /** @private */ + this[K_EXECUTION].delete('execution'); this._publishEvent('enter', content); break; } case 'run.start': { this._debug('start'); - this[kStatus] = 'start'; + /** @private */ + this[K_STATUS] = 'start'; this._publishEvent('start', content); break; } case 'run.execute': { - const exec = this[kExec]; - this[kStatus] = 'executing'; + const exec = this[K_EXECUTION]; + /** @private */ + this[K_STATUS] = 'executing'; const executeMessage = cloneMessage(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - this[kExecuteMessage] = message; + /** @private */ + this[K_EXECUTE_MESSAGE] = message; - this.broker.getQueue('execution-q').assertConsumer(this[kMessageHandlers].onExecutionMessage, { + this.broker.getQueue('execution-q').assertConsumer(this[K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, consumerTag: '_process-execution', }); @@ -320,7 +343,8 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { return execution.execute(executeMessage); } case 'run.error': { - this[kStatus] = 'errored'; + /** @private */ + this[K_STATUS] = 'errored'; this._publishEvent( 'error', cloneContent(content, { @@ -330,12 +354,14 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { break; } case 'run.end': { - this[kStatus] = 'end'; + /** @private */ + this[K_STATUS] = 'end'; if (fields.redelivered) break; this._debug('completed'); - this[kCounters].completed++; + /** @private */ + this[K_COUNTERS].completed++; this.broker.publish('run', 'run.leave', content); @@ -343,10 +369,12 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { break; } case 'run.discarded': { - this[kStatus] = 'discarded'; + /** @private */ + this[K_STATUS] = 'discarded'; if (fields.redelivered) break; - this[kCounters].discarded++; + /** @private */ + this[K_COUNTERS].discarded++; this.broker.publish('run', 'run.leave', content); @@ -354,7 +382,8 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { break; } case 'run.leave': { - this[kStatus] = undefined; + /** @private */ + this[K_STATUS] = undefined; message.ack(); this._deactivateRunConsumers(); const { output, ...rest } = content; @@ -370,7 +399,7 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { Process.prototype._onResumeMessage = function onResumeMessage(message) { message.ack(); - const stateMessage = this[kStateMessage]; + const stateMessage = this[K_STATE_MESSAGE]; switch (stateMessage.fields.routingKey) { case 'run.enter': case 'run.start': @@ -412,8 +441,9 @@ Process.prototype._onExecutionMessage = function onExecutionMessage(routingKey, } } - const executeMessage = this[kExecuteMessage]; - this[kExecuteMessage] = null; + const executeMessage = this[K_EXECUTE_MESSAGE]; + /** @private */ + this[K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; @@ -486,7 +516,7 @@ Process.prototype.getSequenceFlows = function getSequenceFlows() { * @param {string} laneId */ Process.prototype.getLaneById = function getLaneById(laneId) { - const lanes = this[kLanes]; + const lanes = this[K_LANES]; if (!lanes) return; return lanes.find((lane) => lane.id === laneId); }; @@ -516,7 +546,8 @@ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { /** @internal */ Process.prototype._onStop = function onStop() { - this[kStopped] = true; + /** @private */ + this[K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop'); }; diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index b57f0507..c7a58cbf 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -2,19 +2,14 @@ import { ProcessApi } from '../Api.js'; import { cloneContent, cloneMessage, pushParent } from '../messageHelper.js'; import { getUniqueId } from '../shared.js'; import { ActivityTracker } from '../Tracker.js'; +import { K_ACTIVATED, K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS, K_STATUS, K_STOPPED } from '../constants.js'; export default ProcessExecution; -const kActivated = Symbol.for('activated'); -const kActivityQ = Symbol.for('activityQ'); -const kCompleted = Symbol.for('completed'); -const kElements = Symbol.for('elements'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kMessageHandlers = Symbol.for('messageHandlers'); -const kParent = Symbol.for('parent'); -const kStatus = Symbol.for('status'); -const kStopped = Symbol.for('stopped'); -const kTracker = Symbol.for('activity tracker'); +const K_ACTIVITY_Q = Symbol.for('activityQ'); +const K_ELEMENTS = Symbol.for('elements'); +const K_PARENT = Symbol.for('parent'); +const K_TRACKER = Symbol.for('activity tracker'); /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -25,7 +20,8 @@ const kTracker = Symbol.for('activity tracker'); function ProcessExecution(parentActivity, context) { const { id, type, broker, isSubProcess, isTransaction } = parentActivity; - this[kParent] = parentActivity; + /** @private */ + this[K_PARENT] = parentActivity; this.id = id; this.type = type; this.isSubProcess = isSubProcess; @@ -34,7 +30,8 @@ function ProcessExecution(parentActivity, context) { this.environment = context.environment; this.context = context; - this[kElements] = { + /** @private */ + this[K_ELEMENTS] = { postponed: new Set(), children: context.getActivities(id), associations: context.getAssociations(id), @@ -50,14 +47,20 @@ function ProcessExecution(parentActivity, context) { const exchangeName = (this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution'); broker.assertExchange(exchangeName, 'topic', { autoDelete: false, durable: true }); - this[kCompleted] = false; - this[kStopped] = false; - this[kActivated] = false; - this[kStatus] = 'init'; - this[kTracker] = new ActivityTracker(id); + /** @private */ + this[K_COMPLETED] = false; + /** @private */ + this[K_STOPPED] = false; + /** @private */ + this[K_ACTIVATED] = false; + /** @private */ + this[K_STATUS] = 'init'; + /** @private */ + this[K_TRACKER] = new ActivityTracker(id); this.executionId = undefined; - this[kMessageHandlers] = { + /** @private */ + this[K_MESSAGE_HANDLERS] = { onActivityEvent: this._onActivityEvent.bind(this), onApiMessage: this._onApiMessage.bind(this), onChildMessage: this._onChildMessage.bind(this), @@ -68,32 +71,32 @@ function ProcessExecution(parentActivity, context) { Object.defineProperties(ProcessExecution.prototype, { stopped: { get() { - return this[kStopped]; + return this[K_STOPPED]; }, }, completed: { get() { - return this[kCompleted]; + return this[K_COMPLETED]; }, }, status: { get() { - return this[kStatus]; + return this[K_STATUS]; }, }, postponedCount: { get() { - return this[kElements].postponed.size; + return this[K_ELEMENTS].postponed.size; }, }, isRunning: { get() { - return this[kActivated]; + return this[K_ACTIVATED]; }, }, activityStatus: { get() { - return this[kTracker].activityStatus; + return this[K_TRACKER].activityStatus; }, }, }); @@ -109,15 +112,18 @@ ProcessExecution.prototype.execute = function execute(executeMessage) { const executionId = (this.executionId = executeMessage.content.executionId); - this[kExecuteMessage] = cloneMessage(executeMessage, { + /** @private */ + this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage, { executionId, state: 'start', }); - this[kStopped] = false; + /** @private */ + this[K_STOPPED] = false; this.environment.assignVariables(executeMessage); - this[kActivityQ] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); + /** @private */ + this[K_ACTIVITY_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); if (executeMessage.fields.redelivered) { return this.resume(); @@ -136,11 +142,11 @@ ProcessExecution.prototype.execute = function execute(executeMessage) { ProcessExecution.prototype.resume = function resume() { this._debug(`resume process execution at ${this.status}`); - if (this[kCompleted]) return this._complete('completed'); + if (this[K_COMPLETED]) return this._complete('completed'); this._activate(); - const { startActivities, postponed, detachedActivities, convergingGateways } = this[kElements]; + const { startActivities, postponed, detachedActivities, convergingGateways } = this[K_ELEMENTS]; if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); const skipDiscard = (this.environment.settings.skipDiscard = result.settings.skipDiscard); @@ -152,17 +158,18 @@ ProcessExecution.prototype.resume = function resume() { postponed.clear(); detachedActivities.clear(); - this[kActivityQ].consume(this[kMessageHandlers].onChildMessage, { + /** @private */ + this[K_ACTIVITY_Q].consume(this[K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; const status = this.status; if (status === 'init') return this._start(); - const tracker = this[kTracker]; + const tracker = this[K_TRACKER]; for (const msg of new Set(postponed)) { const activity = this.getActivityById(msg.content.id); if (!activity) continue; @@ -177,7 +184,7 @@ ProcessExecution.prototype.resume = function resume() { activity.resume(); } - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; if (!postponed.size && status === 'executing') return this._complete('completed'); }; @@ -186,7 +193,7 @@ ProcessExecution.prototype.resume = function resume() { * Snapshot execution state including children, flows, message flows, and associations. */ ProcessExecution.prototype.getState = function getState() { - const { children, flows, outboundMessageFlows, associations } = this[kElements]; + const { children, flows, outboundMessageFlows, associations } = this[K_ELEMENTS]; const flowStates = flows.reduce((result, flow) => { const elmState = flow.getState(); @@ -196,8 +203,8 @@ ProcessExecution.prototype.getState = function getState() { return { executionId: this.executionId, - stopped: this[kStopped], - completed: this[kCompleted], + stopped: this[K_STOPPED], + completed: this[K_COMPLETED], status: this.status, children: children.reduce((result, activity) => { if (activity.placeholder) return result; @@ -216,15 +223,18 @@ ProcessExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. * @param {import('types').ProcessExecutionState} [state] - * @returns this + * @returns {this} */ ProcessExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - this[kStopped] = state.stopped; - this[kCompleted] = state.completed; - this[kStatus] = state.status; + /** @private */ + this[K_STOPPED] = state.stopped; + /** @private */ + this[K_COMPLETED] = state.completed; + /** @private */ + this[K_STATUS] = state.status; this._debug(`recover process execution at ${this.status}`); @@ -285,7 +295,7 @@ ProcessExecution.prototype.stop = function stop() { */ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { const result = []; - for (const msg of this[kElements].postponed) { + for (const msg of this[K_ELEMENTS].postponed) { const api = this._getChildApi(msg); if (!api) continue; if (filterFn && !filterFn(api)) continue; @@ -298,8 +308,9 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { * Queue a discard message that propagates to all running children. */ ProcessExecution.prototype.discard = function discard() { - this[kStatus] = 'discard'; - return this[kActivityQ].queueMessage( + /** @private */ + this[K_STATUS] = 'discard'; + return this[K_ACTIVITY_Q].queueMessage( { routingKey: 'execution.discard' }, { id: this.id, @@ -314,7 +325,7 @@ ProcessExecution.prototype.discard = function discard() { * Queue a cancel message that propagates to all running children. */ ProcessExecution.prototype.cancel = function discard() { - return this[kActivityQ].queueMessage( + return this[K_ACTIVITY_Q].queueMessage( { routingKey: 'execution.cancel' }, { id: this.id, @@ -329,28 +340,28 @@ ProcessExecution.prototype.cancel = function discard() { * Get child activities in the process scope. */ ProcessExecution.prototype.getActivities = function getActivities() { - return this[kElements].children.slice(); + return this[K_ELEMENTS].children.slice(); }; /** * @param {string} activityId */ ProcessExecution.prototype.getActivityById = function getActivityById(activityId) { - return this[kElements].children.find((child) => child.id === activityId); + return this[K_ELEMENTS].children.find((child) => child.id === activityId); }; /** * Get sequence flows in the process scope. */ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() { - return this[kElements].flows.slice(); + return this[K_ELEMENTS].flows.slice(); }; /** * Get associations in the process scope. */ ProcessExecution.prototype.getAssociations = function getAssociations() { - return this[kElements].associations.slice(); + return this[K_ELEMENTS].associations.slice(); }; /** @@ -358,7 +369,7 @@ ProcessExecution.prototype.getAssociations = function getAssociations() { * @param {import('types').ElementBrokerMessage} [message] */ ProcessExecution.prototype.getApi = function getApi(message) { - if (!message) return ProcessApi(this.broker, this[kExecuteMessage]); + if (!message) return ProcessApi(this.broker, this[K_EXECUTE_MESSAGE]); const content = message.content; @@ -367,7 +378,7 @@ ProcessExecution.prototype.getApi = function getApi(message) { } const api = ProcessApi(this.broker, message); - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const self = this; api.getExecuting = function getExecuting() { @@ -384,17 +395,18 @@ ProcessExecution.prototype.getApi = function getApi(message) { /** @internal */ ProcessExecution.prototype._start = function start() { - if (!this[kElements].children.length) { + if (!this[K_ELEMENTS].children.length) { return this._complete('completed'); } - this[kStatus] = 'start'; + /** @private */ + this[K_STATUS] = 'start'; - const executeContent = { ...this[kExecuteMessage].content, state: this.status }; + const executeContent = { ...this[K_EXECUTE_MESSAGE].content, state: this.status }; this.broker.publish(this._exchangeName, 'execute.start', cloneContent(executeContent)); - const { startActivities, postponed, detachedActivities, convergingGateways } = this[kElements]; + const { startActivities, postponed, detachedActivities, convergingGateways } = this[K_ELEMENTS]; if (startActivities.size > 1 || convergingGateways.size) { const result = this._shakeElements(); const skipDiscard = (this.environment.settings.skipDiscard = result.settings.skipDiscard); @@ -404,18 +416,20 @@ ProcessExecution.prototype._start = function start() { } for (const a of startActivities) a.init(); - this[kStatus] = 'executing'; + /** @private */ + this[K_STATUS] = 'executing'; for (const a of startActivities) a.run(); if (!startActivities.size) { - for (const a of this[kElements].triggeredByEvent) { + for (const a of this[K_ELEMENTS].triggeredByEvent) { if (a.isCatching && !a.isRunning) a.run(); } } postponed.clear(); detachedActivities.clear(); - this[kActivityQ].assertConsumer(this[kMessageHandlers].onChildMessage, { + /** @private */ + this[K_ACTIVITY_Q].assertConsumer(this[K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}`, }); @@ -423,7 +437,7 @@ ProcessExecution.prototype._start = function start() { /** @internal */ ProcessExecution.prototype._activate = function activate() { - const { onApiMessage, onMessageFlowEvent, onActivityEvent } = this[kMessageHandlers]; + const { onApiMessage, onMessageFlowEvent, onActivityEvent } = this[K_MESSAGE_HANDLERS]; if (!this.isSubProcess) { this.broker.consume('api-q', onApiMessage, { @@ -440,7 +454,8 @@ ProcessExecution.prototype._activate = function activate() { } const { outboundMessageFlows, flows, associations, startActivities, startSequences, triggeredByEvent, convergingGateways, children } = - this[kElements]; + /** @private */ + this[K_ELEMENTS]; for (const flow of outboundMessageFlows) { flow.activate(); @@ -491,7 +506,8 @@ ProcessExecution.prototype._activate = function activate() { } } - this[kActivated] = true; + /** @private */ + this[K_ACTIVATED] = true; }; /** @internal */ @@ -501,7 +517,7 @@ ProcessExecution.prototype._deactivate = function deactivate() { broker.cancel(`_process-api-consumer-${executionId}`); broker.cancel(`_process-activity-${executionId}`); - const { children, flows, associations, outboundMessageFlows } = this[kElements]; + const { children, flows, associations, outboundMessageFlows } = this[K_ELEMENTS]; for (const activity of children) { if (activity.placeholder) continue; @@ -522,7 +538,8 @@ ProcessExecution.prototype._deactivate = function deactivate() { flow.broker.cancel('_process-message-consumer'); } - this[kActivated] = false; + /** @private */ + this[K_ACTIVATED] = false; }; /** @internal */ @@ -534,7 +551,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { this.executionId = getUniqueId(id); this._activate(); } - const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities; + const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[K_ELEMENTS].startActivities; const result = { settings: { @@ -554,7 +571,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { switch (routingKey) { case 'activity.shake.link': { - for (const a of this[kElements].triggeredByEvent) { + for (const a of this[K_ELEMENTS].triggeredByEvent) { if (!a.isCatching) continue; a.broker.publish('api', routingKey, cloneContent(content), { type: 'shake' }); } @@ -618,7 +635,7 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) this._debug(`delegate ${eventType} anonymous event`); } - for (const activity of this[kElements].triggeredByEvent) { + for (const activity of this[K_ELEMENTS].triggeredByEvent) { if (activity.isSubProcess && activity.getStartActivities({ referenceId: content.message?.id, referenceType: eventType }).length) { delegate = false; activity.run(content.message); @@ -654,14 +671,15 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe if (delegate) delegate = this._onDelegateEvent(message); - this[kTracker].track(routingKey, message); + /** @private */ + this[K_TRACKER].track(routingKey, message); this.broker.publish('event', routingKey, content, { ...properties, delegate, mandatory: false }); if (shaking) return this._onShakeMessage(message); if (!isDirectChild) return; switch (routingKey) { case 'process.terminate': - return this[kActivityQ].queueMessage({ routingKey: 'execution.terminate' }, cloneContent(content), { + return this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.terminate' }, cloneContent(content), { type: 'terminate', persistent: true, }); @@ -669,7 +687,8 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe return; } - this[kActivityQ].queueMessage(message.fields, cloneContent(content), { persistent: true, ...message.properties }); + /** @private */ + this[K_ACTIVITY_Q].queueMessage(message.fields, cloneContent(content), { persistent: true, ...message.properties }); }; /** @internal */ @@ -690,7 +709,7 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, return this._onDiscard(message); case 'execution.discard.detached': { message.ack(); - for (const detached of this[kElements].detachedActivities) { + for (const detached of this[K_ELEMENTS].detachedActivities) { this._getChildApi(detached).discard(); } return; @@ -700,7 +719,7 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, return this._onCancel(message); case 'activity.error.caught': { let prevMsg; - for (const msg of this[kElements].postponed) { + for (const msg of this[K_ELEMENTS].postponed) { if (msg.content.executionId === content.executionId) { prevMsg = msg; break; @@ -718,7 +737,8 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, switch (routingKey) { case 'activity.detach': { - this[kElements].detachedActivities.add(cloneMessage(message)); + /** @private */ + this[K_ELEMENTS].detachedActivities.add(cloneMessage(message)); break; } case 'activity.cancel': { @@ -739,14 +759,15 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, } case 'activity.error': { let eventCaughtBy; - for (const msg of this[kElements].postponed) { + for (const msg of this[K_ELEMENTS].postponed) { if (msg.fields.routingKey === 'activity.catch' && msg.content.source?.executionId === content.executionId) { eventCaughtBy = msg; break; } } if (eventCaughtBy) { - this[kActivityQ].queueMessage({ routingKey: 'activity.error.caught' }, cloneContent(content), { + /** @private */ + this[K_ACTIVITY_Q].queueMessage({ routingKey: 'activity.error.caught' }, cloneContent(content), { persistent: true, ...message.properties, }); @@ -761,12 +782,12 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, ProcessExecution.prototype._stateChangeMessage = function stateChangeMessage(message, postponeMessage) { const previousMsg = this._popPostponed(message.content); if (previousMsg) previousMsg.ack(); - if (postponeMessage) this[kElements].postponed.add(message); + if (postponeMessage) this[K_ELEMENTS].postponed.add(message); }; /** @internal */ ProcessExecution.prototype._popPostponed = function popPostponed(byContent) { - const { postponed, detachedActivities } = this[kElements]; + const { postponed, detachedActivities } = this[K_ELEMENTS]; let postponedMsg; if (byContent.sequenceId) { @@ -811,7 +832,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message } } - const { postponed, detachedActivities, startActivities } = this[kElements]; + const { postponed, detachedActivities, startActivities } = this[K_ELEMENTS]; const postponedCount = postponed.size; if (!postponedCount) { @@ -824,7 +845,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message this._debug(`left <${id}> (${type}), pending activities ${postponedCount} ${[...postponed].map((m) => m.content.id)}`); if (postponedCount && postponedCount === detachedActivities.size) { - return this[kActivityQ].queueMessage( + return this[K_ACTIVITY_Q].queueMessage( { routingKey: 'execution.discard.detached' }, { id: this.id, @@ -836,7 +857,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message } if (isEnd && startActivities.size) { - const startSequences = this[kElements].startSequences; + const startSequences = this[K_ELEMENTS].startSequences; for (const msg of postponed) { const postponedId = msg.content.id; const startSequence = startSequences.get(postponedId); @@ -857,12 +878,13 @@ ProcessExecution.prototype._stopExecution = function stopExecution(message) { for (const api of this.getPostponed()) api.stop(); } this._deactivate(); - this[kStopped] = true; + /** @private */ + this[K_STOPPED] = true; return this.broker.publish( this._exchangeName, `execution.stopped.${this.executionId}`, { - ...this[kExecuteMessage].content, + ...this[K_EXECUTE_MESSAGE].content, ...(message && message.content), }, { type: 'stopped', persistent: false } @@ -872,7 +894,7 @@ ProcessExecution.prototype._stopExecution = function stopExecution(message) { /** @internal */ ProcessExecution.prototype._onDiscard = function onDiscard() { this._deactivate(); - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const running = new Set(postponed); postponed.clear(); @@ -886,24 +908,26 @@ ProcessExecution.prototype._onDiscard = function onDiscard() { for (const msg of running) this._getChildApi(msg).discard(); } - this[kActivityQ].purge(); + /** @private */ + this[K_ACTIVITY_Q].purge(); return this._complete('discard'); }; /** @internal */ ProcessExecution.prototype._onCancel = function onCancel() { - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const running = new Set(postponed); const isTransaction = this.isTransaction; if (isTransaction) { this._debug(`cancel transaction execution (cancel child executions ${running.size})`); - this[kStatus] = 'cancel'; + /** @private */ + this[K_STATUS] = 'cancel'; this.broker.publish( 'event', 'transaction.cancel', - cloneMessage(this[kExecuteMessage], { + cloneMessage(this[K_EXECUTE_MESSAGE], { state: 'cancel', }) ); @@ -943,7 +967,8 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes case 'discard': return this.discard(message); case 'stop': - this[kActivityQ].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false }); + /** @private */ + this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false }); break; } }; @@ -967,7 +992,7 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou { consumerTag: `_ct-delegate-${correlationId}`, noAck: true } ); - for (const child of this[kElements].children) { + for (const child of this[K_ELEMENTS].children) { if (child.placeholder) continue; child.broker.publish('api', routingKey, cloneContent(message.content), message.properties); @@ -980,7 +1005,8 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou /** @internal */ ProcessExecution.prototype._complete = function complete(completionType, content) { this._deactivate(); - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; const status = this.status; switch (this.status) { @@ -993,16 +1019,18 @@ ProcessExecution.prototype._complete = function complete(completionType, content break; default: this._debug(`process execution ${completionType}`); - this[kStatus] = completionType; + /** @private */ + this[K_STATUS] = completionType; } const broker = this.broker; - this[kActivityQ].delete(); + /** @private */ + this[K_ACTIVITY_Q].delete(); return broker.publish( this._exchangeName, `execution.${completionType}.${this.executionId}`, - cloneContent(this[kExecuteMessage].content, { + cloneContent(this[K_EXECUTE_MESSAGE].content, { output: { ...this.environment.output }, ...content, state: completionType, @@ -1013,10 +1041,11 @@ ProcessExecution.prototype._complete = function complete(completionType, content /** @internal */ ProcessExecution.prototype._terminate = function terminate(message) { - this[kStatus] = 'terminated'; + /** @private */ + this[K_STATUS] = 'terminated'; this._debug('terminating process execution'); - const postponed = this[kElements].postponed; + const postponed = this[K_ELEMENTS].postponed; const running = new Set(postponed); postponed.clear(); @@ -1031,22 +1060,23 @@ ProcessExecution.prototype._terminate = function terminate(message) { msg.ack(); } - this[kActivityQ].purge(); + /** @private */ + this[K_ACTIVITY_Q].purge(); }; /** @internal */ ProcessExecution.prototype._getFlowById = function getFlowById(flowId) { - return this[kElements].flows.find((f) => f.id === flowId); + return this[K_ELEMENTS].flows.find((f) => f.id === flowId); }; /** @internal */ ProcessExecution.prototype._getAssociationById = function getAssociationById(associationId) { - return this[kElements].associations.find((a) => a.id === associationId); + return this[K_ELEMENTS].associations.find((a) => a.id === associationId); }; /** @internal */ ProcessExecution.prototype._getMessageFlowById = function getMessageFlowById(flowId) { - return this[kElements].outboundMessageFlows.find((f) => f.id === flowId); + return this[K_ELEMENTS].outboundMessageFlows.find((f) => f.id === flowId); }; /** @internal */ @@ -1078,7 +1108,7 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { if (message.fields.routingKey !== 'activity.shake.end') return; let seq; - if (!(seq = this[kElements].startSequences.get(message.content.id))) return; + if (!(seq = this[K_ELEMENTS].startSequences.get(message.content.id))) return; for (const s of message.content.sequence) { if (s.isSequenceFlow) continue; @@ -1088,5 +1118,6 @@ ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { /** @internal */ ProcessExecution.prototype._debug = function debugMessage(logMessage) { - this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); + /** @private */ + this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; diff --git a/src/tasks/ReceiveTask.js b/src/tasks/ReceiveTask.js old mode 100755 new mode 100644 index e95c18a6..332f8255 --- a/src/tasks/ReceiveTask.js +++ b/src/tasks/ReceiveTask.js @@ -1,10 +1,6 @@ import Activity from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; - -const kCompleted = Symbol.for('completed'); -const kExecuteMessage = Symbol.for('executeMessage'); -const kReferenceElement = Symbol.for('referenceElement'); -const kReferenceInfo = Symbol.for('referenceInfo'); +import { K_COMPLETED, K_EXECUTE_MESSAGE, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; export default function ReceiveTask(activityDef, context) { const task = new Activity(ReceiveTaskBehaviour, activityDef, context); @@ -32,7 +28,8 @@ export function ReceiveTaskBehaviour(activity) { this.activity = activity; this.broker = activity.broker; - this[kReferenceElement] = reference.id && activity.getActivityById(reference.id); + /** @private */ + this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); } ReceiveTaskBehaviour.prototype.execute = function execute(executeMessage) { @@ -47,19 +44,21 @@ function ReceiveTaskExecution(parent) { this.reference = reference; this.broker = broker; this.loopCharacteristics = loopCharacteristics; - this.referenceElement = parent[kReferenceElement]; + this.referenceElement = parent[K_REFERENCE_ELEMENT]; - this[kCompleted] = false; + /** @private */ + this[K_COMPLETED] = false; } ReceiveTaskExecution.prototype.execute = function execute(executeMessage) { - this[kExecuteMessage] = executeMessage; + /** @private */ + this[K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; const { executionId, isRootScope } = executeContent; this.executionId = executionId; - const info = (this[kReferenceInfo] = this._getReferenceInfo(executeMessage)); + const info = (this[K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage)); if (isRootScope) { this._setupMessageHandling(executionId); @@ -76,7 +75,7 @@ ReceiveTaskExecution.prototype.execute = function execute(executeMessage) { consumerTag: `_onmessage-${executionId}`, }); - if (this[kCompleted]) return; + if (this[K_COMPLETED]) return; broker.subscribeTmp('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { noAck: true, @@ -93,7 +92,7 @@ ReceiveTaskExecution.prototype._onCatchMessage = function onCatchMessage(routing const content = message.content; const { id: signalId, executionId: signalExecutionId } = content.message || {}; - const { message: referenceMessage, description } = this[kReferenceInfo]; + const { message: referenceMessage, description } = this[K_REFERENCE_INFO]; if ((!referenceMessage.id && signalId) || signalExecutionId) { if (this.loopCharacteristics && signalExecutionId !== this.executionId) return; @@ -106,7 +105,7 @@ ReceiveTaskExecution.prototype._onCatchMessage = function onCatchMessage(routing const { type: messageType, correlationId } = message.properties; const broker = this.broker; - const executeContent = this[kExecuteMessage].content; + const executeContent = this[K_EXECUTE_MESSAGE].content; broker.publish('event', 'activity.consumed', cloneContent(executeContent, { message: { ...message.content.message } }), { correlationId, @@ -128,9 +127,10 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, return this._complete(message.content.message, { correlationId }); } case 'discard': { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content), { correlationId }); + return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content), { correlationId }); } case 'stop': { return this._stop(); @@ -139,9 +139,10 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, }; ReceiveTaskExecution.prototype._complete = function complete(output, options) { - this[kCompleted] = true; + /** @private */ + this[K_COMPLETED] = true; this._stop(); - return this.broker.publish('execution', 'execute.completed', cloneContent(this[kExecuteMessage].content, { output }), options); + return this.broker.publish('execution', 'execute.completed', cloneContent(this[K_EXECUTE_MESSAGE].content, { output }), options); }; ReceiveTaskExecution.prototype._stop = function stop() { diff --git a/src/tasks/SubProcess.js b/src/tasks/SubProcess.js index 9527ec35..17e99c60 100644 --- a/src/tasks/SubProcess.js +++ b/src/tasks/SubProcess.js @@ -2,8 +2,8 @@ import Activity from '../activity/Activity.js'; import ProcessExecution from '../process/ProcessExecution.js'; import { cloneContent } from '../messageHelper.js'; -const kExecutions = Symbol.for('executions'); -const kOnExecutionCompleted = Symbol.for('execution completed handler'); +const K_EXECUTIONS = Symbol.for('executions'); +const K_ON_EXECUTION_COMPLETED = Symbol.for('execution completed handler'); export default function SubProcess(activityDef, context) { const triggeredByEvent = activityDef.behaviour && activityDef.behaviour.triggeredByEvent; @@ -38,19 +38,21 @@ export function SubProcessBehaviour(activity, context) { this.broker = activity.broker; this.executionId = undefined; - this[kExecutions] = new Set(); - this[kOnExecutionCompleted] = this._onExecutionCompleted.bind(this); + /** @private */ + this[K_EXECUTIONS] = new Set(); + /** @private */ + this[K_ON_EXECUTION_COMPLETED] = this._onExecutionCompleted.bind(this); } Object.defineProperties(SubProcessBehaviour.prototype, { execution: { get() { - return [...this[kExecutions]][0]; + return [...this[K_EXECUTIONS]][0]; }, }, executions: { get() { - return [...this[kExecutions]]; + return [...this[K_EXECUTIONS]]; }, }, }); @@ -73,7 +75,7 @@ SubProcessBehaviour.prototype.execute = function execute(executeMessage) { SubProcessBehaviour.prototype.getState = function getState() { const states = []; - for (const pe of this[kExecutions]) { + for (const pe of this[K_EXECUTIONS]) { const state = pe.getState(); state.environment = pe.environment.getState(); states.push(state); @@ -91,7 +93,7 @@ SubProcessBehaviour.prototype.getState = function getState() { SubProcessBehaviour.prototype.recover = function recover(state) { if (!state) return; - const executions = this[kExecutions]; + const executions = this[K_EXECUTIONS]; const loopCharacteristics = this.loopCharacteristics; if (loopCharacteristics && state.executions) { @@ -117,7 +119,7 @@ SubProcessBehaviour.prototype.recover = function recover(state) { SubProcessBehaviour.prototype.getPostponed = function getPostponed() { let postponed = []; - for (const pe of this[kExecutions]) { + for (const pe of this[K_EXECUTIONS]) { postponed = postponed.concat(pe.getPostponed()); } return postponed; @@ -137,7 +139,8 @@ SubProcessBehaviour.prototype._upsertExecution = function upsertExecution(execut const subContext = this.context.clone(subEnvironment, this.activity); execution = new ProcessExecution(this.activity, subContext); - this[kExecutions].add(execution); + /** @private */ + this[K_EXECUTIONS].add(execution); this._addListeners(executionId); @@ -145,7 +148,7 @@ SubProcessBehaviour.prototype._upsertExecution = function upsertExecution(execut }; SubProcessBehaviour.prototype._addListeners = function addListeners(executionId) { - this.broker.subscribeTmp('subprocess-execution', `execution.#.${executionId}`, this[kOnExecutionCompleted], { + this.broker.subscribeTmp('subprocess-execution', `execution.#.${executionId}`, this[K_ON_EXECUTION_COMPLETED], { noAck: true, consumerTag: `_sub-process-execution-${executionId}`, }); @@ -182,7 +185,8 @@ SubProcessBehaviour.prototype._onExecutionCompleted = function onExecutionComple SubProcessBehaviour.prototype._completeExecution = function completeExecution(completeRoutingKey, content) { if (this.loopCharacteristics) { const execution = this._getExecutionById(content.executionId); - this[kExecutions].delete(execution); + /** @private */ + this[K_EXECUTIONS].delete(execution); } this.broker.publish('execution', completeRoutingKey, cloneContent(content)); @@ -206,7 +210,7 @@ SubProcessBehaviour.prototype.getApi = function getApi(apiMessage) { }; SubProcessBehaviour.prototype._getExecutionById = function getExecutionById(executionId) { - for (const pe of this[kExecutions]) { + for (const pe of this[K_EXECUTIONS]) { if (pe.executionId === executionId) return pe; } }; diff --git a/test/bpmn-elements-test.js b/test/bpmn-elements-test.js index 1be61aa1..9e82b278 100644 --- a/test/bpmn-elements-test.js +++ b/test/bpmn-elements-test.js @@ -1,4 +1,4 @@ -import * as api from '../src/index.js'; +import * as api from 'bpmn-elements'; describe('bpmn-elemements module', () => { it('exports Timers', () => { diff --git a/test/feature/BoundaryEvent-feature.js b/test/feature/BoundaryEvent-feature.js index 5b5235c3..e2ebffb8 100644 --- a/test/feature/BoundaryEvent-feature.js +++ b/test/feature/BoundaryEvent-feature.js @@ -868,7 +868,7 @@ Feature('BoundaryEvent', () => { let end; When('task is completed', () => { - definition.waitFor('leave'); + end = definition.waitFor('leave'); definition.signal({ id: 'task' }); }); diff --git a/test/feature/issues/engine-issues-feature.js b/test/feature/issues/engine-issues-feature.js index 3feb8c54..f0f0aae8 100644 --- a/test/feature/issues/engine-issues-feature.js +++ b/test/feature/issues/engine-issues-feature.js @@ -1,4 +1,4 @@ -import { Definition } from '../../../src/index.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../../helpers/testHelpers.js'; import factory from '../../helpers/factory.js'; diff --git a/test/feature/issues/issue-31-feature.js b/test/feature/issues/issue-31-feature.js index 22deac37..6e227bbd 100644 --- a/test/feature/issues/issue-31-feature.js +++ b/test/feature/issues/issue-31-feature.js @@ -1,4 +1,4 @@ -import { Definition } from '../../../src/index.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../../helpers/testHelpers.js'; import factory from '../../helpers/factory.js'; diff --git a/test/feature/issues/issue-32-feature.js b/test/feature/issues/issue-32-feature.js index 82844446..af0d34ed 100644 --- a/test/feature/issues/issue-32-feature.js +++ b/test/feature/issues/issue-32-feature.js @@ -1,4 +1,4 @@ -import { Definition } from '../../../src/index.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../../helpers/testHelpers.js'; const source1 = ` diff --git a/test/feature/issues/issue-39-feature.js b/test/feature/issues/issue-39-feature.js index 490b2a9e..17b8670e 100644 --- a/test/feature/issues/issue-39-feature.js +++ b/test/feature/issues/issue-39-feature.js @@ -1,4 +1,4 @@ -import { Definition, SequenceFlow } from '../../../src/index.js'; +import { Definition, SequenceFlow } from 'bpmn-elements'; import testHelpers from '../../helpers/testHelpers.js'; const source = ` diff --git a/test/feature/issues/issue-42-feature.js b/test/feature/issues/issue-42-feature.js index 961372da..e982ffe7 100644 --- a/test/feature/issues/issue-42-feature.js +++ b/test/feature/issues/issue-42-feature.js @@ -1,4 +1,4 @@ -import { Definition } from '../../../src/index.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../../helpers/testHelpers.js'; import factory from '../../helpers/factory.js'; diff --git a/test/feature/issues/stack-overflow-feature.js b/test/feature/issues/stack-overflow-feature.js index 4fb14b2e..0837014b 100644 --- a/test/feature/issues/stack-overflow-feature.js +++ b/test/feature/issues/stack-overflow-feature.js @@ -1,4 +1,4 @@ -import { Definition } from '../../../src/index.js'; +import { Definition } from 'bpmn-elements'; import JsExtension from '../../resources/extensions/JsExtension.js'; import nock from 'nock'; import testHelpers from '../../helpers/testHelpers.js'; diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index a5c2a833..f02c0f43 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -685,9 +685,7 @@ Feature('Shaking', () => { And('the shake walk continues past the catch and reaches the end event', () => { const reachedEnd = shakeEndMessages.some((m) => m.content.sequence.some((s) => s.id === 'end')); expect(reachedEnd, 'shake.end with end in sequence').to.be.true; - const endSequence = shakeEndMessages - .map((m) => m.content.sequence.map((s) => s.id)) - .find((ids) => ids.includes('end')); + const endSequence = shakeEndMessages.map((m) => m.content.sequence.map((s) => s.id)).find((ids) => ids.includes('end')); expect(endSequence).to.include.members(['catch', 'from-catch', 'end']); }); diff --git a/test/feature/signal-feature.js b/test/feature/signal-feature.js index 2608165b..da7f3520 100644 --- a/test/feature/signal-feature.js +++ b/test/feature/signal-feature.js @@ -942,7 +942,7 @@ Feature('Signals', () => { } ); - let end, state, definition; + let state, definition; const output = {}; When('definition is ran', () => { definition = new Definition(context); @@ -1257,10 +1257,6 @@ Feature('Signals', () => { Then('activity output is set to signal message', () => { expect(output).to.have.property('namedMessageEvent').with.property('input', 1); }); - - And('execution completes', () => { - return end; - }); }); }); diff --git a/test/feature/stop-and-resume-feature.js b/test/feature/stop-and-resume-feature.js index 66c5ffe8..0316dc14 100644 --- a/test/feature/stop-and-resume-feature.js +++ b/test/feature/stop-and-resume-feature.js @@ -569,6 +569,7 @@ Feature('Stop and resume', () => { let stopped; When('run', () => { + stopped = definition.waitFor('stop'); definition.run(); }); diff --git a/test/feature/swim-lanes-feature.js b/test/feature/swim-lanes-feature.js index 4f679e9b..629328a0 100644 --- a/test/feature/swim-lanes-feature.js +++ b/test/feature/swim-lanes-feature.js @@ -1,4 +1,4 @@ -import { Definition, Process, Activity, Lane } from '../../src/index.js'; +import { Definition, Process, Activity, Lane } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; diff --git a/test/helpers/testHelpers.js b/test/helpers/testHelpers.js index c7299dd4..77f8d9d4 100644 --- a/test/helpers/testHelpers.js +++ b/test/helpers/testHelpers.js @@ -1,6 +1,6 @@ import fs from 'fs'; import Debug from 'debug'; -import * as types from '../../src/index.js'; +import * as types from 'bpmn-elements'; import BpmnModdle from 'bpmn-moddle'; import Context from '../../src/Context.js'; import Environment from '../../src/Environment.js'; diff --git a/test/io/InputOutputSpecification-test.js b/test/io/InputOutputSpecification-test.js index 3ac85d26..a084b664 100644 --- a/test/io/InputOutputSpecification-test.js +++ b/test/io/InputOutputSpecification-test.js @@ -463,7 +463,7 @@ describe('InputOutputSpecification', () => { task.run(); - let api = await wait; + const api = await wait; expect(api.content.ioSpecification).to.have.property('dataOutputs').with.length(1); expect(api.content.ioSpecification.dataOutputs[0]).that.eql({ id: 'userInput', type: 'bpmn:DataOutput', name: 'sirname' }); @@ -479,7 +479,7 @@ describe('InputOutputSpecification', () => { }, }); - api = await leave; + await leave; expect(context.environment.variables._data).to.have.property('inputFromUser', 'von Rosen'); }); @@ -669,7 +669,7 @@ describe('InputOutputSpecification', () => { task.run(); - let api = await wait; + const api = await wait; api.signal({ ioSpecification: { @@ -682,7 +682,7 @@ describe('InputOutputSpecification', () => { }, }); - api = await leave; + await leave; expect(context.environment.variables._data).to.have.property('surname', 'von Rosen'); }); diff --git a/test/process/Process-test.js b/test/process/Process-test.js index 531fa5e5..5721862f 100644 --- a/test/process/Process-test.js +++ b/test/process/Process-test.js @@ -1393,7 +1393,7 @@ describe('Process', () => { bp.run(); - let api = await wait1; + const api = await wait1; const wait2 = new Promise((resolve) => { bp.once('wait', resolve); @@ -1401,7 +1401,7 @@ describe('Process', () => { api.signal(); - api = await wait2; + await wait2; expect(count).to.equal(1); }); }); diff --git a/test/tasks/UserTask-test.js b/test/tasks/UserTask-test.js index 01058b8d..d7954665 100644 --- a/test/tasks/UserTask-test.js +++ b/test/tasks/UserTask-test.js @@ -199,7 +199,6 @@ describe('UserTask', () => { expect(executeQ.messageCount, 'execute queue').to.equal(2); - waiting = task.waitFor('wait'); taskApi.signal({ iteration: 2 }); const left = await leave; @@ -356,7 +355,7 @@ describe('UserTask', () => { it('keeps execute wait state until signaled', async () => { const task = context.getActivityById('task'); - let waiting = task.waitFor('wait'); + const waiting = task.waitFor('wait'); const left = task.waitFor('leave'); task.activate(); task.run(); @@ -366,8 +365,6 @@ describe('UserTask', () => { expect(task.broker.getQueue('run-q').messageCount, 'run queue').to.equal(1); expect(task.broker.getQueue('execute-q').messageCount, 'execute queue').to.be.above(1); - waiting = task.waitFor('wait'); - const childExecutions = task.getApi().getExecuting(); expect(childExecutions.length).to.equal(3); diff --git a/tsconfig.json b/tsconfig.json index b39c6871..98925029 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,20 @@ { "include": ["src/**/*", "types"], + "exclude": ["types/augmentations.d.ts"], "compilerOptions": { "emitDeclarationOnly": true, "sourceMap": false, "rootDir": "src", - "lib": ["es2017"], - "target": "es2017", + "lib": ["es2020"], + "target": "es2020", "outDir": "./tmp/ignore", "declaration": true, "noEmitOnError": true, "noErrorTruncation": true, "allowJs": true, "checkJs": false, - "module": "esnext", - "moduleResolution": "node", + "module": "nodenext", + "moduleResolution": "nodenext", "resolveJsonModule": false, "allowSyntheticDefaultImports": true, "strict": true, @@ -21,9 +22,10 @@ "noImplicitThis": true, "noUnusedLocals": true, "noUnusedParameters": true, - "typeRoots": ["./node_modules/@types"], + "types": ["node"], "paths": { - "types": ["./types/types.js"] + "types": ["./types/types.js"], + "src/*": ["./src/*"] } } } diff --git a/tsconfig.tests.json b/tsconfig.tests.json new file mode 100644 index 00000000..8591c495 --- /dev/null +++ b/tsconfig.tests.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*", "test/**/*", "types"], + "compilerOptions": { + "rootDir": ".", + "noEmit": true, + "emitDeclarationOnly": false, + "declaration": false + } +} diff --git a/types/augmentations.d.ts b/types/augmentations.d.ts new file mode 100644 index 00000000..9fc1b57f --- /dev/null +++ b/types/augmentations.d.ts @@ -0,0 +1,90 @@ +// Augmentations for the dts-buddy-generated bundle in types/index.d.ts. +// These interfaces add the prototype getters defined via Object.defineProperties +// in src/, which TypeScript cannot pick up from constructor functions. +// The build script (scripts/build-types.js) appends this file to types/index.d.ts. + +declare module 'bpmn-elements' { + interface Activity { + get counters(): { taken: number; discarded: number }; + get execution(): import('types').ActivityExecution | undefined; + get executionId(): string | undefined; + get extensions(): import('types').IExtension; + get bpmnIo(): import('types').IExtension | undefined; + get formatter(): any; + get isRunning(): boolean; + get outbound(): import('types').SequenceFlow[]; + get inbound(): import('types').SequenceFlow[]; + get isEnd(): boolean; + get isStart(): boolean; + get isSubProcess(): boolean; + get isTransaction(): boolean; + get isMultiInstance(): boolean; + get isThrowing(): boolean; + get isCatching(): boolean; + get isForCompensation(): boolean; + get isParallelJoin(): boolean; + get triggeredByEvent(): boolean; + get attachedTo(): import('types').Activity | null; + get lane(): import('types').Lane | undefined; + get eventDefinitions(): any[]; + /** Parent element process or sub process reference */ + get parentElement(): import('types').Process | import('types').Activity; + get initialized(): boolean; + } + + interface Process { + get counters(): { completed: number; discarded: number }; + get lanes(): import('types').Lane[] | undefined; + get extensions(): import('types').IExtension | undefined; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string | undefined; + get execution(): import('types').ProcessExecution | undefined; + get status(): string | undefined; + get activityStatus(): string; + } + + interface Definition { + get counters(): { completed: number; discarded: number }; + get execution(): import('types').DefinitionExecution | undefined; + get executionId(): string | undefined; + get isRunning(): boolean; + get status(): string | undefined; + get stopped(): boolean; + get activityStatus(): string; + } + + interface Environment { + get variables(): Record; + get services(): Record; + set services(value: Record); + } + + interface ContextInstance { + /** Process or sub-process activity that owns this context */ + get owner(): import('types').Process | import('types').Activity | undefined; + } + + interface ProcessExecution { + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + + interface DefinitionExecution { + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get processes(): import('types').Process[]; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + + interface ActivityExecution { + get completed(): boolean; + } +} diff --git a/types/index.d.ts b/types/index.d.ts index fd4905fe..fe21f1c9 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,101 +1,6750 @@ -export * from './types.js'; -import { - Association, - MessageFlow, - SequenceFlow, - IActivityBehaviour, - ActivityBehaviour, - EventDefinition, - MessageElement, - ConditionalEventDefinition, - TimerEventDefinition, -} from './types.js'; - declare module 'bpmn-elements' { - export var BoundaryEvent: typeof ActivityBehaviour; - export var CallActivity: typeof ActivityBehaviour; - export var Dummy: typeof ActivityBehaviour; - export var TextAnnotation: typeof Dummy; - export var Group: typeof Dummy; - export var Category: typeof Dummy; - export var EndEvent: typeof ActivityBehaviour; - export var EventBasedGateway: typeof ActivityBehaviour; - export var ExclusiveGateway: typeof ActivityBehaviour; - export var InclusiveGateway: typeof ActivityBehaviour; - export var IntermediateCatchEvent: typeof ActivityBehaviour; - export var IntermediateThrowEvent: typeof ActivityBehaviour; - export var ParallelGateway: typeof ActivityBehaviour; - export var ReceiveTask: typeof ActivityBehaviour; - export var ScriptTask: typeof ActivityBehaviour; - export var ServiceTask: typeof ActivityBehaviour; - export var SendTask: typeof ServiceTask; - export var BusinessRuleTask: typeof ServiceTask; - export var SignalTask: typeof ActivityBehaviour; - export var ManualTask: typeof SignalTask; - export var UserTask: typeof SignalTask; - export var StartEvent: typeof ActivityBehaviour; - export var SubProcess: typeof ActivityBehaviour; - export var Task: typeof ActivityBehaviour; - export var Transaction: typeof ActivityBehaviour; - - export var CancelEventDefinition: EventDefinition; - export var CompensateEventDefinition: EventDefinition; - export var ConditionalEventDefinition: EventDefinition; - export var ErrorEventDefinition: EventDefinition; - export var EscalationEventDefinition: EventDefinition; - export var LinkEventDefinition: EventDefinition; - export var MessageEventDefinition: EventDefinition; - export var SignalEventDefinition: EventDefinition; - export var TerminateEventDefinition: EventDefinition; - export var TimerEventDefinition: TimerEventDefinition; - - export class Message extends MessageElement {} - export class Signal extends MessageElement {} - export class Escalation extends MessageElement {} + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + export function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + export class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger; + environment: Environment_1; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): SequenceFlow_1 | undefined; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + export function BpmnError(errorDef: any, context: any): { + id: any; + type: any; + name: any; + errorCode: any; + resolve: (executionMessage: any, error: any) => { + id: any; + type: any; + messageType: string; + name: any; + code: any; + }; + }; + /** + * Build a runtime Context from a parsed BPMN definition. + * @param environment Existing environment to clone; a fresh one is created when omitted + */ + export function Context(definitionContext: import("moddle-context-serializer").SerializableContext, environment?: Environment_1): ContextInstance_1; + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + function ContextInstance_1(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment_1, owner?: Process_1 | Activity): void; + class ContextInstance_1 { + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment_1, owner?: Process_1 | Activity); + id: string; + name: string; + type: string; + sid: string; + definitionContext: import("moddle-context-serializer").SerializableContext; + environment: Environment_1; + extensionsMapper: ExtensionsMapper; + refs: Map>; + get owner(): Activity | Process_1 | undefined; + /** + * Get or create the activity instance for the given id. + * */ + getActivityById(activityId: string): any; + /** + * Return the cached activity instance, instantiating it the first time it is referenced. + * */ + upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + /** + * Get or create the sequence flow instance for the given id. + * */ + getSequenceFlowById(sequenceFlowId: string): any; + + getInboundSequenceFlows(activityId: string): any[]; + + getOutboundSequenceFlows(activityId: string): any[]; + + getInboundAssociations(activityId: string): any[]; + + getOutboundAssociations(activityId: string): any[]; + /** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getActivities(scopeId?: string): any[]; + /** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getSequenceFlows(scopeId?: string): any[]; + /** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * */ + upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * @param scopeId Process or sub-process id + */ + getAssociations(scopeId?: string): any[]; + + upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * + */ + clone(newEnvironment?: Environment_1, newOwner?: Process_1 | Activity): ContextInstance_1; + /** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * */ + getProcessById(processId: string): any; + /** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * */ + getNewProcessById(processId: string): any; + /** + * Get every process in the definition. + */ + getProcesses(): any[]; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any[]; + /** + * Get message flows that originate from the given process id. + * @param sourceId Source process id + */ + getMessageFlows(sourceId: string): any[]; + /** + * Get or create a data object instance for the given reference id. + * */ + getDataObjectById(referenceId: string): any; + /** + * Get or create a data store instance for the given reference id. + * */ + getDataStoreById(referenceId: string): any; + /** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param scopeId Process or sub-process id + */ + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + /** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * */ + loadExtensions(activity: ElementBase): Extensions | undefined; + /** + * Resolve the parent process or sub-process activity that owns the given activity. + * */ + getActivityParentById(activityId: string): any; + + private [K_OWNER]; + } + function ExtensionsMapper(context: any): void; + class ExtensionsMapper { + constructor(context: any); + context: any; + get(activity: any): Extensions; + + _getExtensions(): any[]; + } + function Extensions(activity: any, context: any, extensions: any): void; + class Extensions { + constructor(activity: any, context: any, extensions: any); + extensions: any[]; + get count(): number; + activate(message: any): void; + deactivate(message: any): void; + + private [K_ACTIVATED]; + } + const K_OWNER: unique symbol; + export function DataObject(dataObjectDef: any, { environment }: { + environment: any; + }): void; + export class DataObject { + constructor(dataObjectDef: any, { environment }: { + environment: any; + }); + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + environment: any; + read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; + write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + _createContent(value: any): { + id: any; + type: any; + name: any; + value: any; + }; + } + export function DataStore(dataStoreDef: any, { environment }: { + environment: any; + }): void; + export class DataStore { + constructor(dataStoreDef: any, { environment }: { + environment: any; + }); + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + environment: any; + read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; + write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + _createContent(value: any): { + id: any; + type: any; + name: any; + value: any; + }; + } + export function DataStoreReference(dataObjectDef: any, { environment }: { + environment: any; + }): void; + export class DataStoreReference { + constructor(dataObjectDef: any, { environment }: { + environment: any; + }); + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + environment: any; + read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; + write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + _createContent(value: any): { + id: any; + type: any; + name: any; + value: any; + }; + } + /** + * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and + * mediates inter-process messaging. + * @param options When provided, environment is cloned and settings merged + */ + export function Definition(context: ContextInstance, options?: EnvironmentOptions): Definition; + export class Definition { + /** + * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and + * mediates inter-process messaging. + * @param options When provided, environment is cloned and settings merged + */ + constructor(context: ContextInstance, options?: EnvironmentOptions); + id: string | undefined; + type: string | undefined; + name: string | undefined; + environment: Environment_1 | undefined; + context: ContextInstance | undefined; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emit: any; + emitFatal: any; + logger: ILogger | undefined; + /** + * Start running the definition. Accepts run options, a callback, or both. + * The callback fires once on leave, stop, or error. + * @throws {Error} when already running and no callback is supplied + */ + run(optionsOrCallback?: Record | runCallback, optionalCallback?: runCallback): this; + /** + * Resume after recover by republishing the last run message. The callback fires once on + * leave, stop, or error. + * */ + resume(callback?: runCallback): this; + /** + * Snapshot definition state for recover. + */ + getState(): any; + /** + * Restore definition state captured by getState. + * @throws {Error} when called on a running definition + */ + recover(state?: DefinitionState): this; + /** + * Walk activity graphs to discover sequences. Limited to the activity's owning process + * when startId is given, otherwise all processes are shaken. + * + */ + shake(startId?: string): {} | undefined; + + _shakeProcess(shakeBp: any, startId: any): any; + /** + * Get every process in the definition. + */ + getProcesses(): any; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any; + /** + * Get processes that are currently running. + */ + getRunningProcesses(): any; + + getProcessById(processId: string): any; + /** + * Find an activity by id across all processes in the definition. + * */ + getActivityById(childId: string): any; + /** + * Lookup any element (activity, flow, etc.) in the parsed definition by id. + * */ + getElementById(elementId: string): any; + /** + * List currently postponed activities as Api wrappers. + * + */ + getPostponed(...args: any[]): any; + /** + * Resolve a Definition Api wrapper, preferring the running execution if any. + * @throws {Error} when the definition is not running and no message is given + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Send a delegated signal to the running definition. + * + */ + signal(message?: signalMessage): any; + /** + * Cancel a running activity inside the definition by delegated api message. + * + */ + cancelActivity(message?: signalMessage): any; + /** + * Deliver a message to a referenced element. Resolves the message reference when the + * target element exposes a `resolve` method (e.g. message-, signal-, escalation events). + * */ + sendMessage(message: { + id?: string; + [x: string]: any; + }): any; + /** + * Stop the definition if running. + */ + stop(): void; + + _activateRunConsumers(): void; + + _deactivateRunConsumers(): void; + + _createMessage(override: any): any; + + _onRunMessage(routingKey: any, message: any): any; + + _onResumeMessage(message: any): any; + + _onExecutionMessage(routingKey: any, message: any): void; + + _onApiMessage(routingKey: any, message: any): void; + + _publishEvent(action: any, content: any, msgOpts: any): void; + + _onStop(): void; + + _onBrokerReturnFn(message: any): void; + + _reset(): void; + + _debug(msg: any): void; + + private [K_COUNTERS]; + + private [K_STOPPED]; + + private [K_EXECUTION]; + + private [K_MESSAGE_HANDLERS]; + + private [K_STATUS]; + + private [K_CONSUMING]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + export function Category(activityDef: any): { + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + placeholder: boolean; + }; + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + export function Environment(options?: EnvironmentOptions): void; + export class Environment { + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + constructor(options?: EnvironmentOptions); + options: {}; + expressions: IExpressions; + extensions: Record | undefined; + output: any; + scripts: IScripts | Scripts; + timers: ITimers | Timers; + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + Logger: LoggerFactory | typeof DummyLogger; + /** + * Snapshot environment state for recover. + */ + getState(): { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + /** + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. + * */ + recover(state?: EnvironmentState): this; + /** + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. + * + */ + clone(overrideOptions?: EnvironmentOptions): any; + /** + * Merge variables into the environment. Non-objects are ignored. + * */ + assignVariables(newVars: Record): void; + /** + * Merge settings into the environment. Non-objects are ignored. + * */ + assignSettings(newSettings: EnvironmentSettings): this; + /** + * Resolve a registered script by language and identifier. + * */ + getScript(...args: any[]): void | Script; + /** + * Register a script for an activity, delegating to the configured scripts engine. + * */ + registerScript(...args: any[]): void | Script; + /** + * Lookup a registered service by name. + * */ + getServiceByName(serviceName: string): CallableFunction; + /** + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param message Element message merged onto the resolution scope + * + */ + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + /** + * Register a service callable by name. + * */ + addService(name: string, fn: CallableFunction): void; + + private [K_SERVICES]; + + private [K_VARIABLES]; + } + function DummyLogger(): { + debug: () => void; + error: () => void; + warn: () => void; + }; + const K_SERVICES: unique symbol; + const K_VARIABLES: unique symbol; + export function Escalation(signalDef: any, context: any): { + id: any; + type: any; + name: any; + parent: any; + resolve: (executionMessage: any) => { + id: any; + type: any; + messageType: string; + name: any; + parent: any; + }; + }; + export function InputOutputSpecification(activity: any, ioSpecificationDef: any, context: any): void; + export class InputOutputSpecification { + constructor(activity: any, ioSpecificationDef: any, context: any); + id: any; + type: any; + behaviour: any; + activity: any; + broker: any; + context: any; + activate(message: any): void; + deactivate(): void; + _onActivityEvent(routingKey: any, message: any): any; + _onFormatEnter(): any; + _onFormatComplete(message: any): any; + _getDataOutputs(dataOutputs: any): any; + + private [K_CONSUMING]; + } + export function Message(messageDef: any, context: any): { + id: any; + type: any; + name: any; + parent: any; + resolve: (executionMessage: any) => any; + }; + /** + * Process lane. Wraps a `` definition and points back to its owning process; + * activities reference their lane through `Activity.lane`. + * */ + export function Lane(process: Process_1, laneDefinition: import("moddle-context-serializer").SerializableElement): void; + export class Lane { + /** + * Process lane. Wraps a `` definition and points back to its owning process; + * activities reference their lane through `Activity.lane`. + * */ + constructor(process: Process_1, laneDefinition: import("moddle-context-serializer").SerializableElement); + id: string | undefined; + type: string | undefined; + name: any; + parent: { + id: string; + type: string; + }; + behaviour: { + [x: string]: any; + }; + environment: Environment_1; + broker: ElementBroker; + context: ContextInstance; + logger: ILogger; + get process(): Process_1; + + private [K_PROCESS]; + } + const K_PROCESS: unique symbol; + export function MultiInstanceLoopCharacteristics(activity: any, loopCharacteristics: any): void; + export class MultiInstanceLoopCharacteristics { + constructor(activity: any, loopCharacteristics: any); + activity: any; + loopCharacteristics: any; + type: any; + isSequential: any; + collection: any; + loopCardinality: any; + loopType: string | undefined; + elementVariable: any; + characteristics: any; + execution: any; + execute(executeMessage: any): any; + } + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + export function Process(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + export class Process { + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + isExecutable: any; + environment: Environment_1; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + logger: ILogger; + /** + * Allocate an executionId and emit init event without starting the run. + * @param useAsExecutionId Override for the generated execution id + */ + init(useAsExecutionId?: string): void; + /** + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param runContent Optional content merged into the run message + * @throws {Error} when the process is already running + */ + run(runContent?: Record): void; + /** + * Resume after recover by republishing the last run message. + * @throws {Error} when called on a running process + */ + resume(): this; + /** + * Snapshot process state for recover. + */ + getState(): { + id: string | undefined; + type: string; + executionId: any; + environment: EnvironmentState; + status: any; + stopped: any; + counters: any; + broker: { + exchanges: { + bindings?: { + id: string; + options: { + priority: number; + }; + queueName: string; + pattern: string; + }[] | undefined; + deliveryQueue?: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + } | undefined; + name: string; + type: import("smqp").exchangeType; + options: { + [x: string]: any; + durable?: boolean; + autoDelete?: boolean; + }; + }[] | undefined; + queues: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + }[] | undefined; + } | undefined; + execution: any; + }; + /** + * Restore process state captured by getState. + * @throws {Error} when called on a running process + */ + recover(state?: ProcessState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. + * + */ + shake(startId?: string): any; + /** + * Stop the process if running. + */ + stop(): void; + /** + * Resolve a Process Api wrapper, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Send a delegated signal to the running process. + * + */ + signal(message?: signalMessage): any; + /** + * Cancel a running activity inside the process by delegated api message. + * + */ + cancelActivity(message?: signalMessage): any; + + _activateRunConsumers(): void; + + _deactivateRunConsumers(): void; + + _onRunMessage(routingKey: any, message: any): any; + + _onResumeMessage(message: any): any; + + _onExecutionMessage(routingKey: any, message: any): void; + + _publishEvent(state: any, content: any): void; + /** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. + * */ + sendMessage(message: ElementBrokerMessage): void; + + getActivityById(childId: string): any; + /** + * Get every activity in the process scope. + */ + getActivities(): any; + /** + * Get start activities, optionally filtered by referenced event definition. + * + */ + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any; + + getLaneById(laneId: string): any; + /** + * List currently postponed activities as Api wrappers. + * + */ + getPostponed(...args: any[]): any; + + _onApiMessage(routingKey: any, message: any): void; + + _onStop(): void; + + _createMessage(override: any): any; + + _debug(msg: any): void; + + private [K_COUNTERS]; + + private [K_CONSUMING]; + + private [K_EXECUTION]; + + private [K_STATUS]; + + private [K_STOPPED]; + + private [K_MESSAGE_HANDLERS]; + + private [K_LANES]; + + private [K_EXTENSIONS]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_LANES: unique symbol; + export function Properties(activity: any, propertiesDef: any, context: any): void; + export class Properties { + constructor(activity: any, propertiesDef: any, context: any); + activity: any; + broker: any; + activate(message: any): void; + deactivate(): void; + _onActivityEvent(routingKey: any, message: any): any; + _formatOnEnter(message: any): any; + _formatOnComplete(message: any): any; + _getProperties(message: any, values: any): {}; + [K_PROPERTIES]: { + properties: Set; + dataInputObjects: Set; + dataOutputObjects: Set; + }; + + private [K_CONSUMING]; + } + const K_PROPERTIES: unique symbol; + export function ServiceImplementation(activity: any): void; + export class ServiceImplementation { + constructor(activity: any); + type: string; + implementation: any; + activity: any; + execute(executionMessage: any, callback: any): any; + } + export function Signal(signalDef: any, context: any): { + id: any; + type: any; + name: any; + parent: any; + resolve: (executionMessage: any) => any; + }; + export function StandardLoopCharacteristics(activity: any, loopCharacteristics: any): MultiInstanceLoopCharacteristics; + export function Timers(options: any): void; + export class Timers { + constructor(options: any); + count: number; + options: any; + setTimeout: any; + clearTimeout: any; + get executing(): any[]; + register(owner: any): RegisteredTimers; + _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; + _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; + + private [K_EXECUTING]; + } + function RegisteredTimers(timersApi: any, owner: any): void; + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + + private [K_TIMER_API]; + } + function Timer_1(owner: any, timerId: any, callback: any, delay: any, args: any): void; + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + const K_EXECUTING: unique symbol; + const K_TIMER_API: unique symbol; + export class ActivityError extends Error { + constructor(description: any, sourceMessage: any, inner: any); + type: string; + name: any; + description: any; + source: { + fields: any; + content: any; + properties: any; + } | undefined; + inner: any; + code: any; + } + export class RunError extends ActivityError { + constructor(...args: any[]); + } + export function CallActivity(activityDef: any, context: any): Activity; + export function ReceiveTask(activityDef: any, context: any): Activity; + export function ScriptTask(activityDef: any, context: any): Activity; + export function ServiceTask(activityDef: any, context: any): Activity; + export function SignalTask(activityDef: any, context: any): Activity; + export function SubProcess(activityDef: any, context: any): Activity; + export function Task(activityDef: any, context: any): Activity; + export function Transaction(activityDef: any, context: any): Activity; + /** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + export function Association(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; + export class Association { + /** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isAssociation: boolean; + environment: Environment_1; + logger: ILogger; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + get counters(): { + take: number; + discard: number; + }; + /** + * Take the association and publish association.take. + * + */ + take(content?: Record): boolean; + /** + * Discard the association and publish association.discard. + * + */ + discard(content?: Record): boolean; + /** + * Snapshot association state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): AssociationState | undefined; + /** + * Restore association state captured by getState. + * */ + recover(state: AssociationState): void; + /** + * Resolve an association-scoped Api wrapper. + * + */ + getApi(message?: ElementBrokerMessage): Api_1; + /** + * Stop the association's broker. + */ + stop(): void; + + _publishEvent(action: any, content: any): void; + + _createMessageContent(override: any): any; + + private [K_COUNTERS]; + } + /** + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + export function MessageFlow(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + export class MessageFlow { + /** + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + source: any; + target: any; + behaviour: Record; + environment: Environment_1; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + emit: any; + waitFor: any; + logger: ILogger; + get counters(): { + messages: number; + }; + /** + * Snapshot message-flow state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): MessageFlowState | undefined; + /** + * Restore message-flow state captured by getState. + * */ + recover(state: MessageFlowState): void; + /** + * Resolve a message-scoped Api wrapper. + * + */ + getApi(message?: ElementBrokerMessage): Api_1; + /** + * Subscribe to the source element's message and end events to bridge the message across. + */ + activate(): void; + /** + * Cancel the source element subscriptions added by activate. + */ + deactivate(): void; + + _onSourceEnd({ content }: { + content: any; + }): void; + + _createMessageContent(message: any): { + id: string | undefined; + type: string; + name: any; + source: any; + target: any; + parent: any; + message: any; + }; + + private [K_COUNTERS]; + + private [K_SOURCE_ELEMENT]; + } + const K_SOURCE_ELEMENT: unique symbol; + /** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + export function SequenceFlow(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; + export class SequenceFlow { + /** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isDefault: any; + isSequenceFlow: boolean; + environment: Environment_1; + logger: ILogger; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + get counters(): { + take: number; + discard: number; + looped: number; + }; + /** + * Take the flow and publish flow.take. + * + */ + take(content?: Record): boolean; + /** + * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits + * flow.looped instead when the target id is already in the sequence. + * + */ + discard(content?: Record): void; + /** + * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` + * is set. + * */ + getState(): SequenceFlowState | undefined; + /** + * Restore flow state captured by getState. + * */ + recover(state: SequenceFlowState): void; + /** + * Resolve a Flow Api wrapper. + * + */ + getApi(message?: ElementBrokerMessage): Api_1; + /** + * Stop the flow's broker. + */ + stop(): void; + /** + * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop + * when the target was already visited, otherwise flow.shake. + * */ + shake(message: ElementBrokerMessage): any; + /** + * Resolve the flow's condition (script or expression). Returns null when no condition is set. + * Emits a fatal error when the script language is missing or unsupported. + * */ + getCondition(): ISequenceFlowCondition | null; + /** + * Build a flow event message body, optionally merging override content. + * + */ + createMessage(override?: Record): { + id: string | undefined; + type: string; + name: any; + sourceId: any; + targetId: any; + isSequenceFlow: boolean; + isDefault: any; + parent: any; + }; + /** + * Evaluate the flow's condition for the source activity message. Default flows are always taken. + * @param fromMessage Source activity message + * @param callback Callback with truthy result if flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; + + _publishEvent(action: any, content: any): void; + + private [K_COUNTERS]; + } + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment_1; + get context(): ContextInstance; + get logger(): ILogger; + } + + class Element extends ElementBase { + get broker(): ElementBroker; + stop(): void; + resume(): void; + getApi(message?: ElementBrokerMessage): Api; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; + waitFor(eventName: string, options?: any): Promise>; + } + + interface Api extends ElementBrokerMessage { + get id(): string; + get type(): string; + get name(): string; + get executionId(): string; + get environment(): Environment_1; + get broker(): ElementBroker; + get owner(): T; + cancel(message?: signalMessage, options?: any): void; + discard(): void; + fail(error: Error): void; + signal(message?: signalMessage, options?: any): void; + stop(): void; + resolveExpression(expression: string): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + getPostponed(...args: any[]): any[]; + createMessage(content?: Record): any; + getExecuting(): Api[]; + } + + class Environment_1 { + constructor(options?: EnvironmentOptions); + options: Record; + expressions: IExpressions; + extensions: Record; + scripts: IScripts; + timers: ITimers; + Logger: LoggerFactory; + get settings(): EnvironmentSettings; + get variables(): Record; + get output(): Record; + set services(arg: any); + get services(): any; + getState(): EnvironmentState; + recover(state?: EnvironmentState): Environment_1; + clone(overrideOptions?: EnvironmentOptions): Environment_1; + assignVariables(newVars: Record): void; + assignSettings(newSettings: Record): Environment_1; + registerScript(activity: any): Script; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + getServiceByName(serviceName: string): CallableFunction; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + addService(name: string, fn: CallableFunction): void; + } + class ContextInstance { + constructor(definitionContext: SerializableContext, environment?: Environment_1); + get id(): string; + get name(): string; + get type(): string; + /** Unique context instance id */ + get sid(): string; + get definitionContext(): SerializableContext; + get environment(): Environment_1; + /** Context owner, Process or SubProcess activity */ + get owner(): Process_1 | Activity | undefined; + getActivityById(activityId: string): T; + getSequenceFlowById(sequenceFlowId: string): SequenceFlow_1; + getInboundSequenceFlows(activityId: string): SequenceFlow_1[]; + getOutboundSequenceFlows(activityId: string): SequenceFlow_1[]; + getInboundAssociations(activityId: string): Association_1[]; + getOutboundAssociations(activityId: string): Association_1[]; + getActivities(scopeId?: string): ElementBase[]; + getSequenceFlows(scopeId?: string): SequenceFlow_1[]; + getAssociations(scopeId?: string): Association_1[]; + clone(newEnvironment?: Environment_1): ContextInstance; + getProcessById(processId: string): Process_1; + getNewProcessById(processId: string): Process_1; + getProcesses(): Process_1[]; + getExecutableProcesses(): Process_1[]; + getMessageFlows(sourceId: string): MessageFlow_1[]; + getDataObjectById(referenceId: string): any; + getDataStoreById(referenceId: string): any; + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; + loadExtensions(activity: ElementBase): IExtension; + } + + class Process_1 extends Element { + constructor(processDef: SerializableElement, context: ContextInstance); + get isExecutable(): boolean; + get counters(): completedCounters; + get lanes(): Lane_1[] | undefined; + get extensions(): IExtension; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string; + get execution(): ProcessExecution; + get status(): ProcessRunStatus | undefined; + get activityStatus(): ActivityStatus; + init(useAsExecutionId?: string): void; + run(runContent?: Record): void; + getState(): ProcessState; + recover(state?: ProcessState): Process_1; + shake(startId?: string): void; + signal(message: any): any; + cancelActivity(message: any): any; + sendMessage(message: any): void; + getActivityById(childId: string): T; + getActivities(): Activity[]; + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + getSequenceFlows(): SequenceFlow_1[]; + getLaneById(laneId: string): Lane_1 | undefined; + getPostponed(filterFn: filterPostponed): Api[]; + } + + interface ProcessExecution { + get isSubProcess(): boolean; + get broker(): Broker; + get environment(): Environment_1; + get context(): ContextInstance; + get executionId(): string; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): ActivityStatus; + execute(executeMessage: ElementBrokerMessage): void; + getPostponed(filterFn: filterPostponed): Api[]; + getActivities(): Activity[]; + getActivityById(activityId: string): T; + getSequenceFlows(): SequenceFlow_1[]; + getApi(message?: ElementBrokerMessage): Api; + } + + class Lane_1 extends ElementBase { + constructor(process: Process_1, laneDefinition: SerializableElement); + /** Process broker */ + get broker(): Broker; + get process(): Process_1; + } + + class SequenceFlow_1 extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isDefault(): boolean; + get isSequenceFlow(): boolean; + get counters(): { take: number; discard: number; looped: number }; + take(content?: any): boolean; + discard(content?: any): void; + shake(message: any): number; + getCondition(): ISequenceFlowCondition | null; + createMessage(override?: any): object; + /** + * Evaluate flow + * Executes condition if any, default flow is + * @param fromMessage Activity message + * @param callback Callback with evaluation result, if truthy flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + getState(): SequenceFlowState | undefined; + } + + class MessageFlow_1 extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get source(): MessageFlowReference; + get target(): MessageFlowReference; + get counters(): { messages: number }; + activate(): void; + deactivate(): void; + getState(): MessageFlowState | undefined; + } + + class Association_1 extends Element { + constructor(associationDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isAssociation(): boolean; + get counters(): { take: number; discard: number }; + take(content?: any): boolean; + discard(content?: any): boolean; + getState(): AssociationState | undefined; + } + interface ElementBroker extends Broker { + get owner(): T; + } + + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + } + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + type filterPostponed = (elementApi: any) => boolean; + + enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', + } + + /** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ + enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', + } + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + interface DefinitionExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + processes: ProcessState[]; + } + + interface DefinitionState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: DefinitionExecutionState; + } + + type runCallback = (err: Error, definitionApi: any) => void; + + interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; + } + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + const K_ACTIVATED: unique symbol; + const K_COMPLETED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXECUTION: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_MESSAGE_Q: unique symbol; + const K_REFERENCE_ELEMENT: unique symbol; + const K_REFERENCE_INFO: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_STATUS: unique symbol; + const K_STOPPED: unique symbol; + export function BoundaryEvent(activityDef: any, context: any): Activity; + export function EndEvent(activityDef: any, context: any): Activity; + export function IntermediateCatchEvent(activityDef: any, context: any): Activity; + export function IntermediateThrowEvent(activityDef: any, context: any): Activity; + export function StartEvent(activityDef: any, context: any): Activity; + export function CancelEventDefinition(activity: any, eventDefinition: any): void; + export class CancelEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + environment: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(_: any, message: any): any; + _complete(output: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _debug(msg: any): void; + + private [K_EXECUTE_MESSAGE]; + + private [K_COMPLETED]; + } + export function CompensateEventDefinition(activity: any, eventDefinition: any, context: any): void; + export class CompensateEventDefinition { + constructor(activity: any, eventDefinition: any, context: any); + id: any; + type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + _onCollect(routingKey: any, message: any): any; + _onCompensateApiMessage(routingKey: any, message: any): any; + _compensate(): any; + _onCollected(routingKey: any, message: any): any; + _onDiscardApiMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stopCollect(): void; + _stop(): void; + _debug(msg: any): void; + + private [K_COMPLETED]; + + private [K_ASSOCIATIONS]; + + private [K_MESSAGE_Q]; + + private [K_COMPENSATE_Q]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ASSOCIATIONS: unique symbol; + const K_COMPENSATE_Q: unique symbol; + export function ConditionalEventDefinition(activity: any, eventDefinition: any, _context: any, index: any): void; + export class ConditionalEventDefinition { + constructor(activity: any, eventDefinition: any, _context: any, index: any); + id: any; + type: any; + behaviour: any; + activity: any; + environment: any; + broker: any; + logger: any; + condition: ScriptCondition | ExpressionCondition | null; + get executionId(): any; + execute(executeMessage: any): void; + _setup(executeMessage: any): void; + /** + * Evaluate condition + * */ + evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; + /** + * Handle evaluate result or error + * @param err Condition evaluation error + * @param result Result from evaluated condition, completes execution if truthy + */ + evaluateCallback(err: Error | null, result: any): any; + /** + * Get condition + * @param index Eventdefinition sequence number, used to name registered script + * */ + getCondition(index: number): ExpressionCondition | ScriptCondition | null; + _onDelegateApiMessage(routingKey: any, message: any): void; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _debug(msg: any): void; + + private [K_EXECUTE_MESSAGE]; + } + export function ErrorEventDefinition(activity: any, eventDefinition: any): void; + export class ErrorEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + environment: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onErrorMessage(routingKey: any, message: any): any; + _onThrowApiMessage(routingKey: any, message: any): any; + _catchError(routingKey: any, message: any, error: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export function EscalationEventDefinition(activity: any, eventDefinition: any): void; + export class EscalationEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + const K_REFERENCE: unique symbol; + export function LinkEventDefinition(activity: any, eventDefinition: any): void; + export class LinkEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: { + id: any; + linkName: any; + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + _onLinkApiMessage(_: any, message: any): void; + _onShakeMessage(_: any, message: any): void; + + private [K_EXECUTE_MESSAGE]; + } + export function MessageEventDefinition(activity: any, eventDefinition: any): void; + export class MessageEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): void; + _onApiMessage(routingKey: any, message: any): any; + _complete(verb: any, output: any, options: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export function SignalEventDefinition(activity: any, eventDefinition: any): void; + export class SignalEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _complete(output: any, options: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export function TerminateEventDefinition(activity: any, eventDefinition: any): void; + export class TerminateEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + activity: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + } + export function TimerEventDefinition(activity: any, eventDefinition: any): void; + export class TimerEventDefinition { + constructor(activity: any, eventDefinition: any); + type: any; + activity: any; + environment: any; + eventDefinition: any; + timeDuration: any; + timeCycle: any; + timeDate: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + startedAt: Date | undefined; + stop(): void; + _completed(completeContent: any, options: any): void; + _onDelegatedApiMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + parse(timerType: any, value: any): { + expireAt: Date | undefined; + repeat: number | undefined; + delay: number | undefined; + }; + _getTimers(executeMessage: any): { + expireAt?: Date | undefined; + }; + _debug(msg: any): void; + + private [K_STOPPED]; + + private [K_TIMER]; + [K_TIMER_CONTENT]: any; + } + const K_TIMER: unique symbol; + const K_TIMER_CONTENT: unique symbol; + function Scripts(): void; + class Scripts { + getScript(): void; + register(): void; + } + export function EventBasedGateway(activityDef: any, context: any): Activity; + export function ExclusiveGateway(activityDef: any, context: any): Activity; + export function InclusiveGateway(activityDef: any, context: any): Activity; + export function ParallelGateway(activityDef: any, context: any): Activity; + export class ParallelGateway { + constructor(activityDef: any, context: any); + id: string | undefined; + } + /** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param sourceMessage Cloned to back the api + * @param environment Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing + */ + function Api_1(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment_1): void; + class Api_1 { + /** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param sourceMessage Cloned to back the api + * @param environment Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing + */ + constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment_1); + id: any; + type: any; + name: any; + executionId: any; + environment: any; + content: any; + fields: any; + messageProperties: any; + broker: any; + owner: any; + messagePrefix: string; + /** + * Send a cancel api message. + * + */ + cancel(message?: signalMessage, options?: any): void; + /** + * Send a discard api message. + */ + discard(): void; + /** + * Send an error api message that fails the activity. + * */ + fail(error: Error): void; + /** + * Send a signal api message. + * + */ + signal(message?: signalMessage, options?: any): void; + /** + * Send a stop api message. + */ + stop(): void; + /** + * Resolve an expression with the api message as scope and the broker owner as context. + * */ + resolveExpression(expression: string): any; + /** + * Publish a custom api message to the broker. + * @param action Routing key suffix, e.g. `signal`, `cancel` + * @param content Merged into the message content + * + */ + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + /** + * List currently postponed activities, falling back to a sub-process execution when applicable. + * + */ + getPostponed(...args: any[]): any; + /** + * Build a message body by merging the given content onto the source content. + * + */ + createMessage(content?: Record): any; + } + /** + * Script condition + * */ + function ScriptCondition(owner: ElementBase, script: any, language: string): void; + class ScriptCondition { + /** + * Script condition + * */ + constructor(owner: ElementBase, script: any, language: string); + type: string; + language: string; + _owner: ElementBase; + _script: any; + /** + * Execute + * */ + execute(message: any, callback: CallableFunction): any; + } + /** + * Expression condition + * */ + function ExpressionCondition(owner: ElementBase, expression: string): void; + class ExpressionCondition { + /** + * Expression condition + * */ + constructor(owner: ElementBase, expression: string); + type: string; + expression: string; + _owner: ElementBase; + /** + * Execute + * */ + execute(message: any, callback: CallableFunction): any; + } + + export {}; } declare module 'bpmn-elements/events' { - export var BoundaryEventBehaviour: IActivityBehaviour; - export var EndEventBehaviour: IActivityBehaviour; - export var IntermediateCatchEventBehaviour: IActivityBehaviour; - export var IntermediateThrowEventBehaviour: IActivityBehaviour; - export var StartEventBehaviour: IActivityBehaviour; + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + export function BoundaryEvent(activityDef: any, context: any): Activity; + export function BoundaryEventBehaviour(activity: any): void; + export class BoundaryEventBehaviour { + constructor(activity: any); + id: any; + type: any; + attachedTo: any; + activity: any; + environment: any; + broker: any; + execute(executeMessage: any): any; + _onExecutionMessage(routingKey: any, message: any): any; + _onCompleted(_: any, { content }: { + content: any; + }): any; + _onAttachedLeave(_: any, { content }: { + content: any; + }): any; + _onExpectMessage(_: any, { content }: { + content: any; + }): void; + _onDetachMessage(_: any, message: any): void; + _onApiMessage(_: any, message: any): void; + _onRepeatMessage(_: any, message: any): void; + _stop(detach: any): void; + + private [K_EXECUTION]; + + private [K_SHOVELS]; + + private [K_ATTACHED_TAGS]; + + private [K_EXECUTE_MESSAGE]; + + private [K_COMPLETE_CONTENT]; + } + const K_SHOVELS: unique symbol; + const K_ATTACHED_TAGS: unique symbol; + const K_COMPLETE_CONTENT: unique symbol; + export function EndEvent(activityDef: any, context: any): Activity; + export function EndEventBehaviour(activity: any): void; + export class EndEventBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute(executeMessage: any): any; + + private [K_EXECUTION]; + } + export function IntermediateCatchEvent(activityDef: any, context: any): Activity; + export function IntermediateCatchEventBehaviour(activity: any): void; + export class IntermediateCatchEventBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute(executeMessage: any): any; + _onApiMessage(executeMessage: any, routingKey: any, message: any): any; + + private [K_EXECUTION]; + } + export function IntermediateThrowEvent(activityDef: any, context: any): Activity; + export function IntermediateThrowEventBehaviour(activity: any): void; + export class IntermediateThrowEventBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute(executeMessage: any): any; + + private [K_EXECUTION]; + } + export function StartEvent(activityDef: any, context: any): Activity; + export function StartEventBehaviour(activity: any): void; + export class StartEventBehaviour { + constructor(activity: any); + id: any; + type: any; + activity: any; + broker: any; + get executionId(): any; + execute(executeMessage: any): any; + _onApiMessage(routingKey: any, message: any): any; + _onDelegatedApiMessage(routingKey: any, message: any): any; + _stop(): void; + + private [K_EXECUTION]; + + private [K_EXECUTE_MESSAGE]; + } + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger; + environment: Environment; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + const K_ACTIVATED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXECUTION: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_STATE_MESSAGE: unique symbol; + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + class Element extends ElementBase { + get broker(): ElementBroker; + stop(): void; + resume(): void; + getApi(message?: ElementBrokerMessage): Api; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; + waitFor(eventName: string, options?: any): Promise>; + } + + interface Api extends ElementBrokerMessage { + get id(): string; + get type(): string; + get name(): string; + get executionId(): string; + get environment(): Environment; + get broker(): ElementBroker; + get owner(): T; + cancel(message?: signalMessage, options?: any): void; + discard(): void; + fail(error: Error): void; + signal(message?: signalMessage, options?: any): void; + stop(): void; + resolveExpression(expression: string): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + getPostponed(...args: any[]): any[]; + createMessage(content?: Record): any; + getExecuting(): Api[]; + } + + class Environment { + constructor(options?: EnvironmentOptions); + options: Record; + expressions: IExpressions; + extensions: Record; + scripts: IScripts; + timers: ITimers; + Logger: LoggerFactory; + get settings(): EnvironmentSettings; + get variables(): Record; + get output(): Record; + set services(arg: any); + get services(): any; + getState(): EnvironmentState; + recover(state?: EnvironmentState): Environment; + clone(overrideOptions?: EnvironmentOptions): Environment; + assignVariables(newVars: Record): void; + assignSettings(newSettings: Record): Environment; + registerScript(activity: any): Script; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + getServiceByName(serviceName: string): CallableFunction; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + addService(name: string, fn: CallableFunction): void; + } + class ContextInstance { + constructor(definitionContext: SerializableContext, environment?: Environment); + get id(): string; + get name(): string; + get type(): string; + /** Unique context instance id */ + get sid(): string; + get definitionContext(): SerializableContext; + get environment(): Environment; + /** Context owner, Process or SubProcess activity */ + get owner(): Process | Activity | undefined; + getActivityById(activityId: string): T; + getSequenceFlowById(sequenceFlowId: string): SequenceFlow; + getInboundSequenceFlows(activityId: string): SequenceFlow[]; + getOutboundSequenceFlows(activityId: string): SequenceFlow[]; + getInboundAssociations(activityId: string): Association[]; + getOutboundAssociations(activityId: string): Association[]; + getActivities(scopeId?: string): ElementBase[]; + getSequenceFlows(scopeId?: string): SequenceFlow[]; + getAssociations(scopeId?: string): Association[]; + clone(newEnvironment?: Environment): ContextInstance; + getProcessById(processId: string): Process; + getNewProcessById(processId: string): Process; + getProcesses(): Process[]; + getExecutableProcesses(): Process[]; + getMessageFlows(sourceId: string): MessageFlow[]; + getDataObjectById(referenceId: string): any; + getDataStoreById(referenceId: string): any; + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; + loadExtensions(activity: ElementBase): IExtension; + } + + class Process extends Element { + constructor(processDef: SerializableElement, context: ContextInstance); + get isExecutable(): boolean; + get counters(): completedCounters; + get lanes(): Lane[] | undefined; + get extensions(): IExtension; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string; + get execution(): ProcessExecution; + get status(): ProcessRunStatus | undefined; + get activityStatus(): ActivityStatus; + init(useAsExecutionId?: string): void; + run(runContent?: Record): void; + getState(): ProcessState; + recover(state?: ProcessState): Process; + shake(startId?: string): void; + signal(message: any): any; + cancelActivity(message: any): any; + sendMessage(message: any): void; + getActivityById(childId: string): T; + getActivities(): Activity[]; + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + getSequenceFlows(): SequenceFlow[]; + getLaneById(laneId: string): Lane | undefined; + getPostponed(filterFn: filterPostponed): Api[]; + } + + interface ProcessExecution { + get isSubProcess(): boolean; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get executionId(): string; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): ActivityStatus; + execute(executeMessage: ElementBrokerMessage): void; + getPostponed(filterFn: filterPostponed): Api[]; + getActivities(): Activity[]; + getActivityById(activityId: string): T; + getSequenceFlows(): SequenceFlow[]; + getApi(message?: ElementBrokerMessage): Api; + } + + class Lane extends ElementBase { + constructor(process: Process, laneDefinition: SerializableElement); + /** Process broker */ + get broker(): Broker; + get process(): Process; + } + + class SequenceFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isDefault(): boolean; + get isSequenceFlow(): boolean; + get counters(): { take: number; discard: number; looped: number }; + take(content?: any): boolean; + discard(content?: any): void; + shake(message: any): number; + getCondition(): ISequenceFlowCondition | null; + createMessage(override?: any): object; + /** + * Evaluate flow + * Executes condition if any, default flow is + * @param fromMessage Activity message + * @param callback Callback with evaluation result, if truthy flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + getState(): SequenceFlowState | undefined; + } + + class MessageFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get source(): MessageFlowReference; + get target(): MessageFlowReference; + get counters(): { messages: number }; + activate(): void; + deactivate(): void; + getState(): MessageFlowState | undefined; + } + + class Association extends Element { + constructor(associationDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isAssociation(): boolean; + get counters(): { take: number; discard: number }; + take(content?: any): boolean; + discard(content?: any): boolean; + getState(): AssociationState | undefined; + } + interface ElementBroker extends Broker { + get owner(): T; + } + + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + } + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + type filterPostponed = (elementApi: any) => boolean; + + enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', + } + + /** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ + enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', + } + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; + } + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + + export {}; } declare module 'bpmn-elements/eventDefinitions' { - export var CancelEventDefinition: EventDefinition; - export var CompensateEventDefinition: EventDefinition; - export var ConditionalEventDefinition: ConditionalEventDefinition; - export var ErrorEventDefinition: EventDefinition; - export var EscalationEventDefinition: EventDefinition; - export var LinkEventDefinition: EventDefinition; - export var MessageEventDefinition: EventDefinition; - export var SignalEventDefinition: EventDefinition; - export var TerminateEventDefinition: EventDefinition; - export var TimerEventDefinition: TimerEventDefinition; + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + export function CancelEventDefinition(activity: any, eventDefinition: any): void; + export class CancelEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + environment: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(_: any, message: any): any; + _complete(output: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _debug(msg: any): void; + + private [K_EXECUTE_MESSAGE]; + + private [K_COMPLETED]; + } + export function CompensateEventDefinition(activity: any, eventDefinition: any, context: any): void; + export class CompensateEventDefinition { + constructor(activity: any, eventDefinition: any, context: any); + id: any; + type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + _onCollect(routingKey: any, message: any): any; + _onCompensateApiMessage(routingKey: any, message: any): any; + _compensate(): any; + _onCollected(routingKey: any, message: any): any; + _onDiscardApiMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stopCollect(): void; + _stop(): void; + _debug(msg: any): void; + + private [K_COMPLETED]; + + private [K_ASSOCIATIONS]; + + private [K_MESSAGE_Q]; + + private [K_COMPENSATE_Q]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ASSOCIATIONS: unique symbol; + const K_COMPENSATE_Q: unique symbol; + export function ConditionalEventDefinition(activity: any, eventDefinition: any, _context: any, index: any): void; + export class ConditionalEventDefinition { + constructor(activity: any, eventDefinition: any, _context: any, index: any); + id: any; + type: any; + behaviour: any; + activity: any; + environment: any; + broker: any; + logger: any; + condition: ScriptCondition | ExpressionCondition | null; + get executionId(): any; + execute(executeMessage: any): void; + _setup(executeMessage: any): void; + /** + * Evaluate condition + * */ + evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; + /** + * Handle evaluate result or error + * @param err Condition evaluation error + * @param result Result from evaluated condition, completes execution if truthy + */ + evaluateCallback(err: Error | null, result: any): any; + /** + * Get condition + * @param index Eventdefinition sequence number, used to name registered script + * */ + getCondition(index: number): ExpressionCondition | ScriptCondition | null; + _onDelegateApiMessage(routingKey: any, message: any): void; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _debug(msg: any): void; + + private [K_EXECUTE_MESSAGE]; + } + export function ErrorEventDefinition(activity: any, eventDefinition: any): void; + export class ErrorEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + environment: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onErrorMessage(routingKey: any, message: any): any; + _onThrowApiMessage(routingKey: any, message: any): any; + _catchError(routingKey: any, message: any, error: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export function EscalationEventDefinition(activity: any, eventDefinition: any): void; + export class EscalationEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + const K_REFERENCE: unique symbol; + export function LinkEventDefinition(activity: any, eventDefinition: any): void; + export class LinkEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: { + id: any; + linkName: any; + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + _onLinkApiMessage(_: any, message: any): void; + _onShakeMessage(_: any, message: any): void; + + private [K_EXECUTE_MESSAGE]; + } + export function MessageEventDefinition(activity: any, eventDefinition: any): void; + export class MessageEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): void; + _onApiMessage(routingKey: any, message: any): any; + _complete(verb: any, output: any, options: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export function SignalEventDefinition(activity: any, eventDefinition: any): void; + export class SignalEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _complete(output: any, options: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export function TerminateEventDefinition(activity: any, eventDefinition: any): void; + export class TerminateEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + activity: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + } + export function TimerEventDefinition(activity: any, eventDefinition: any): void; + export class TimerEventDefinition { + constructor(activity: any, eventDefinition: any); + type: any; + activity: any; + environment: any; + eventDefinition: any; + timeDuration: any; + timeCycle: any; + timeDate: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + startedAt: Date | undefined; + stop(): void; + _completed(completeContent: any, options: any): void; + _onDelegatedApiMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + parse(timerType: any, value: any): { + expireAt: Date | undefined; + repeat: number | undefined; + delay: number | undefined; + }; + _getTimers(executeMessage: any): { + expireAt?: Date | undefined; + }; + _debug(msg: any): void; + + private [K_STOPPED]; + + private [K_TIMER]; + [K_TIMER_CONTENT]: any; + } + const K_TIMER: unique symbol; + const K_TIMER_CONTENT: unique symbol; + const K_ACTIVATED: unique symbol; + const K_COMPLETED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_MESSAGE_Q: unique symbol; + const K_REFERENCE_ELEMENT: unique symbol; + const K_REFERENCE_INFO: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_STOPPED: unique symbol; + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + class Element extends ElementBase { + get broker(): ElementBroker; + stop(): void; + resume(): void; + getApi(message?: ElementBrokerMessage): Api; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; + waitFor(eventName: string, options?: any): Promise>; + } + + interface Api extends ElementBrokerMessage { + get id(): string; + get type(): string; + get name(): string; + get executionId(): string; + get environment(): Environment; + get broker(): ElementBroker; + get owner(): T; + cancel(message?: signalMessage, options?: any): void; + discard(): void; + fail(error: Error): void; + signal(message?: signalMessage, options?: any): void; + stop(): void; + resolveExpression(expression: string): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + getPostponed(...args: any[]): any[]; + createMessage(content?: Record): any; + getExecuting(): Api[]; + } + + class Environment { + constructor(options?: EnvironmentOptions); + options: Record; + expressions: IExpressions; + extensions: Record; + scripts: IScripts; + timers: ITimers; + Logger: LoggerFactory; + get settings(): EnvironmentSettings; + get variables(): Record; + get output(): Record; + set services(arg: any); + get services(): any; + getState(): EnvironmentState; + recover(state?: EnvironmentState): Environment; + clone(overrideOptions?: EnvironmentOptions): Environment; + assignVariables(newVars: Record): void; + assignSettings(newSettings: Record): Environment; + registerScript(activity: any): Script; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + getServiceByName(serviceName: string): CallableFunction; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + addService(name: string, fn: CallableFunction): void; + } + class ContextInstance { + constructor(definitionContext: SerializableContext, environment?: Environment); + get id(): string; + get name(): string; + get type(): string; + /** Unique context instance id */ + get sid(): string; + get definitionContext(): SerializableContext; + get environment(): Environment; + /** Context owner, Process or SubProcess activity */ + get owner(): Process | Activity | undefined; + getActivityById(activityId: string): T; + getSequenceFlowById(sequenceFlowId: string): SequenceFlow; + getInboundSequenceFlows(activityId: string): SequenceFlow[]; + getOutboundSequenceFlows(activityId: string): SequenceFlow[]; + getInboundAssociations(activityId: string): Association[]; + getOutboundAssociations(activityId: string): Association[]; + getActivities(scopeId?: string): ElementBase[]; + getSequenceFlows(scopeId?: string): SequenceFlow[]; + getAssociations(scopeId?: string): Association[]; + clone(newEnvironment?: Environment): ContextInstance; + getProcessById(processId: string): Process; + getNewProcessById(processId: string): Process; + getProcesses(): Process[]; + getExecutableProcesses(): Process[]; + getMessageFlows(sourceId: string): MessageFlow[]; + getDataObjectById(referenceId: string): any; + getDataStoreById(referenceId: string): any; + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; + loadExtensions(activity: ElementBase): IExtension; + } + + class Process extends Element { + constructor(processDef: SerializableElement, context: ContextInstance); + get isExecutable(): boolean; + get counters(): completedCounters; + get lanes(): Lane[] | undefined; + get extensions(): IExtension; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string; + get execution(): ProcessExecution; + get status(): ProcessRunStatus | undefined; + get activityStatus(): ActivityStatus; + init(useAsExecutionId?: string): void; + run(runContent?: Record): void; + getState(): ProcessState; + recover(state?: ProcessState): Process; + shake(startId?: string): void; + signal(message: any): any; + cancelActivity(message: any): any; + sendMessage(message: any): void; + getActivityById(childId: string): T; + getActivities(): Activity[]; + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + getSequenceFlows(): SequenceFlow[]; + getLaneById(laneId: string): Lane | undefined; + getPostponed(filterFn: filterPostponed): Api[]; + } + + interface ProcessExecution { + get isSubProcess(): boolean; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get executionId(): string; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): ActivityStatus; + execute(executeMessage: ElementBrokerMessage): void; + getPostponed(filterFn: filterPostponed): Api[]; + getActivities(): Activity[]; + getActivityById(activityId: string): T; + getSequenceFlows(): SequenceFlow[]; + getApi(message?: ElementBrokerMessage): Api; + } + + class Lane extends ElementBase { + constructor(process: Process, laneDefinition: SerializableElement); + /** Process broker */ + get broker(): Broker; + get process(): Process; + } + + class SequenceFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isDefault(): boolean; + get isSequenceFlow(): boolean; + get counters(): { take: number; discard: number; looped: number }; + take(content?: any): boolean; + discard(content?: any): void; + shake(message: any): number; + getCondition(): ISequenceFlowCondition | null; + createMessage(override?: any): object; + /** + * Evaluate flow + * Executes condition if any, default flow is + * @param fromMessage Activity message + * @param callback Callback with evaluation result, if truthy flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + getState(): SequenceFlowState | undefined; + } + + class MessageFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get source(): MessageFlowReference; + get target(): MessageFlowReference; + get counters(): { messages: number }; + activate(): void; + deactivate(): void; + getState(): MessageFlowState | undefined; + } + + class Association extends Element { + constructor(associationDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isAssociation(): boolean; + get counters(): { take: number; discard: number }; + take(content?: any): boolean; + discard(content?: any): boolean; + getState(): AssociationState | undefined; + } + /** + * Script condition + * */ + function ScriptCondition(owner: ElementBase, script: any, language: string): void; + class ScriptCondition { + /** + * Script condition + * */ + constructor(owner: ElementBase, script: any, language: string); + type: string; + language: string; + _owner: ElementBase; + _script: any; + /** + * Execute + * */ + execute(message: any, callback: CallableFunction): any; + } + /** + * Expression condition + * */ + function ExpressionCondition(owner: ElementBase, expression: string): void; + class ExpressionCondition { + /** + * Expression condition + * */ + constructor(owner: ElementBase, expression: string); + type: string; + expression: string; + _owner: ElementBase; + /** + * Execute + * */ + execute(message: any, callback: CallableFunction): any; + } + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger; + environment: Environment; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + interface ElementBroker extends Broker { + get owner(): T; + } + + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + } + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + type filterPostponed = (elementApi: any) => boolean; + + enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', + } + + /** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ + enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', + } + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; + } + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + + export {}; } declare module 'bpmn-elements/flows' { - export var Association: Association; - export var SequenceFlow: SequenceFlow; - export var MessageFlow: MessageFlow; + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + /** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + export function Association(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; + export class Association { + /** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isAssociation: boolean; + environment: Environment; + logger: ILogger; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + get counters(): { + take: number; + discard: number; + }; + /** + * Take the association and publish association.take. + * + */ + take(content?: Record): boolean; + /** + * Discard the association and publish association.discard. + * + */ + discard(content?: Record): boolean; + /** + * Snapshot association state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): AssociationState | undefined; + /** + * Restore association state captured by getState. + * */ + recover(state: AssociationState): void; + /** + * Resolve an association-scoped Api wrapper. + * + */ + getApi(message?: ElementBrokerMessage): Api_1; + /** + * Stop the association's broker. + */ + stop(): void; + + _publishEvent(action: any, content: any): void; + + _createMessageContent(override: any): any; + + private [K_COUNTERS]; + } + /** + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + export function MessageFlow(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + export class MessageFlow { + /** + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + source: any; + target: any; + behaviour: Record; + environment: Environment; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + emit: any; + waitFor: any; + logger: ILogger; + get counters(): { + messages: number; + }; + /** + * Snapshot message-flow state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): MessageFlowState | undefined; + /** + * Restore message-flow state captured by getState. + * */ + recover(state: MessageFlowState): void; + /** + * Resolve a message-scoped Api wrapper. + * + */ + getApi(message?: ElementBrokerMessage): Api_1; + /** + * Subscribe to the source element's message and end events to bridge the message across. + */ + activate(): void; + /** + * Cancel the source element subscriptions added by activate. + */ + deactivate(): void; + + _onSourceEnd({ content }: { + content: any; + }): void; + + _createMessageContent(message: any): { + id: string | undefined; + type: string; + name: any; + source: any; + target: any; + parent: any; + message: any; + }; + + private [K_COUNTERS]; + + private [K_SOURCE_ELEMENT]; + } + const K_SOURCE_ELEMENT: unique symbol; + /** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + export function SequenceFlow(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; + export class SequenceFlow { + /** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isDefault: any; + isSequenceFlow: boolean; + environment: Environment; + logger: ILogger; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + get counters(): { + take: number; + discard: number; + looped: number; + }; + /** + * Take the flow and publish flow.take. + * + */ + take(content?: Record): boolean; + /** + * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits + * flow.looped instead when the target id is already in the sequence. + * + */ + discard(content?: Record): void; + /** + * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` + * is set. + * */ + getState(): SequenceFlowState | undefined; + /** + * Restore flow state captured by getState. + * */ + recover(state: SequenceFlowState): void; + /** + * Resolve a Flow Api wrapper. + * + */ + getApi(message?: ElementBrokerMessage): Api_1; + /** + * Stop the flow's broker. + */ + stop(): void; + /** + * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop + * when the target was already visited, otherwise flow.shake. + * */ + shake(message: ElementBrokerMessage): any; + /** + * Resolve the flow's condition (script or expression). Returns null when no condition is set. + * Emits a fatal error when the script language is missing or unsupported. + * */ + getCondition(): ISequenceFlowCondition | null; + /** + * Build a flow event message body, optionally merging override content. + * + */ + createMessage(override?: Record): { + id: string | undefined; + type: string; + name: any; + sourceId: any; + targetId: any; + isSequenceFlow: boolean; + isDefault: any; + parent: any; + }; + /** + * Evaluate the flow's condition for the source activity message. Default flows are always taken. + * @param fromMessage Source activity message + * @param callback Callback with truthy result if flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; + + _publishEvent(action: any, content: any): void; + + private [K_COUNTERS]; + } + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + class Element extends ElementBase { + get broker(): ElementBroker; + stop(): void; + resume(): void; + getApi(message?: ElementBrokerMessage): Api; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; + waitFor(eventName: string, options?: any): Promise>; + } + + interface Api extends ElementBrokerMessage { + get id(): string; + get type(): string; + get name(): string; + get executionId(): string; + get environment(): Environment; + get broker(): ElementBroker; + get owner(): T; + cancel(message?: signalMessage, options?: any): void; + discard(): void; + fail(error: Error): void; + signal(message?: signalMessage, options?: any): void; + stop(): void; + resolveExpression(expression: string): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + getPostponed(...args: any[]): any[]; + createMessage(content?: Record): any; + getExecuting(): Api[]; + } + + class Environment { + constructor(options?: EnvironmentOptions); + options: Record; + expressions: IExpressions; + extensions: Record; + scripts: IScripts; + timers: ITimers; + Logger: LoggerFactory; + get settings(): EnvironmentSettings; + get variables(): Record; + get output(): Record; + set services(arg: any); + get services(): any; + getState(): EnvironmentState; + recover(state?: EnvironmentState): Environment; + clone(overrideOptions?: EnvironmentOptions): Environment; + assignVariables(newVars: Record): void; + assignSettings(newSettings: Record): Environment; + registerScript(activity: any): Script; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + getServiceByName(serviceName: string): CallableFunction; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + addService(name: string, fn: CallableFunction): void; + } + class ContextInstance { + constructor(definitionContext: SerializableContext, environment?: Environment); + get id(): string; + get name(): string; + get type(): string; + /** Unique context instance id */ + get sid(): string; + get definitionContext(): SerializableContext; + get environment(): Environment; + /** Context owner, Process or SubProcess activity */ + get owner(): Process | Activity | undefined; + getActivityById(activityId: string): T; + getSequenceFlowById(sequenceFlowId: string): SequenceFlow_1; + getInboundSequenceFlows(activityId: string): SequenceFlow_1[]; + getOutboundSequenceFlows(activityId: string): SequenceFlow_1[]; + getInboundAssociations(activityId: string): Association_1[]; + getOutboundAssociations(activityId: string): Association_1[]; + getActivities(scopeId?: string): ElementBase[]; + getSequenceFlows(scopeId?: string): SequenceFlow_1[]; + getAssociations(scopeId?: string): Association_1[]; + clone(newEnvironment?: Environment): ContextInstance; + getProcessById(processId: string): Process; + getNewProcessById(processId: string): Process; + getProcesses(): Process[]; + getExecutableProcesses(): Process[]; + getMessageFlows(sourceId: string): MessageFlow_1[]; + getDataObjectById(referenceId: string): any; + getDataStoreById(referenceId: string): any; + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; + loadExtensions(activity: ElementBase): IExtension; + } + + class Process extends Element { + constructor(processDef: SerializableElement, context: ContextInstance); + get isExecutable(): boolean; + get counters(): completedCounters; + get lanes(): Lane[] | undefined; + get extensions(): IExtension; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string; + get execution(): ProcessExecution; + get status(): ProcessRunStatus | undefined; + get activityStatus(): ActivityStatus; + init(useAsExecutionId?: string): void; + run(runContent?: Record): void; + getState(): ProcessState; + recover(state?: ProcessState): Process; + shake(startId?: string): void; + signal(message: any): any; + cancelActivity(message: any): any; + sendMessage(message: any): void; + getActivityById(childId: string): T; + getActivities(): Activity[]; + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + getSequenceFlows(): SequenceFlow_1[]; + getLaneById(laneId: string): Lane | undefined; + getPostponed(filterFn: filterPostponed): Api[]; + } + + interface ProcessExecution { + get isSubProcess(): boolean; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get executionId(): string; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): ActivityStatus; + execute(executeMessage: ElementBrokerMessage): void; + getPostponed(filterFn: filterPostponed): Api[]; + getActivities(): Activity[]; + getActivityById(activityId: string): T; + getSequenceFlows(): SequenceFlow_1[]; + getApi(message?: ElementBrokerMessage): Api; + } + + class Lane extends ElementBase { + constructor(process: Process, laneDefinition: SerializableElement); + /** Process broker */ + get broker(): Broker; + get process(): Process; + } + + class SequenceFlow_1 extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isDefault(): boolean; + get isSequenceFlow(): boolean; + get counters(): { take: number; discard: number; looped: number }; + take(content?: any): boolean; + discard(content?: any): void; + shake(message: any): number; + getCondition(): ISequenceFlowCondition | null; + createMessage(override?: any): object; + /** + * Evaluate flow + * Executes condition if any, default flow is + * @param fromMessage Activity message + * @param callback Callback with evaluation result, if truthy flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + getState(): SequenceFlowState | undefined; + } + + class MessageFlow_1 extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get source(): MessageFlowReference; + get target(): MessageFlowReference; + get counters(): { messages: number }; + activate(): void; + deactivate(): void; + getState(): MessageFlowState | undefined; + } + + class Association_1 extends Element { + constructor(associationDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isAssociation(): boolean; + get counters(): { take: number; discard: number }; + take(content?: any): boolean; + discard(content?: any): boolean; + getState(): AssociationState | undefined; + } + interface ElementBroker extends Broker { + get owner(): T; + } + + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + } + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + type filterPostponed = (elementApi: any) => boolean; + + enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', + } + + /** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ + enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', + } + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; + } + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + /** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param sourceMessage Cloned to back the api + * @param environment Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing + */ + function Api_1(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment): void; + class Api_1 { + /** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param sourceMessage Cloned to back the api + * @param environment Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing + */ + constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment); + id: any; + type: any; + name: any; + executionId: any; + environment: any; + content: any; + fields: any; + messageProperties: any; + broker: any; + owner: any; + messagePrefix: string; + /** + * Send a cancel api message. + * + */ + cancel(message?: signalMessage, options?: any): void; + /** + * Send a discard api message. + */ + discard(): void; + /** + * Send an error api message that fails the activity. + * */ + fail(error: Error): void; + /** + * Send a signal api message. + * + */ + signal(message?: signalMessage, options?: any): void; + /** + * Send a stop api message. + */ + stop(): void; + /** + * Resolve an expression with the api message as scope and the broker owner as context. + * */ + resolveExpression(expression: string): any; + /** + * Publish a custom api message to the broker. + * @param action Routing key suffix, e.g. `signal`, `cancel` + * @param content Merged into the message content + * + */ + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + /** + * List currently postponed activities, falling back to a sub-process execution when applicable. + * + */ + getPostponed(...args: any[]): any; + /** + * Build a message body by merging the given content onto the source content. + * + */ + createMessage(content?: Record): any; + } + const K_ACTIVATED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_STATE_MESSAGE: unique symbol; + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger; + environment: Environment; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): SequenceFlow_1 | undefined; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + + export {}; } declare module 'bpmn-elements/gateways' { - export var EventBasedGatewayBehaviour: IActivityBehaviour; - export var ExclusiveGatewayBehaviour: IActivityBehaviour; - export var InclusiveGatewayBehaviour: IActivityBehaviour; - export var ParallelGatewayBehaviour: IActivityBehaviour; + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + export function EventBasedGateway(activityDef: any, context: any): Activity; + export function EventBasedGatewayBehaviour(activity: any, context: any): void; + export class EventBasedGatewayBehaviour { + constructor(activity: any, context: any); + id: any; + type: any; + activity: any; + broker: any; + context: any; + execute(executeMessage: any): any; + _onTargetCompleted(executeMessage: any, _: any, message: any, owner: any): void; + _complete(completedContent: any): void; + _stop(): void; + + private [K_TARGETS]; + + private [K_COMPLETED]; + } + export function ExclusiveGateway(activityDef: any, context: any): Activity; + export function ExclusiveGatewayBehaviour(activity: any): void; + export class ExclusiveGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute({ content }: { + content: any; + }): void; + } + export function InclusiveGateway(activityDef: any, context: any): Activity; + export function InclusiveGatewayBehaviour(activity: any): void; + export class InclusiveGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute({ content }: { + content: any; + }): void; + } + export function ParallelGateway(activityDef: any, context: any): Activity; + export class ParallelGateway { + constructor(activityDef: any, context: any); + id: string | undefined; + } + export function ParallelGatewayBehaviour(activity: any): void; + export class ParallelGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + activity: any; + broker: any; + inbound: Set; + isConverging: boolean; + execute(executeMessage: any): any; + setup(executeMessage: any): any; + peerMonitor: PeerMonitor | undefined; + _onExecuteMessage(routingKey: any, message: any): any; + _onPeerEnterMessage(_: any, message: any): void; + _complete(): any; + _stop(): void; + + private [K_EXECUTE_MESSAGE]; + + private [K_TARGETS]; + } + function PeerMonitor(activity: any, peers: any, targets: any): void; + class PeerMonitor { + constructor(activity: any, peers: any, targets: any); + activity: any; + id: any; + broker: any; + running: Map; + index: number; + discarded: number; + watching: Map; + peers: any; + targets: any; + touched: Set; + inbound: any[]; + get isRunning(): boolean; + execute(executeMessage: any): number; + monitor(peerActivity: any): void; + _onCompleteMessage(_routingKey: any, message: any): boolean; + stop(): void; + } + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger; + environment: Environment; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + const K_ACTIVATED: unique symbol; + const K_COMPLETED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_TARGETS: unique symbol; + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + class Element extends ElementBase { + get broker(): ElementBroker; + stop(): void; + resume(): void; + getApi(message?: ElementBrokerMessage): Api; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; + waitFor(eventName: string, options?: any): Promise>; + } + + interface Api extends ElementBrokerMessage { + get id(): string; + get type(): string; + get name(): string; + get executionId(): string; + get environment(): Environment; + get broker(): ElementBroker; + get owner(): T; + cancel(message?: signalMessage, options?: any): void; + discard(): void; + fail(error: Error): void; + signal(message?: signalMessage, options?: any): void; + stop(): void; + resolveExpression(expression: string): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + getPostponed(...args: any[]): any[]; + createMessage(content?: Record): any; + getExecuting(): Api[]; + } + + class Environment { + constructor(options?: EnvironmentOptions); + options: Record; + expressions: IExpressions; + extensions: Record; + scripts: IScripts; + timers: ITimers; + Logger: LoggerFactory; + get settings(): EnvironmentSettings; + get variables(): Record; + get output(): Record; + set services(arg: any); + get services(): any; + getState(): EnvironmentState; + recover(state?: EnvironmentState): Environment; + clone(overrideOptions?: EnvironmentOptions): Environment; + assignVariables(newVars: Record): void; + assignSettings(newSettings: Record): Environment; + registerScript(activity: any): Script; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + getServiceByName(serviceName: string): CallableFunction; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + addService(name: string, fn: CallableFunction): void; + } + class ContextInstance { + constructor(definitionContext: SerializableContext, environment?: Environment); + get id(): string; + get name(): string; + get type(): string; + /** Unique context instance id */ + get sid(): string; + get definitionContext(): SerializableContext; + get environment(): Environment; + /** Context owner, Process or SubProcess activity */ + get owner(): Process | Activity | undefined; + getActivityById(activityId: string): T; + getSequenceFlowById(sequenceFlowId: string): SequenceFlow; + getInboundSequenceFlows(activityId: string): SequenceFlow[]; + getOutboundSequenceFlows(activityId: string): SequenceFlow[]; + getInboundAssociations(activityId: string): Association[]; + getOutboundAssociations(activityId: string): Association[]; + getActivities(scopeId?: string): ElementBase[]; + getSequenceFlows(scopeId?: string): SequenceFlow[]; + getAssociations(scopeId?: string): Association[]; + clone(newEnvironment?: Environment): ContextInstance; + getProcessById(processId: string): Process; + getNewProcessById(processId: string): Process; + getProcesses(): Process[]; + getExecutableProcesses(): Process[]; + getMessageFlows(sourceId: string): MessageFlow[]; + getDataObjectById(referenceId: string): any; + getDataStoreById(referenceId: string): any; + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; + loadExtensions(activity: ElementBase): IExtension; + } + + class Process extends Element { + constructor(processDef: SerializableElement, context: ContextInstance); + get isExecutable(): boolean; + get counters(): completedCounters; + get lanes(): Lane[] | undefined; + get extensions(): IExtension; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string; + get execution(): ProcessExecution; + get status(): ProcessRunStatus | undefined; + get activityStatus(): ActivityStatus; + init(useAsExecutionId?: string): void; + run(runContent?: Record): void; + getState(): ProcessState; + recover(state?: ProcessState): Process; + shake(startId?: string): void; + signal(message: any): any; + cancelActivity(message: any): any; + sendMessage(message: any): void; + getActivityById(childId: string): T; + getActivities(): Activity[]; + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + getSequenceFlows(): SequenceFlow[]; + getLaneById(laneId: string): Lane | undefined; + getPostponed(filterFn: filterPostponed): Api[]; + } + + interface ProcessExecution { + get isSubProcess(): boolean; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get executionId(): string; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): ActivityStatus; + execute(executeMessage: ElementBrokerMessage): void; + getPostponed(filterFn: filterPostponed): Api[]; + getActivities(): Activity[]; + getActivityById(activityId: string): T; + getSequenceFlows(): SequenceFlow[]; + getApi(message?: ElementBrokerMessage): Api; + } + + class Lane extends ElementBase { + constructor(process: Process, laneDefinition: SerializableElement); + /** Process broker */ + get broker(): Broker; + get process(): Process; + } + + class SequenceFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isDefault(): boolean; + get isSequenceFlow(): boolean; + get counters(): { take: number; discard: number; looped: number }; + take(content?: any): boolean; + discard(content?: any): void; + shake(message: any): number; + getCondition(): ISequenceFlowCondition | null; + createMessage(override?: any): object; + /** + * Evaluate flow + * Executes condition if any, default flow is + * @param fromMessage Activity message + * @param callback Callback with evaluation result, if truthy flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + getState(): SequenceFlowState | undefined; + } + + class MessageFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get source(): MessageFlowReference; + get target(): MessageFlowReference; + get counters(): { messages: number }; + activate(): void; + deactivate(): void; + getState(): MessageFlowState | undefined; + } + + class Association extends Element { + constructor(associationDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isAssociation(): boolean; + get counters(): { take: number; discard: number }; + take(content?: any): boolean; + discard(content?: any): boolean; + getState(): AssociationState | undefined; + } + interface ElementBroker extends Broker { + get owner(): T; + } + + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + } + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + type filterPostponed = (elementApi: any) => boolean; + + enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', + } + + /** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ + enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', + } + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; + } + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + + export {}; } declare module 'bpmn-elements/tasks' { - export var CallActivityBehaviour: IActivityBehaviour; - export var ReceiveTaskBehaviour: IActivityBehaviour; - export var ScriptTaskBehaviour: IActivityBehaviour; - export var ServiceTaskBehaviour: IActivityBehaviour; - /** Signal-, Manual-, and User-task behaviour */ - export var SignalTaskBehaviour: IActivityBehaviour; - /** Sub process and Transaction behaviour */ - export var SubProcessBehaviour: IActivityBehaviour; - export var TaskBehaviour: IActivityBehaviour; + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + export function CallActivity(activityDef: any, context: any): Activity; + export function CallActivityBehaviour(activity: any): void; + export class CallActivityBehaviour { + constructor(activity: any); + id: any; + type: any; + calledElement: any; + loopCharacteristics: any; + activity: any; + broker: any; + environment: any; + execute(executeMessage: any): any; + _onDelegatedApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; + _onApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; + _stop(executionId: any): void; + } + export function ReceiveTask(activityDef: any, context: any): Activity; + export function ReceiveTaskBehaviour(activity: any): void; + export class ReceiveTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + reference: any; + loopCharacteristics: any; + activity: any; + broker: any; + execute(executeMessage: any): any; + + private [K_REFERENCE_ELEMENT]; + } + export function ScriptTask(activityDef: any, context: any): Activity; + export function ScriptTaskBehaviour(activity: any): void; + export class ScriptTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + scriptFormat: any; + loopCharacteristics: any; + activity: any; + environment: any; + execute(executeMessage: any): any; + } + export function ServiceTask(activityDef: any, context: any): Activity; + export function ServiceTaskBehaviour(activity: any): void; + export class ServiceTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + environment: any; + broker: any; + execute(executeMessage: any): any; + service: any; + getService(message: any): any; + _onApiMessage(executeMessage: any, _: any, message: any): any; + } + export function SignalTask(activityDef: any, context: any): Activity; + export function SignalTaskBehaviour(activity: any): void; + export class SignalTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + broker: any; + execute(executeMessage: any): any; + _onDelegatedApiMessage(executeMessage: any, routingKey: any, message: any): any; + _onApiMessage(executeMessage: any, routingKey: any, message: any): any; + _stop(executionId: any): void; + } + export function SubProcess(activityDef: any, context: any): Activity; + export function SubProcessBehaviour(activity: any, context: any): void; + export class SubProcessBehaviour { + constructor(activity: any, context: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + context: any; + environment: any; + broker: any; + executionId: any; + execute(executeMessage: any): any; + getState(): any; + recover(state: any): ProcessExecution_1 | undefined; + getPostponed(): any[]; + _upsertExecution(executeMessage: any): any; + _addListeners(executionId: any): void; + _onExecutionCompleted(_: any, message: any): any; + _completeExecution(completeRoutingKey: any, content: any): void; + getApi(apiMessage: any): any; + _getExecutionById(executionId: any): any; + + private [K_EXECUTIONS]; + + private [K_ON_EXECUTION_COMPLETED]; + } + const K_EXECUTIONS: unique symbol; + const K_ON_EXECUTION_COMPLETED: unique symbol; + export function Task(activityDef: any, context: any): Activity; + export function TaskBehaviour(activity: any): void; + export class TaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + broker: any; + execute(executeMessage: any): any; + } + export function Transaction(activityDef: any, context: any): Activity; + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger; + environment: Environment; + context: ContextInstance; + broker: import("smqp").default | undefined; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + const K_ACTIVATED: unique symbol; + const K_COMPLETED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_REFERENCE_ELEMENT: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_STATUS: unique symbol; + const K_STOPPED: unique symbol; + /** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + function ProcessExecution_1(parentActivity: Process | Activity, context: ContextInstance): void; + class ProcessExecution_1 { + /** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + constructor(parentActivity: Process | Activity, context: ContextInstance); + id: string | undefined; + type: string; + isSubProcess: any; + isTransaction: any; + broker: import("smqp").default | ElementBroker | undefined; + environment: Environment; + context: ContextInstance; + _exchangeName: string; + executionId: string | undefined; + /** + * Activate children and start the process execution. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing + */ + execute(executeMessage: ElementBrokerMessage): any; + /** + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. + */ + resume(): any; + /** + * Snapshot execution state including children, flows, message flows, and associations. + */ + getState(): { + associations?: (AssociationState | undefined)[] | undefined; + messageFlows?: (MessageFlowState | undefined)[] | undefined; + flows?: any[] | undefined; + executionId: string | undefined; + stopped: boolean; + completed: boolean; + status: any; + children: never[]; + }; + /** + * Restore execution state captured by getState. + * */ + recover(state?: ProcessExecutionState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. + * + */ + shake(fromId?: string): any; + /** + * Stop the running process execution via the api. + */ + stop(): void; + /** + * List currently postponed children as Api wrappers. + * + */ + getPostponed(filterFn?: filterPostponed): any[]; + /** + * Queue a discard message that propagates to all running children. + */ + discard(): number | undefined; + /** + * Queue a cancel message that propagates to all running children. + */ + cancel(): number | undefined; + /** + * Get child activities in the process scope. + */ + getActivities(): ElementBase[]; + + getActivityById(activityId: string): ElementBase | undefined; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): SequenceFlow[]; + /** + * Get associations in the process scope. + */ + getAssociations(): Association[]; + /** + * Resolve a process or child Api for the given message. + * + */ + getApi(message?: ElementBrokerMessage): any; + + _start(): any; + + _activate(): void; + + _deactivate(): void; + + _shakeElements(fromId: any): { + settings: { + skipDiscard: boolean | undefined; + }; + sequences: Map; + }; + + _onDelegateEvent(message: any): boolean; + + _onMessageFlowEvent(routingKey: any, message: any): void; + + _onActivityEvent(routingKey: any, message: any): number | void; + + _onChildMessage(routingKey: any, message: any): any; + + _stateChangeMessage(message: any, postponeMessage: any): void; + + _popPostponed(byContent: any): any; + + _onChildCompleted(message: any): any; + + _stopExecution(message: any): any; + + _onDiscard(): any; + + _onCancel(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _delegateApiMessage(routingKey: any, message: any, continueOnConsumed: any): boolean; + + _complete(completionType: any, content: any): any; + + _terminate(message: any): void; + + _getFlowById(flowId: any): SequenceFlow | undefined; + + _getAssociationById(associationId: any): Association | undefined; + + _getMessageFlowById(flowId: any): MessageFlow | undefined; + + _getChildById(childId: any): ElementBase | SequenceFlow | undefined; + + _getChildApi(message: any): any; + + _onShakeMessage(message: any): void; + + _debug(logMessage: any): void; + + private [K_PARENT]; + + private [K_ELEMENTS]; + + private [K_COMPLETED]; + + private [K_STOPPED]; + + private [K_ACTIVATED]; + + private [K_STATUS]; + + private [K_TRACKER]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EXECUTE_MESSAGE]; + + private [K_ACTIVITY_Q]; + } + const K_PARENT: unique symbol; + const K_ELEMENTS: unique symbol; + const K_TRACKER: unique symbol; + const K_ACTIVITY_Q: unique symbol; + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + class Element extends ElementBase { + get broker(): ElementBroker; + stop(): void; + resume(): void; + getApi(message?: ElementBrokerMessage): Api; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; + waitFor(eventName: string, options?: any): Promise>; + } + + interface Api extends ElementBrokerMessage { + get id(): string; + get type(): string; + get name(): string; + get executionId(): string; + get environment(): Environment; + get broker(): ElementBroker; + get owner(): T; + cancel(message?: signalMessage, options?: any): void; + discard(): void; + fail(error: Error): void; + signal(message?: signalMessage, options?: any): void; + stop(): void; + resolveExpression(expression: string): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + getPostponed(...args: any[]): any[]; + createMessage(content?: Record): any; + getExecuting(): Api[]; + } + + class Environment { + constructor(options?: EnvironmentOptions); + options: Record; + expressions: IExpressions; + extensions: Record; + scripts: IScripts; + timers: ITimers; + Logger: LoggerFactory; + get settings(): EnvironmentSettings; + get variables(): Record; + get output(): Record; + set services(arg: any); + get services(): any; + getState(): EnvironmentState; + recover(state?: EnvironmentState): Environment; + clone(overrideOptions?: EnvironmentOptions): Environment; + assignVariables(newVars: Record): void; + assignSettings(newSettings: Record): Environment; + registerScript(activity: any): Script; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + getServiceByName(serviceName: string): CallableFunction; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + addService(name: string, fn: CallableFunction): void; + } + class ContextInstance { + constructor(definitionContext: SerializableContext, environment?: Environment); + get id(): string; + get name(): string; + get type(): string; + /** Unique context instance id */ + get sid(): string; + get definitionContext(): SerializableContext; + get environment(): Environment; + /** Context owner, Process or SubProcess activity */ + get owner(): Process | Activity | undefined; + getActivityById(activityId: string): T; + getSequenceFlowById(sequenceFlowId: string): SequenceFlow; + getInboundSequenceFlows(activityId: string): SequenceFlow[]; + getOutboundSequenceFlows(activityId: string): SequenceFlow[]; + getInboundAssociations(activityId: string): Association[]; + getOutboundAssociations(activityId: string): Association[]; + getActivities(scopeId?: string): ElementBase[]; + getSequenceFlows(scopeId?: string): SequenceFlow[]; + getAssociations(scopeId?: string): Association[]; + clone(newEnvironment?: Environment): ContextInstance; + getProcessById(processId: string): Process; + getNewProcessById(processId: string): Process; + getProcesses(): Process[]; + getExecutableProcesses(): Process[]; + getMessageFlows(sourceId: string): MessageFlow[]; + getDataObjectById(referenceId: string): any; + getDataStoreById(referenceId: string): any; + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; + loadExtensions(activity: ElementBase): IExtension; + } + + class Process extends Element { + constructor(processDef: SerializableElement, context: ContextInstance); + get isExecutable(): boolean; + get counters(): completedCounters; + get lanes(): Lane[] | undefined; + get extensions(): IExtension; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string; + get execution(): ProcessExecution; + get status(): ProcessRunStatus | undefined; + get activityStatus(): ActivityStatus; + init(useAsExecutionId?: string): void; + run(runContent?: Record): void; + getState(): ProcessState; + recover(state?: ProcessState): Process; + shake(startId?: string): void; + signal(message: any): any; + cancelActivity(message: any): any; + sendMessage(message: any): void; + getActivityById(childId: string): T; + getActivities(): Activity[]; + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + getSequenceFlows(): SequenceFlow[]; + getLaneById(laneId: string): Lane | undefined; + getPostponed(filterFn: filterPostponed): Api[]; + } + + interface ProcessExecution { + get isSubProcess(): boolean; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get executionId(): string; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): ActivityStatus; + execute(executeMessage: ElementBrokerMessage): void; + getPostponed(filterFn: filterPostponed): Api[]; + getActivities(): Activity[]; + getActivityById(activityId: string): T; + getSequenceFlows(): SequenceFlow[]; + getApi(message?: ElementBrokerMessage): Api; + } + + class Lane extends ElementBase { + constructor(process: Process, laneDefinition: SerializableElement); + /** Process broker */ + get broker(): Broker; + get process(): Process; + } + + class SequenceFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isDefault(): boolean; + get isSequenceFlow(): boolean; + get counters(): { take: number; discard: number; looped: number }; + take(content?: any): boolean; + discard(content?: any): void; + shake(message: any): number; + getCondition(): ISequenceFlowCondition | null; + createMessage(override?: any): object; + /** + * Evaluate flow + * Executes condition if any, default flow is + * @param fromMessage Activity message + * @param callback Callback with evaluation result, if truthy flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + getState(): SequenceFlowState | undefined; + } + + class MessageFlow extends Element { + constructor(flowDef: SerializableElement, context: ContextInstance); + get source(): MessageFlowReference; + get target(): MessageFlowReference; + get counters(): { messages: number }; + activate(): void; + deactivate(): void; + getState(): MessageFlowState | undefined; + } + + class Association extends Element { + constructor(associationDef: SerializableElement, context: ContextInstance); + get sourceId(): string; + get targetId(): string; + get isAssociation(): boolean; + get counters(): { take: number; discard: number }; + take(content?: any): boolean; + discard(content?: any): boolean; + getState(): AssociationState | undefined; + } + interface ElementBroker extends Broker { + get owner(): T; + } + + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + } + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + type filterPostponed = (elementApi: any) => boolean; + + enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', + } + + /** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ + enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', + } + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; + } + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + + export {}; +} + +//# sourceMappingURL=index.d.ts.map +// Augmentations for the dts-buddy-generated bundle in types/index.d.ts. +// These interfaces add the prototype getters defined via Object.defineProperties +// in src/, which TypeScript cannot pick up from constructor functions. +// The build script (scripts/build-types.js) appends this file to types/index.d.ts. + +declare module 'bpmn-elements' { + interface Activity { + get counters(): { taken: number; discarded: number }; + get execution(): import('types').ActivityExecution | undefined; + get executionId(): string | undefined; + get extensions(): import('types').IExtension; + get bpmnIo(): import('types').IExtension | undefined; + get formatter(): any; + get isRunning(): boolean; + get outbound(): import('types').SequenceFlow[]; + get inbound(): import('types').SequenceFlow[]; + get isEnd(): boolean; + get isStart(): boolean; + get isSubProcess(): boolean; + get isTransaction(): boolean; + get isMultiInstance(): boolean; + get isThrowing(): boolean; + get isCatching(): boolean; + get isForCompensation(): boolean; + get isParallelJoin(): boolean; + get triggeredByEvent(): boolean; + get attachedTo(): import('types').Activity | null; + get lane(): import('types').Lane | undefined; + get eventDefinitions(): any[]; + /** Parent element process or sub process reference */ + get parentElement(): import('types').Process | import('types').Activity; + get initialized(): boolean; + } + + interface Process { + get counters(): { completed: number; discarded: number }; + get lanes(): import('types').Lane[] | undefined; + get extensions(): import('types').IExtension | undefined; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string | undefined; + get execution(): import('types').ProcessExecution | undefined; + get status(): string | undefined; + get activityStatus(): string; + } + + interface Definition { + get counters(): { completed: number; discarded: number }; + get execution(): import('types').DefinitionExecution | undefined; + get executionId(): string | undefined; + get isRunning(): boolean; + get status(): string | undefined; + get stopped(): boolean; + get activityStatus(): string; + } + + interface Environment { + get variables(): Record; + get services(): Record; + set services(value: Record); + } + + interface ContextInstance { + /** Process or sub-process activity that owns this context */ + get owner(): import('types').Process | import('types').Activity | undefined; + } + + interface ProcessExecution { + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + + interface DefinitionExecution { + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get processes(): import('types').Process[]; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + + interface ActivityExecution { + get completed(): boolean; + } } diff --git a/types/index.d.ts.map b/types/index.d.ts.map new file mode 100644 index 00000000..e3314e57 --- /dev/null +++ b/types/index.d.ts.map @@ -0,0 +1,267 @@ +{ + "version": 3, + "file": "index.d.ts", + "names": [ + "Activity", + "K_ACTIVITY_DEF", + "K_FLOWS", + "K_FLAGS", + "K_EXEC", + "K_EVENT_DEFINITIONS", + "K_CONSUMING_RUN_Q", + "Context", + "ExtensionsMapper", + "Extensions", + "K_OWNER", + "Definition", + "Environment", + "DummyLogger", + "K_SERVICES", + "K_VARIABLES", + "Escalation", + "Message", + "Lane", + "K_PROCESS", + "Process", + "K_LANES", + "Properties", + "K_PROPERTIES", + "ServiceImplementation", + "Signal", + "StandardLoopCharacteristics", + "Timers", + "RegisteredTimers", + "K_EXECUTING", + "K_TIMER_API", + "ActivityError", + "RunError", + "CallActivity", + "ReceiveTask", + "ScriptTask", + "ServiceTask", + "SignalTask", + "SubProcess", + "Task", + "Transaction", + "Association", + "MessageFlow", + "K_SOURCE_ELEMENT", + "SequenceFlow", + "ElementBase", + "Element", + "Api", + "ContextInstance", + "ProcessExecution", + "ElementBroker", + "signalMessage", + "ElementMessageContent", + "ElementBrokerMessage", + "ElementParent", + "ISequenceFlowCondition", + "IActivityBehaviour", + "Extension", + "IExtension", + "IExpressions", + "EnvironmentSettings", + "EnvironmentOptions", + "startActivityFilterOptions", + "filterPostponed", + "ProcessRunStatus", + "ActivityStatus", + "ElementState", + "EnvironmentState", + "completedCounters", + "ActivityExecutionState", + "ActivityState", + "SequenceFlowState", + "MessageFlowState", + "AssociationState", + "ProcessExecutionState", + "ProcessState", + "DefinitionExecutionState", + "DefinitionState", + "runCallback", + "MessageFlowReference", + "LoggerFactory", + "ILogger", + "wrappedSetTimeout", + "wrappedClearTimeout", + "Timer", + "RegisteredTimer", + "ITimers", + "IScripts", + "Script", + "K_ACTIVATED", + "K_COMPLETED", + "K_CONSUMING", + "K_COUNTERS", + "K_EXECUTE_MESSAGE", + "K_EXECUTION", + "K_EXTENSIONS", + "K_MESSAGE_HANDLERS", + "K_MESSAGE_Q", + "K_REFERENCE_ELEMENT", + "K_REFERENCE_INFO", + "K_STATE_MESSAGE", + "K_STATUS", + "K_STOPPED", + "BoundaryEvent", + "EndEvent", + "IntermediateCatchEvent", + "IntermediateThrowEvent", + "StartEvent", + "CancelEventDefinition", + "CompensateEventDefinition", + "K_ASSOCIATIONS", + "K_COMPENSATE_Q", + "ConditionalEventDefinition", + "ErrorEventDefinition", + "EscalationEventDefinition", + "K_REFERENCE", + "LinkEventDefinition", + "MessageEventDefinition", + "SignalEventDefinition", + "TerminateEventDefinition", + "TimerEventDefinition", + "K_TIMER", + "K_TIMER_CONTENT", + "Scripts", + "EventBasedGateway", + "ExclusiveGateway", + "InclusiveGateway", + "ParallelGateway", + "ScriptCondition", + "ExpressionCondition", + "BoundaryEventBehaviour", + "K_SHOVELS", + "K_ATTACHED_TAGS", + "K_COMPLETE_CONTENT", + "EndEventBehaviour", + "IntermediateCatchEventBehaviour", + "IntermediateThrowEventBehaviour", + "StartEventBehaviour", + "EventBasedGatewayBehaviour", + "ExclusiveGatewayBehaviour", + "InclusiveGatewayBehaviour", + "ParallelGatewayBehaviour", + "PeerMonitor", + "K_TARGETS", + "CallActivityBehaviour", + "ReceiveTaskBehaviour", + "ScriptTaskBehaviour", + "ServiceTaskBehaviour", + "SignalTaskBehaviour", + "SubProcessBehaviour", + "K_EXECUTIONS", + "K_ON_EXECUTION_COMPLETED", + "TaskBehaviour", + "K_PARENT", + "K_ELEMENTS", + "K_TRACKER", + "K_ACTIVITY_Q" + ], + "sources": [ + "../src/activity/Activity.js", + "../src/Context.js", + "../src/definition/Definition.js", + "types.d.ts", + "../src/Environment.js", + "../src/activity/Escalation.js", + "../src/activity/Message.js", + "../src/process/Lane.js", + "../src/process/Process.js", + "../src/io/Properties.js", + "../src/tasks/ServiceImplementation.js", + "../src/activity/Signal.js", + "../src/tasks/StandardLoopCharacteristics.js", + "../src/Timers.js", + "../src/error/Errors.js", + "../src/tasks/CallActivity.js", + "../src/tasks/ReceiveTask.js", + "../src/tasks/ScriptTask.js", + "../src/tasks/ServiceTask.js", + "../src/tasks/SignalTask.js", + "../src/tasks/SubProcess.js", + "../src/tasks/Task.js", + "../src/tasks/Transaction.js", + "../src/flows/MessageFlow.js", + "../src/Api.js", + "interfaces.d.ts", + "../src/constants.js", + "../src/events/BoundaryEvent.js", + "../src/events/EndEvent.js", + "../src/events/IntermediateCatchEvent.js", + "../src/events/IntermediateThrowEvent.js", + "../src/events/StartEvent.js", + "../src/eventDefinitions/CancelEventDefinition.js", + "../src/eventDefinitions/CompensateEventDefinition.js", + "../src/eventDefinitions/ConditionalEventDefinition.js", + "../src/eventDefinitions/ErrorEventDefinition.js", + "../src/eventDefinitions/EscalationEventDefinition.js", + "../src/eventDefinitions/LinkEventDefinition.js", + "../src/eventDefinitions/MessageEventDefinition.js", + "../src/eventDefinitions/SignalEventDefinition.js", + "../src/eventDefinitions/TerminateEventDefinition.js", + "../src/eventDefinitions/TimerEventDefinition.js", + "../src/Scripts.js", + "../src/gateways/EventBasedGateway.js", + "../src/gateways/ExclusiveGateway.js", + "../src/gateways/InclusiveGateway.js", + "../src/gateways/ParallelGateway.js", + "../src/condition.js", + "../src/process/ProcessExecution.js" + ], + "sourcesContent": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "mappings": ";;;;;;;;;iBA0BgBA,QAAQA;cAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;;;;;;;;;;;;;;iBCCCC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6UtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCWGC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCqMLC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UCFvBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;iBCLOC,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAVC,OAAOA;;;;;;;;;;;iBH+VVC,IAAIA;cAAJA,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;OI/VnBC,SAASA;;;;;;;;;;;;;;;;;;;;iBJ+SMC,OAAOA;cAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OKvStBC,OAAOA;iBCHWC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;OAF5BC,YAAYA;iBCDMC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;iBCFrBC,MAAMA;;;;;;;iBCENC,2BAA2BA;iBCGnCC,MAAMA;cAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;cCCJC,aAAaA;;;;;;;;;;;;;cAebC,QAAQA;;;iBCbGC,YAAYA;iBCAZC,WAAWA;iBCCXC,UAAUA;iBCDVC,WAAWA;iBCAXC,UAAUA;iBCGVC,UAAUA;iBCJVC,IAAIA;iBCDJC,WAAWA;;;;;iBnBoYdC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAVXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OoBtX1BC,gBAAgBA;;;;;iBpBgWDC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAjQHC,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YqB9DrBC,GAAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QrB4LEC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4FXC,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YsBzUhBC,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YASZC,wBAAwBA;;;;;;;;YAQxBC,eAAeA;;;;;;;;;OASpBC,WAAWA;;YAENC,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;OCvVlBC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OACfC,QAAQA;OACRC,SAASA;iBCHEC,aAAaA;iBCLbC,QAAQA;iBCARC,sBAAsBA;iBCAtBC,sBAAsBA;iBCAtBC,UAAUA;iBCFVC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,cAAcA;OADdC,cAAcA;iBCCIC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,WAAWA;iBCDOC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJtCC,OAAOA;OADPC,eAAeA;UCLLC,OAAOA;OAAPA,OAAOA;;;;iBCICC,iBAAiBA;iBCDjBC,gBAAgBA;iBCAhBC,gBAAgBA;iBCOhBC,eAAeA;cAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UCFvBC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;iBpB1BX1B,aAAaA;iBAIrB2B,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OANhCC,SAASA;OAFTC,eAAeA;OACfC,kBAAkBA;iBCFA7B,QAAQA;iBAIhB8B,iBAAiBA;cAAjBA,iBAAiBA;;;;;;;;;iBCJT7B,sBAAsBA;iBAI9B8B,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;;iBCJvB7B,sBAAsBA;iBAI9B8B,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;iBCJvB7B,UAAUA;iBAIlB8B,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;U/BiBnBzI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BXVmF,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;QvB0FEvD,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;YsBpYPS,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;iBOpVPoB,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,cAAcA;OADdC,cAAcA;iBCCIC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,WAAWA;iBCDOC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJtCC,OAAOA;OADPC,eAAeA;OfLRjC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OAEfE,SAASA;QvBwFQzD,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;;;;U4C9XhBuF,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;U/CVnBjI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;YyBTE4C,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;iBtB+CV/C,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAVXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OoBtX1BC,gBAAgBA;;;;;iBpBgWDC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAjQHC,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YqB9DrBC,GAAGA;;;;;;;;;;;;;;;;;;;;QrBkKEnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YsB7VAgC,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCvVlBC,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;;;;;;;U1BeZpG,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;;;;iB2CPCsH,iBAAiBA;iBAIzBc,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;iBCLlBb,gBAAgBA;iBAIxBc,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCJjBb,gBAAgBA;iBAIxBc,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCGjBb,eAAeA;cAAfA,eAAeA;;;;iBAoCvBc,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;;;;;;;;;;;;UAqI/BC,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;U9CzJJ9I,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BXVmF,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OAGf2C,SAASA;QvBuFQlG,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;YsBpYPS,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;iBVnVPvD,YAAYA;iBAIpB+G,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;iBCJb9G,WAAWA;iBASnB+G,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;iBCRZ9G,UAAUA;iBAIlB+G,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;iBCLX9G,WAAWA;iBAInB+G,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;iBCJZ9G,UAAUA;iBAIlB+G,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;iBCDX9G,UAAUA;iBAqBlB+G,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;;;OAxB7BC,YAAYA;OACZC,wBAAwBA;iBCFNhH,IAAIA;iBAIZiH,aAAaA;cAAbA,aAAaA;;;;;;;;iBCLLhH,WAAWA;;;;;;;UtBwBnBxC,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BXVmF,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAElBE,mBAAmBA;OAEnBE,eAAeA;OACfC,QAAQA;OACRC,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OsBHhBmD,QAAQA;OADRC,UAAUA;OAEVC,SAASA;OAHTC,YAAYA;Q7C6FY/G,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;YsBpYPS,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA", + "ignoreList": [] +} \ No newline at end of file diff --git a/types/types.d.ts b/types/types.d.ts index f74e217c..f2cda12c 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1,5 +1,7 @@ import { Broker } from 'smqp'; import { SerializableContext, SerializableElement } from 'moddle-context-serializer'; +export { Activity } from '../src/activity/Activity.js'; +import { Activity } from '../src/activity/Activity.js'; import { ElementBroker, @@ -413,46 +415,8 @@ export declare class MessageFormatter { format(message: MessageElement, callback: CallableFunction): void; } -export declare class Activity extends Element { - constructor(behaviour: IActivityBehaviour, activityDef: SerializableElement, context: ContextInstance); - get Behaviour(): IActivityBehaviour; - get stopped(): boolean; - get status(): ActivityRunStatus | undefined; - get context(): ContextInstance; - get counters(): { taken: number; discarded: number }; - get execution(): ActivityExecution; - get executionId(): string; - get extensions(): IExtension; - get isRunning(): boolean; - get outbound(): SequenceFlow[]; - get inbound(): SequenceFlow[]; - get isEnd(): boolean; - get isStart(): boolean; - get isSubProcess(): boolean; - get isMultiInstance(): boolean; - get isThrowing(): boolean; - get isForCompensation(): boolean; - get isParallelJoin(): boolean; - get triggeredByEvent(): boolean; - get attachedTo(): Activity; - get eventDefinitions(): EventDefinition[]; - get formatter(): MessageFormatter; - /** Parent element process or sub process reference */ - get parentElement(): Process | Activity; - activate(): void; - deactivate(): void; - init(initContent?: any): void; - run(runContent?: any): void; - discard(discardContent?: any): void; - next(): ElementBrokerMessage; - shake(): void; - evaluateOutbound( - fromMessage: ElementBrokerMessage, - discardRestAtTake: boolean, - callback: (err: Error, evaluationResult: any) => void - ): void; - getState(): ActivityState | undefined; -} +// Activity is generated from JSDoc in src/activity/Activity.js. Re-exporting keeps +// existing `import('types').Activity` JSDoc references resolving. export declare class ActivityError extends Error { type: string; From 6469ec01daec3c19090e5a594611c441ab49ae8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 10 May 2026 11:58:31 +0200 Subject: [PATCH 12/31] no more default exports --- CHANGELOG.md | 4 + dist/Context.js | 12 +- dist/Environment.js | 7 +- dist/EventBroker.js | 2 +- dist/Expressions.js | 7 +- dist/activity/Activity.js | 10 +- dist/activity/ActivityExecution.js | 4 +- dist/activity/Dummy.js | 2 +- dist/activity/Escalation.js | 2 +- dist/activity/ExecutionScope.js | 2 +- dist/activity/Message.js | 2 +- dist/activity/Signal.js | 2 +- dist/condition.js | 5 +- dist/definition/Definition.js | 10 +- dist/definition/DefinitionExecution.js | 2 +- dist/error/BpmnError.js | 2 +- .../eventDefinitions/CancelEventDefinition.js | 2 +- .../CompensateEventDefinition.js | 2 +- .../ConditionalEventDefinition.js | 2 +- dist/eventDefinitions/ErrorEventDefinition.js | 2 +- .../EscalationEventDefinition.js | 7 +- .../EventDefinitionExecution.js | 2 +- dist/eventDefinitions/LinkEventDefinition.js | 2 +- .../MessageEventDefinition.js | 7 +- .../eventDefinitions/SignalEventDefinition.js | 7 +- .../TerminateEventDefinition.js | 2 +- dist/eventDefinitions/TimerEventDefinition.js | 2 +- dist/eventDefinitions/index.js | 41 +- dist/events/BoundaryEvent.js | 11 +- dist/events/EndEvent.js | 11 +- dist/events/IntermediateCatchEvent.js | 11 +- dist/events/IntermediateThrowEvent.js | 11 +- dist/events/StartEvent.js | 11 +- dist/events/index.js | 21 +- dist/flows/Association.js | 2 +- dist/flows/MessageFlow.js | 2 +- dist/flows/SequenceFlow.js | 2 - dist/flows/index.js | 13 +- dist/gateways/EventBasedGateway.js | 7 +- dist/gateways/ExclusiveGateway.js | 7 +- dist/gateways/InclusiveGateway.js | 7 +- dist/gateways/ParallelGateway.js | 7 +- dist/gateways/index.js | 17 +- dist/getPropertyValue.js | 2 +- dist/index.js | 85 +- dist/io/BpmnIO.js | 2 +- dist/io/EnvironmentDataObject.js | 2 +- dist/io/EnvironmentDataStore.js | 2 +- dist/io/EnvironmentDataStoreReference.js | 2 +- dist/io/InputOutputSpecification.js | 13 +- dist/io/Properties.js | 15 +- dist/process/Lane.js | 2 +- dist/process/Process.js | 12 +- dist/process/ProcessExecution.js | 3 +- dist/tasks/CallActivity.js | 7 +- dist/tasks/LoopCharacteristics.js | 2 +- dist/tasks/ReceiveTask.js | 7 +- dist/tasks/ScriptTask.js | 11 +- dist/tasks/ServiceImplementation.js | 7 +- dist/tasks/ServiceTask.js | 7 +- dist/tasks/SignalTask.js | 7 +- dist/tasks/StandardLoopCharacteristics.js | 7 +- dist/tasks/SubProcess.js | 15 +- dist/tasks/Task.js | 7 +- dist/tasks/Transaction.js | 7 +- dist/tasks/index.js | 34 +- eslint.config.js | 1 + package.json | 7 +- scripts/build-types.js | 17 +- src/Context.js | 8 +- src/Environment.js | 4 +- src/EventBroker.js | 2 +- src/Expressions.js | 5 +- src/activity/Activity.js | 4 +- src/activity/ActivityExecution.js | 4 +- src/activity/Dummy.js | 2 +- src/activity/Escalation.js | 2 +- src/activity/ExecutionScope.js | 2 +- src/activity/Message.js | 2 +- src/activity/Signal.js | 2 +- src/condition.js | 3 +- src/definition/Definition.js | 5 +- src/definition/DefinitionExecution.js | 2 +- src/error/BpmnError.js | 2 +- src/eventDefinitions/CancelEventDefinition.js | 2 +- .../CompensateEventDefinition.js | 2 +- .../ConditionalEventDefinition.js | 2 +- src/eventDefinitions/ErrorEventDefinition.js | 2 +- .../EscalationEventDefinition.js | 4 +- .../EventDefinitionExecution.js | 2 +- src/eventDefinitions/LinkEventDefinition.js | 2 +- .../MessageEventDefinition.js | 4 +- src/eventDefinitions/SignalEventDefinition.js | 4 +- .../TerminateEventDefinition.js | 2 +- src/eventDefinitions/TimerEventDefinition.js | 2 +- src/eventDefinitions/index.js | 21 +- src/events/BoundaryEvent.js | 6 +- src/events/EndEvent.js | 6 +- src/events/IntermediateCatchEvent.js | 6 +- src/events/IntermediateThrowEvent.js | 6 +- src/events/StartEvent.js | 6 +- src/events/index.js | 10 +- src/flows/Association.js | 2 +- src/flows/MessageFlow.js | 2 +- src/flows/SequenceFlow.js | 2 - src/flows/index.js | 7 +- src/gateways/EventBasedGateway.js | 4 +- src/gateways/ExclusiveGateway.js | 4 +- src/gateways/InclusiveGateway.js | 4 +- src/gateways/ParallelGateway.js | 4 +- src/gateways/index.js | 8 +- src/getPropertyValue.js | 2 +- src/index.js | 38 +- src/io/BpmnIO.js | 2 +- src/io/EnvironmentDataObject.js | 2 +- src/io/EnvironmentDataStore.js | 2 +- src/io/EnvironmentDataStoreReference.js | 2 +- src/io/InputOutputSpecification.js | 4 +- src/io/Properties.js | 4 +- src/process/Lane.js | 2 +- src/process/Process.js | 4 +- src/process/ProcessExecution.js | 4 +- src/tasks/CallActivity.js | 4 +- src/tasks/LoopCharacteristics.js | 2 +- src/tasks/ReceiveTask.js | 4 +- src/tasks/ScriptTask.js | 6 +- src/tasks/ServiceImplementation.js | 5 +- src/tasks/ServiceTask.js | 4 +- src/tasks/SignalTask.js | 4 +- src/tasks/StandardLoopCharacteristics.js | 5 +- src/tasks/SubProcess.js | 6 +- src/tasks/Task.js | 4 +- src/tasks/Transaction.js | 5 +- src/tasks/index.js | 17 +- test/Api-test.js | 3 +- test/Context-test.js | 4 +- test/Environment-test.js | 2 +- test/activity-api-test.js | 2 +- test/activity/Activity-test.js | 8 +- test/activity/ActivityExecution-test.js | 12 +- test/activity/ExecutionScope-test.js | 4 +- test/activity/activity-run-test.js | 6 +- test/definition/Definition-test.js | 2 +- test/definition/DefinitionExecution-test.js | 4 +- test/error/BpmnError-test.js | 5 +- .../CancelEventDefinition-test.js | 4 +- .../CompensateEventDefinition-test.js | 12 +- .../ConditionalEventDefinition-test.js | 4 +- .../ErrorEventDefinition-test.js | 6 +- .../EscalationEventDefinition-test.js | 6 +- .../EventDefinitionExecution-test.js | 2 +- .../LinkEventDefinition-test.js | 4 +- .../MessageEventDefinition-test.js | 6 +- .../SignalEventDefinition-test.js | 9 +- .../TerminateEventDefinition-test.js | 4 +- .../TimerEventDefinition-test.js | 4 +- test/events/BoundaryEvent-test.js | 10 +- test/events/EndEvent-test.js | 4 +- test/events/IntermediateCatchEvent-test.js | 2 +- test/events/StartEvent-test.js | 4 +- test/expressions-test.js | 2 +- test/feature/Definition-feature.js | 3 +- test/feature/EventBasedGateway-feature.js | 2 +- test/feature/activity-feature.js | 3 +- test/feature/activity-io-feature.js | 18 +- test/feature/activity-status-feature.js | 3 +- test/feature/ad-hoc-subprocess-feature.js | 2 +- .../feature/backward-compatability-feature.js | 2 +- test/feature/call-activity-feature.js | 3 +- test/feature/compensation-feature.js | 2 +- test/feature/conditional-event-feature.js | 2 +- test/feature/definition-output-feature.js | 2 +- test/feature/dummy-feature.js | 2 +- test/feature/environment-feature.js | 3 +- test/feature/errors-feature.js | 5 +- test/feature/escalation-feature.js | 2 +- test/feature/expression-feature.js | 2 +- test/feature/extension-feature.js | 3 +- test/feature/format-feature.js | 2 +- test/feature/io-feature.js | 2 +- test/feature/issues/issues-feature.js | 2 +- test/feature/messaging-feature.js | 2 +- test/feature/multiple-startevent-feature.js | 2 +- test/feature/noExecutableProcess-feature.js | 3 +- test/feature/outbound-flows-feature.js | 2 +- test/feature/performance-feature.js | 2 +- test/feature/recover-resume-feature.js | 2 +- test/feature/script-feature.js | 2 +- test/feature/sequence-flow-feature.js | 4 +- test/feature/service-task-feature.js | 2 +- test/feature/shake-feature.js | 2 +- test/feature/signal-feature.js | 2 +- test/feature/stop-and-resume-feature.js | 2 +- test/feature/sub-process-feature.js | 2 +- test/feature/task-loop-feature.js | 2 +- test/feature/timers-feature.js | 5 +- test/feature/transaction-feature.js | 2 +- test/flows/Association-test.js | 4 +- test/flows/MessageFlow-test.js | 4 +- test/flows/SequenceFlow-test.js | 4 +- test/getPropertyValue-test.js | 3 +- test/helpers/testHelpers.js | 4 +- test/io/DataObject-test.js | 4 +- test/io/InputOutputSpecification-test.js | 2 +- test/io/Properties-test.js | 4 +- test/process/Process-test.js | 2 +- test/process/ProcessExecution-test.js | 26 +- test/tasks/LoopCharacteristics-test.js | 4 +- test/tasks/ReceiveTask-test.js | 4 +- test/tasks/ServiceTask-test.js | 2 +- test/tasks/SubProcess-test.js | 4 +- test/tasks/Transaction-test.js | 2 +- test/tasks/isForCompensation-test.js | 4 +- types/index.d.ts | 8030 ++++++++++------- types/index.d.ts.map | 31 +- types/interfaces.d.ts | 355 - types/types.d.ts | 766 +- 217 files changed, 5555 insertions(+), 4825 deletions(-) delete mode 100644 types/interfaces.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0ddc74..607a39cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## Unreleased - fix `Activity.recover()` to return the activity when called without state +- expose throwable error classes via new `bpmn-elements/errors` subpath: `import { ActivityError, BpmnError, RunError } from 'bpmn-elements/errors'` (the `BpmnError` activity factory remains the named export of `bpmn-elements`) +- drop default exports across all implementation files in favour of named exports — internal-facing churn only, the package's public exports map (`bpmn-elements`, `bpmn-elements/events`, `…/eventDefinitions`, `…/flows`, `…/gateways`, `…/tasks`) is unchanged +- replace hand-rolled class declarations in `types/types.d.ts` with re-exports from the implementation files — the type definitions track the JSDoc-driven source rather than living in parallel +- strip the duplicate `export function Foo(...)` declarations that tsc emits alongside `export class Foo` for constructor-function patterns — the bundled `Definition`, `Activity`, `Process`, etc. are now plain class declarations that merge cleanly with the property augmentations ### Types diff --git a/dist/Context.js b/dist/Context.js index 72a34db8..83d0c50f 100644 --- a/dist/Context.js +++ b/dist/Context.js @@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Context; -var _BpmnIO = _interopRequireDefault(require("./io/BpmnIO.js")); -var _Environment = _interopRequireDefault(require("./Environment.js")); +exports.Context = Context; +exports.ContextInstance = ContextInstance; +var _BpmnIO = require("./io/BpmnIO.js"); +var _Environment = require("./Environment.js"); var _shared = require("./shared.js"); var _constants = require("./constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_OWNER = Symbol.for('owner'); /** @@ -17,7 +17,7 @@ const K_OWNER = Symbol.for('owner'); * @param {import('types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted */ function Context(definitionContext, environment) { - environment = environment ? environment.clone() : new _Environment.default(); + environment = environment ? environment.clone() : new _Environment.Environment(); return new ContextInstance(definitionContext, environment); } @@ -304,7 +304,7 @@ ContextInstance.prototype.getStartActivities = function getStartActivities(filte * @param {import('types').ElementBase} activity */ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { - const io = new _BpmnIO.default(activity, this); + const io = new _BpmnIO.BpmnIO(activity, this); const extensions = this.extensionsMapper.get(activity); if (io.hasIo) extensions.extensions.push(io); if (!extensions.extensions.length) return; diff --git a/dist/Environment.js b/dist/Environment.js index 89431e30..2692bdec 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -3,11 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Environment; -var _Expressions = _interopRequireDefault(require("./Expressions.js")); +exports.Environment = Environment; +var _Expressions = require("./Expressions.js"); var _Scripts = require("./Scripts.js"); var _Timers = require("./Timers.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_SERVICES = Symbol.for('services'); const K_VARIABLES = Symbol.for('variables'); const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', 'scripts', 'services', 'settings', 'timers', 'variables']); @@ -19,7 +18,7 @@ const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', */ function Environment(options = {}) { this.options = validateOptions(options); - this.expressions = options.expressions || (0, _Expressions.default)(); + this.expressions = options.expressions || (0, _Expressions.Expressions)(); this.extensions = options.extensions; this.output = options.output || {}; this.scripts = options.scripts || new _Scripts.Scripts(); diff --git a/dist/EventBroker.js b/dist/EventBroker.js index 2d29f5de..7b8ef0ed 100644 --- a/dist/EventBroker.js +++ b/dist/EventBroker.js @@ -115,7 +115,7 @@ function ExecutionBroker(brokerOwner, prefix, onBrokerReturn) { function EventBroker(brokerOwner, options, onBrokerReturn) { this.options = options; this.eventPrefix = options.prefix; - const broker = this.broker = (0, _smqp.Broker)(brokerOwner); + const broker = this.broker = new _smqp.Broker(brokerOwner); broker.assertExchange('event', 'topic', options); broker.on('return', onBrokerReturn ? onBrokerReturn.bind(brokerOwner) : this._onBrokerReturnFn.bind(this)); this.on = this.on.bind(this); diff --git a/dist/Expressions.js b/dist/Expressions.js index a4242b33..75bf7919 100644 --- a/dist/Expressions.js +++ b/dist/Expressions.js @@ -3,9 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Expressions; -var _getPropertyValue = _interopRequireDefault(require("./getPropertyValue.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } +exports.Expressions = Expressions; +var _getPropertyValue = require("./getPropertyValue.js"); const isExpressionPattern = /^\${(.+?)}$/; const expressionPattern = /\${(.+?)}/; function Expressions() { @@ -30,7 +29,7 @@ function resolveExpression(templatedString, context, expressionFnContext) { const n = Number(innerProperty); if (!isNaN(n)) return n; } - const contextValue = (0, _getPropertyValue.default)(context, innerProperty, expressionFnContext); + const contextValue = (0, _getPropertyValue.getPropertyValue)(context, innerProperty, expressionFnContext); if (expressionMatch.input === expressionMatch[0]) { return contextValue; } diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 28868cbb..1a30c8a8 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -4,8 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Activity = Activity; -exports.default = void 0; -var _ActivityExecution = _interopRequireDefault(require("./ActivityExecution.js")); +var _ActivityExecution = require("./ActivityExecution.js"); var _shared = require("../shared.js"); var _Api = require("../Api.js"); var _EventBroker = require("../EventBroker.js"); @@ -14,7 +13,6 @@ var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); var _outboundEvaluator = require("./outbound-evaluator.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_ACTIVITY_DEF = Symbol.for('activityDefinition'); const K_CONSUMING_RUN_Q = Symbol.for('run queue consumer'); const K_EVENT_DEFINITIONS = Symbol.for('eventDefinitions'); @@ -22,7 +20,7 @@ const K_EXEC = Symbol.for('exec'); const K_FLAGS = Symbol.for('flags'); const K_FLOWS = Symbol.for('flows'); const K_FORMATTER = Symbol.for('formatter'); -var _default = exports.default = Activity; + /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param {import('types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution @@ -384,7 +382,7 @@ Activity.prototype.recover = function recover(state) { ...state.counters }; if (state.execution) { - exec.set('execution', new _ActivityExecution.default(this, this.context).recover(state.execution)); + exec.set('execution', new _ActivityExecution.ActivityExecution(this, this.context).recover(state.execution)); } this.broker.recover(state.broker); return this; @@ -811,7 +809,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, const exec = this[K_EXEC]; let execution = exec.get('execution'); if (!execution) { - execution = new _ActivityExecution.default(this, this.context); + execution = new _ActivityExecution.ActivityExecution(this, this.context); exec.set('execution', execution); } this.broker.getQueue('execution-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onExecutionMessage, { diff --git a/dist/activity/ActivityExecution.js b/dist/activity/ActivityExecution.js index b95fbc87..7fd1b6a3 100644 --- a/dist/activity/ActivityExecution.js +++ b/dist/activity/ActivityExecution.js @@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = void 0; +exports.ActivityExecution = ActivityExecution; var _Api = require("../Api.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); const K_EXECUTE_Q = Symbol.for('executeQ'); const K_POSTPONED = Symbol.for('postponed'); -var _default = exports.default = ActivityExecution; + /** * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour * and drives the execute message flow over the activity broker. diff --git a/dist/activity/Dummy.js b/dist/activity/Dummy.js index f2692718..dff7325c 100644 --- a/dist/activity/Dummy.js +++ b/dist/activity/Dummy.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = DummyActivity; +exports.DummyActivity = DummyActivity; var _messageHelper = require("../messageHelper.js"); function DummyActivity(activityDef) { const { diff --git a/dist/activity/Escalation.js b/dist/activity/Escalation.js index 0370b71f..b0aa72a4 100644 --- a/dist/activity/Escalation.js +++ b/dist/activity/Escalation.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Escalation; +exports.Escalation = Escalation; function Escalation(signalDef, context) { const { id, diff --git a/dist/activity/ExecutionScope.js b/dist/activity/ExecutionScope.js index 7f2657b2..8b8efd39 100644 --- a/dist/activity/ExecutionScope.js +++ b/dist/activity/ExecutionScope.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = ExecutionScope; +exports.ExecutionScope = ExecutionScope; var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); function ExecutionScope(activity, initMessage) { diff --git a/dist/activity/Message.js b/dist/activity/Message.js index 01151366..440adfdc 100644 --- a/dist/activity/Message.js +++ b/dist/activity/Message.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Message; +exports.Message = Message; function Message(messageDef, context) { const { id, diff --git a/dist/activity/Signal.js b/dist/activity/Signal.js index 3749cac4..bd2f2533 100644 --- a/dist/activity/Signal.js +++ b/dist/activity/Signal.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Signal; +exports.Signal = Signal; function Signal(signalDef, context) { const { id, diff --git a/dist/condition.js b/dist/condition.js index e379fdc5..8be0857e 100644 --- a/dist/condition.js +++ b/dist/condition.js @@ -5,8 +5,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.ExpressionCondition = ExpressionCondition; exports.ScriptCondition = ScriptCondition; -var _ExecutionScope = _interopRequireDefault(require("./activity/ExecutionScope.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } +var _ExecutionScope = require("./activity/ExecutionScope.js"); /** * Script condition * @param {import('types').ElementBase} owner @@ -28,7 +27,7 @@ function ScriptCondition(owner, script, language) { ScriptCondition.prototype.execute = function execute(message, callback) { const owner = this._owner; try { - return this._script.execute((0, _ExecutionScope.default)(owner, message), callback); + return this._script.execute((0, _ExecutionScope.ExecutionScope)(owner, message), callback); } catch (err) { if (!callback) throw err; owner.logger.error(`<${owner.id}>`, err); diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index 4fca34f5..af1654d8 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -4,16 +4,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Definition = Definition; -exports.default = void 0; -var _DefinitionExecution = _interopRequireDefault(require("./DefinitionExecution.js")); +var _DefinitionExecution = require("./DefinitionExecution.js"); var _Api = require("../Api.js"); var _EventBroker = require("../EventBroker.js"); var _shared = require("../shared.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -var _default = exports.default = Definition; /** * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and * mediates inter-process messaging. @@ -66,6 +63,7 @@ function Definition(context, options) { emit, emitFatal } = (0, _EventBroker.DefinitionBroker)(this, onBrokerReturn); + /** @type {import('smqp').Broker} */ this.broker = broker; this.on = on; this.once = once; @@ -216,7 +214,7 @@ Definition.prototype.recover = function recover(state) { } this.environment.recover(state.environment); if (state.execution) { - exec.set('execution', new _DefinitionExecution.default(this, this.context).recover(state.execution)); + exec.set('execution', new _DefinitionExecution.DefinitionExecution(this, this.context).recover(state.execution)); } this.broker.recover(state.broker); return this; @@ -483,7 +481,7 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) consumerTag: '_definition-execution' }); if (!execution) { - execution = new _DefinitionExecution.default(this, this.context); + execution = new _DefinitionExecution.DefinitionExecution(this, this.context); exec.set('execution', execution); } if (executeMessage.fields.redelivered) { diff --git a/dist/definition/DefinitionExecution.js b/dist/definition/DefinitionExecution.js index aa0de5e9..42acb97d 100644 --- a/dist/definition/DefinitionExecution.js +++ b/dist/definition/DefinitionExecution.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = DefinitionExecution; +exports.DefinitionExecution = DefinitionExecution; var _Api = require("../Api.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); diff --git a/dist/error/BpmnError.js b/dist/error/BpmnError.js index 4fb88b4a..d0e64aed 100644 --- a/dist/error/BpmnError.js +++ b/dist/error/BpmnError.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = BpmnErrorActivity; +exports.BpmnErrorActivity = BpmnErrorActivity; function BpmnErrorActivity(errorDef, context) { const { id, diff --git a/dist/eventDefinitions/CancelEventDefinition.js b/dist/eventDefinitions/CancelEventDefinition.js index 1469e6df..c608e687 100644 --- a/dist/eventDefinitions/CancelEventDefinition.js +++ b/dist/eventDefinitions/CancelEventDefinition.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = CancelEventDefinition; +exports.CancelEventDefinition = CancelEventDefinition; var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); function CancelEventDefinition(activity, eventDefinition) { diff --git a/dist/eventDefinitions/CompensateEventDefinition.js b/dist/eventDefinitions/CompensateEventDefinition.js index 6562deb7..7254c959 100644 --- a/dist/eventDefinitions/CompensateEventDefinition.js +++ b/dist/eventDefinitions/CompensateEventDefinition.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = CompensateEventDefinition; +exports.CompensateEventDefinition = CompensateEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); diff --git a/dist/eventDefinitions/ConditionalEventDefinition.js b/dist/eventDefinitions/ConditionalEventDefinition.js index 8f98cce9..dacccb72 100644 --- a/dist/eventDefinitions/ConditionalEventDefinition.js +++ b/dist/eventDefinitions/ConditionalEventDefinition.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = ConditionalEventDefinition; +exports.ConditionalEventDefinition = ConditionalEventDefinition; var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); var _condition = require("../condition.js"); diff --git a/dist/eventDefinitions/ErrorEventDefinition.js b/dist/eventDefinitions/ErrorEventDefinition.js index 78008a8b..03108f09 100644 --- a/dist/eventDefinitions/ErrorEventDefinition.js +++ b/dist/eventDefinitions/ErrorEventDefinition.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = ErrorEventDefinition; +exports.ErrorEventDefinition = ErrorEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); diff --git a/dist/eventDefinitions/EscalationEventDefinition.js b/dist/eventDefinitions/EscalationEventDefinition.js index 4bdf5de5..f1a31b07 100644 --- a/dist/eventDefinitions/EscalationEventDefinition.js +++ b/dist/eventDefinitions/EscalationEventDefinition.js @@ -3,12 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = EscalationEventDefinition; -var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); +exports.EscalationEventDefinition = EscalationEventDefinition; +var _getPropertyValue = require("../getPropertyValue.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_REFERENCE = Symbol.for('reference'); function EscalationEventDefinition(activity, eventDefinition) { const { @@ -113,7 +112,7 @@ EscalationEventDefinition.prototype.executeThrow = function executeThrow(execute }; EscalationEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { const info = this[K_REFERENCE]; - if ((0, _getPropertyValue.default)(message, 'content.message.id') !== info.message.id) return; + if ((0, _getPropertyValue.getPropertyValue)(message, 'content.message.id') !== info.message.id) return; const output = message.content.message; /** @private */ this[_constants.K_COMPLETED] = true; diff --git a/dist/eventDefinitions/EventDefinitionExecution.js b/dist/eventDefinitions/EventDefinitionExecution.js index 32672b4f..ffb78d5c 100644 --- a/dist/eventDefinitions/EventDefinitionExecution.js +++ b/dist/eventDefinitions/EventDefinitionExecution.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = EventDefinitionExecution; +exports.EventDefinitionExecution = EventDefinitionExecution; var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKey = 'execute.completed') { diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index 9407b2d2..d1e46160 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = LinkEventDefinition; +exports.LinkEventDefinition = LinkEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); diff --git a/dist/eventDefinitions/MessageEventDefinition.js b/dist/eventDefinitions/MessageEventDefinition.js index 812ce2c0..a40e8397 100644 --- a/dist/eventDefinitions/MessageEventDefinition.js +++ b/dist/eventDefinitions/MessageEventDefinition.js @@ -3,12 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = MessageEventDefinition; -var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); +exports.MessageEventDefinition = MessageEventDefinition; +var _getPropertyValue = require("../getPropertyValue.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function MessageEventDefinition(activity, eventDefinition) { const { id, @@ -125,7 +124,7 @@ MessageEventDefinition.prototype.executeThrow = function executeThrow(executeMes return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); }; MessageEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { - if ((0, _getPropertyValue.default)(message, 'content.message.id') !== this[_constants.K_REFERENCE_INFO].message.id) return; + if ((0, _getPropertyValue.getPropertyValue)(message, 'content.message.id') !== this[_constants.K_REFERENCE_INFO].message.id) return; const { type, correlationId diff --git a/dist/eventDefinitions/SignalEventDefinition.js b/dist/eventDefinitions/SignalEventDefinition.js index ad2793e3..84e77aab 100644 --- a/dist/eventDefinitions/SignalEventDefinition.js +++ b/dist/eventDefinitions/SignalEventDefinition.js @@ -3,12 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = SignalEventDefinition; -var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); +exports.SignalEventDefinition = SignalEventDefinition; +var _getPropertyValue = require("../getPropertyValue.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function SignalEventDefinition(activity, eventDefinition) { const { id, @@ -127,7 +126,7 @@ SignalEventDefinition.prototype.executeThrow = function executeThrow(executeMess }; SignalEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { const info = this[_constants.K_REFERENCE_INFO]; - if ((0, _getPropertyValue.default)(message, 'content.message.id') !== info.message.id) return; + if ((0, _getPropertyValue.getPropertyValue)(message, 'content.message.id') !== info.message.id) return; /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); diff --git a/dist/eventDefinitions/TerminateEventDefinition.js b/dist/eventDefinitions/TerminateEventDefinition.js index 70cc3933..3d3565c7 100644 --- a/dist/eventDefinitions/TerminateEventDefinition.js +++ b/dist/eventDefinitions/TerminateEventDefinition.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = TerminateEventDefinition; +exports.TerminateEventDefinition = TerminateEventDefinition; var _messageHelper = require("../messageHelper.js"); function TerminateEventDefinition(activity, eventDefinition) { const { diff --git a/dist/eventDefinitions/TimerEventDefinition.js b/dist/eventDefinitions/TimerEventDefinition.js index ac2249d3..61938ce3 100644 --- a/dist/eventDefinitions/TimerEventDefinition.js +++ b/dist/eventDefinitions/TimerEventDefinition.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = TimerEventDefinition; +exports.TimerEventDefinition = TimerEventDefinition; var _piso = require("@0dep/piso"); var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); diff --git a/dist/eventDefinitions/index.js b/dist/eventDefinitions/index.js index 78dcfac1..c15a7d7e 100644 --- a/dist/eventDefinitions/index.js +++ b/dist/eventDefinitions/index.js @@ -6,71 +6,70 @@ Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "CancelEventDefinition", { enumerable: true, get: function () { - return _CancelEventDefinition.default; + return _CancelEventDefinition.CancelEventDefinition; } }); Object.defineProperty(exports, "CompensateEventDefinition", { enumerable: true, get: function () { - return _CompensateEventDefinition.default; + return _CompensateEventDefinition.CompensateEventDefinition; } }); Object.defineProperty(exports, "ConditionalEventDefinition", { enumerable: true, get: function () { - return _ConditionalEventDefinition.default; + return _ConditionalEventDefinition.ConditionalEventDefinition; } }); Object.defineProperty(exports, "ErrorEventDefinition", { enumerable: true, get: function () { - return _ErrorEventDefinition.default; + return _ErrorEventDefinition.ErrorEventDefinition; } }); Object.defineProperty(exports, "EscalationEventDefinition", { enumerable: true, get: function () { - return _EscalationEventDefinition.default; + return _EscalationEventDefinition.EscalationEventDefinition; } }); Object.defineProperty(exports, "LinkEventDefinition", { enumerable: true, get: function () { - return _LinkEventDefinition.default; + return _LinkEventDefinition.LinkEventDefinition; } }); Object.defineProperty(exports, "MessageEventDefinition", { enumerable: true, get: function () { - return _MessageEventDefinition.default; + return _MessageEventDefinition.MessageEventDefinition; } }); Object.defineProperty(exports, "SignalEventDefinition", { enumerable: true, get: function () { - return _SignalEventDefinition.default; + return _SignalEventDefinition.SignalEventDefinition; } }); Object.defineProperty(exports, "TerminateEventDefinition", { enumerable: true, get: function () { - return _TerminateEventDefinition.default; + return _TerminateEventDefinition.TerminateEventDefinition; } }); Object.defineProperty(exports, "TimerEventDefinition", { enumerable: true, get: function () { - return _TimerEventDefinition.default; + return _TimerEventDefinition.TimerEventDefinition; } }); -var _CancelEventDefinition = _interopRequireDefault(require("./CancelEventDefinition.js")); -var _CompensateEventDefinition = _interopRequireDefault(require("./CompensateEventDefinition.js")); -var _ConditionalEventDefinition = _interopRequireDefault(require("./ConditionalEventDefinition.js")); -var _ErrorEventDefinition = _interopRequireDefault(require("./ErrorEventDefinition.js")); -var _EscalationEventDefinition = _interopRequireDefault(require("./EscalationEventDefinition.js")); -var _LinkEventDefinition = _interopRequireDefault(require("./LinkEventDefinition.js")); -var _MessageEventDefinition = _interopRequireDefault(require("./MessageEventDefinition.js")); -var _SignalEventDefinition = _interopRequireDefault(require("./SignalEventDefinition.js")); -var _TerminateEventDefinition = _interopRequireDefault(require("./TerminateEventDefinition.js")); -var _TimerEventDefinition = _interopRequireDefault(require("./TimerEventDefinition.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } \ No newline at end of file +var _CancelEventDefinition = require("./CancelEventDefinition.js"); +var _CompensateEventDefinition = require("./CompensateEventDefinition.js"); +var _ConditionalEventDefinition = require("./ConditionalEventDefinition.js"); +var _ErrorEventDefinition = require("./ErrorEventDefinition.js"); +var _EscalationEventDefinition = require("./EscalationEventDefinition.js"); +var _LinkEventDefinition = require("./LinkEventDefinition.js"); +var _MessageEventDefinition = require("./MessageEventDefinition.js"); +var _SignalEventDefinition = require("./SignalEventDefinition.js"); +var _TerminateEventDefinition = require("./TerminateEventDefinition.js"); +var _TimerEventDefinition = require("./TimerEventDefinition.js"); \ No newline at end of file diff --git a/dist/events/BoundaryEvent.js b/dist/events/BoundaryEvent.js index 87a91e3b..bb4cef13 100644 --- a/dist/events/BoundaryEvent.js +++ b/dist/events/BoundaryEvent.js @@ -3,19 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.BoundaryEvent = BoundaryEvent; exports.BoundaryEventBehaviour = BoundaryEventBehaviour; -exports.default = BoundaryEvent; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); -var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); +var _Activity = require("../activity/Activity.js"); +var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _shared = require("../shared.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_ATTACHED_TAGS = Symbol.for('attachedConsumers'); const K_COMPLETE_CONTENT = Symbol.for('completeContent'); const K_SHOVELS = Symbol.for('shovels'); function BoundaryEvent(activityDef, context) { - return new _Activity.default(BoundaryEventBehaviour, activityDef, context); + return new _Activity.Activity(BoundaryEventBehaviour, activityDef, context); } function BoundaryEventBehaviour(activity) { this.id = activity.id; @@ -25,7 +24,7 @@ function BoundaryEventBehaviour(activity) { this.environment = activity.environment; this.broker = activity.broker; /** @private */ - this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions, 'execute.bound.completed'); + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions, 'execute.bound.completed'); /** @private */ this[K_SHOVELS] = new Set(); /** @private */ diff --git a/dist/events/EndEvent.js b/dist/events/EndEvent.js index ec1c7018..ba2b3fa7 100644 --- a/dist/events/EndEvent.js +++ b/dist/events/EndEvent.js @@ -3,15 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.EndEvent = EndEvent; exports.EndEventBehaviour = EndEventBehaviour; -exports.default = EndEvent; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); -var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); +var _Activity = require("../activity/Activity.js"); +var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function EndEvent(activityDef, context) { - return new _Activity.default(EndEventBehaviour, { + return new _Activity.Activity(EndEventBehaviour, { ...activityDef, isThrowing: true }, context); @@ -21,7 +20,7 @@ function EndEventBehaviour(activity) { this.type = activity.type; this.broker = activity.broker; /** @private */ - this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } EndEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[_constants.K_EXECUTION]; diff --git a/dist/events/IntermediateCatchEvent.js b/dist/events/IntermediateCatchEvent.js index aa72a938..7b3c0cea 100644 --- a/dist/events/IntermediateCatchEvent.js +++ b/dist/events/IntermediateCatchEvent.js @@ -3,15 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.IntermediateCatchEvent = IntermediateCatchEvent; exports.IntermediateCatchEventBehaviour = IntermediateCatchEventBehaviour; -exports.default = IntermediateCatchEvent; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); -var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); +var _Activity = require("../activity/Activity.js"); +var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function IntermediateCatchEvent(activityDef, context) { - return new _Activity.default(IntermediateCatchEventBehaviour, { + return new _Activity.Activity(IntermediateCatchEventBehaviour, { ...activityDef, isCatching: true }, context); @@ -21,7 +20,7 @@ function IntermediateCatchEventBehaviour(activity) { this.type = activity.type; this.broker = activity.broker; /** @private */ - this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } IntermediateCatchEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[_constants.K_EXECUTION]; diff --git a/dist/events/IntermediateThrowEvent.js b/dist/events/IntermediateThrowEvent.js index 36a02b00..9df78066 100644 --- a/dist/events/IntermediateThrowEvent.js +++ b/dist/events/IntermediateThrowEvent.js @@ -3,15 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.IntermediateThrowEvent = IntermediateThrowEvent; exports.IntermediateThrowEventBehaviour = IntermediateThrowEventBehaviour; -exports.default = IntermediateThrowEvent; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); -var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); +var _Activity = require("../activity/Activity.js"); +var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function IntermediateThrowEvent(activityDef, context) { - return new _Activity.default(IntermediateThrowEventBehaviour, { + return new _Activity.Activity(IntermediateThrowEventBehaviour, { ...activityDef, isThrowing: true }, context); @@ -21,7 +20,7 @@ function IntermediateThrowEventBehaviour(activity) { this.type = activity.type; this.broker = activity.broker; /** @private */ - this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } IntermediateThrowEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[_constants.K_EXECUTION]; diff --git a/dist/events/StartEvent.js b/dist/events/StartEvent.js index f6a594f8..5f5370c3 100644 --- a/dist/events/StartEvent.js +++ b/dist/events/StartEvent.js @@ -3,15 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.StartEvent = StartEvent; exports.StartEventBehaviour = StartEventBehaviour; -exports.default = StartEvent; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); -var _EventDefinitionExecution = _interopRequireDefault(require("../eventDefinitions/EventDefinitionExecution.js")); +var _Activity = require("../activity/Activity.js"); +var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function StartEvent(activityDef, context) { - return new _Activity.default(StartEventBehaviour, activityDef, context); + return new _Activity.Activity(StartEventBehaviour, activityDef, context); } function StartEventBehaviour(activity) { this.id = activity.id; @@ -19,7 +18,7 @@ function StartEventBehaviour(activity) { this.activity = activity; this.broker = activity.broker; /** @private */ - this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.default(activity, activity.eventDefinitions); + this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } Object.defineProperty(StartEventBehaviour.prototype, 'executionId', { get() { diff --git a/dist/events/index.js b/dist/events/index.js index 467d5d7f..3f2f82e4 100644 --- a/dist/events/index.js +++ b/dist/events/index.js @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "BoundaryEvent", { enumerable: true, get: function () { - return _BoundaryEvent.default; + return _BoundaryEvent.BoundaryEvent; } }); Object.defineProperty(exports, "BoundaryEventBehaviour", { @@ -18,7 +18,7 @@ Object.defineProperty(exports, "BoundaryEventBehaviour", { Object.defineProperty(exports, "EndEvent", { enumerable: true, get: function () { - return _EndEvent.default; + return _EndEvent.EndEvent; } }); Object.defineProperty(exports, "EndEventBehaviour", { @@ -30,7 +30,7 @@ Object.defineProperty(exports, "EndEventBehaviour", { Object.defineProperty(exports, "IntermediateCatchEvent", { enumerable: true, get: function () { - return _IntermediateCatchEvent.default; + return _IntermediateCatchEvent.IntermediateCatchEvent; } }); Object.defineProperty(exports, "IntermediateCatchEventBehaviour", { @@ -42,7 +42,7 @@ Object.defineProperty(exports, "IntermediateCatchEventBehaviour", { Object.defineProperty(exports, "IntermediateThrowEvent", { enumerable: true, get: function () { - return _IntermediateThrowEvent.default; + return _IntermediateThrowEvent.IntermediateThrowEvent; } }); Object.defineProperty(exports, "IntermediateThrowEventBehaviour", { @@ -54,7 +54,7 @@ Object.defineProperty(exports, "IntermediateThrowEventBehaviour", { Object.defineProperty(exports, "StartEvent", { enumerable: true, get: function () { - return _StartEvent.default; + return _StartEvent.StartEvent; } }); Object.defineProperty(exports, "StartEventBehaviour", { @@ -63,9 +63,8 @@ Object.defineProperty(exports, "StartEventBehaviour", { return _StartEvent.StartEventBehaviour; } }); -var _BoundaryEvent = _interopRequireWildcard(require("./BoundaryEvent.js")); -var _EndEvent = _interopRequireWildcard(require("./EndEvent.js")); -var _IntermediateCatchEvent = _interopRequireWildcard(require("./IntermediateCatchEvent.js")); -var _IntermediateThrowEvent = _interopRequireWildcard(require("./IntermediateThrowEvent.js")); -var _StartEvent = _interopRequireWildcard(require("./StartEvent.js")); -function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } \ No newline at end of file +var _BoundaryEvent = require("./BoundaryEvent.js"); +var _EndEvent = require("./EndEvent.js"); +var _IntermediateCatchEvent = require("./IntermediateCatchEvent.js"); +var _IntermediateThrowEvent = require("./IntermediateThrowEvent.js"); +var _StartEvent = require("./StartEvent.js"); \ No newline at end of file diff --git a/dist/flows/Association.js b/dist/flows/Association.js index 2ff3464f..12776994 100644 --- a/dist/flows/Association.js +++ b/dist/flows/Association.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Association; +exports.Association = Association; var _messageHelper = require("../messageHelper.js"); var _EventBroker = require("../EventBroker.js"); var _Api = require("../Api.js"); diff --git a/dist/flows/MessageFlow.js b/dist/flows/MessageFlow.js index fedc0ff1..845a6c57 100644 --- a/dist/flows/MessageFlow.js +++ b/dist/flows/MessageFlow.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = MessageFlow; +exports.MessageFlow = MessageFlow; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _EventBroker = require("../EventBroker.js"); diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index 11a36c0d..2236e2c2 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -4,14 +4,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.SequenceFlow = SequenceFlow; -exports.default = void 0; var _messageHelper = require("../messageHelper.js"); var _shared = require("../shared.js"); var _EventBroker = require("../EventBroker.js"); var _Api = require("../Api.js"); var _condition = require("../condition.js"); var _constants = require("../constants.js"); -var _default = exports.default = SequenceFlow; /** * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. diff --git a/dist/flows/index.js b/dist/flows/index.js index 0a087bcf..9a8a259a 100644 --- a/dist/flows/index.js +++ b/dist/flows/index.js @@ -6,22 +6,21 @@ Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "Association", { enumerable: true, get: function () { - return _Association.default; + return _Association.Association; } }); Object.defineProperty(exports, "MessageFlow", { enumerable: true, get: function () { - return _MessageFlow.default; + return _MessageFlow.MessageFlow; } }); Object.defineProperty(exports, "SequenceFlow", { enumerable: true, get: function () { - return _SequenceFlow.default; + return _SequenceFlow.SequenceFlow; } }); -var _Association = _interopRequireDefault(require("./Association.js")); -var _MessageFlow = _interopRequireDefault(require("./MessageFlow.js")); -var _SequenceFlow = _interopRequireDefault(require("./SequenceFlow.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } \ No newline at end of file +var _Association = require("./Association.js"); +var _MessageFlow = require("./MessageFlow.js"); +var _SequenceFlow = require("./SequenceFlow.js"); \ No newline at end of file diff --git a/dist/gateways/EventBasedGateway.js b/dist/gateways/EventBasedGateway.js index b3f19894..aaaf2e83 100644 --- a/dist/gateways/EventBasedGateway.js +++ b/dist/gateways/EventBasedGateway.js @@ -3,14 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.EventBasedGateway = EventBasedGateway; exports.EventBasedGatewayBehaviour = EventBasedGatewayBehaviour; -exports.default = EventBasedGateway; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function EventBasedGateway(activityDef, context) { - return new _Activity.default(EventBasedGatewayBehaviour, activityDef, context); + return new _Activity.Activity(EventBasedGatewayBehaviour, activityDef, context); } function EventBasedGatewayBehaviour(activity, context) { this.id = activity.id; diff --git a/dist/gateways/ExclusiveGateway.js b/dist/gateways/ExclusiveGateway.js index 43884f0c..e0f7a023 100644 --- a/dist/gateways/ExclusiveGateway.js +++ b/dist/gateways/ExclusiveGateway.js @@ -3,13 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.ExclusiveGateway = ExclusiveGateway; exports.ExclusiveGatewayBehaviour = ExclusiveGatewayBehaviour; -exports.default = ExclusiveGateway; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function ExclusiveGateway(activityDef, context) { - return new _Activity.default(ExclusiveGatewayBehaviour, activityDef, context); + return new _Activity.Activity(ExclusiveGatewayBehaviour, activityDef, context); } function ExclusiveGatewayBehaviour(activity) { const { diff --git a/dist/gateways/InclusiveGateway.js b/dist/gateways/InclusiveGateway.js index 58773ae6..c057f5a0 100644 --- a/dist/gateways/InclusiveGateway.js +++ b/dist/gateways/InclusiveGateway.js @@ -3,13 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.InclusiveGateway = InclusiveGateway; exports.InclusiveGatewayBehaviour = InclusiveGatewayBehaviour; -exports.default = InclusiveGateway; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function InclusiveGateway(activityDef, context) { - return new _Activity.default(InclusiveGatewayBehaviour, activityDef, context); + return new _Activity.Activity(InclusiveGatewayBehaviour, activityDef, context); } function InclusiveGatewayBehaviour(activity) { const { diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 4621e8b5..12964415 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -3,18 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.ParallelGateway = ParallelGateway; exports.ParallelGatewayBehaviour = ParallelGatewayBehaviour; -exports.default = ParallelGateway; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const STATE_MONTITORING = 'monitoring'; const STATE_SETUP = 'setup'; const K_PEERS = Symbol.for('peers'); const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); function ParallelGateway(activityDef, context) { - const activity = new _Activity.default(ParallelGatewayBehaviour, { + const activity = new _Activity.Activity(ParallelGatewayBehaviour, { ...activityDef, isParallelGateway: true }, context); diff --git a/dist/gateways/index.js b/dist/gateways/index.js index e5d2a9f2..621a5627 100644 --- a/dist/gateways/index.js +++ b/dist/gateways/index.js @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "EventBasedGateway", { enumerable: true, get: function () { - return _EventBasedGateway.default; + return _EventBasedGateway.EventBasedGateway; } }); Object.defineProperty(exports, "EventBasedGatewayBehaviour", { @@ -18,7 +18,7 @@ Object.defineProperty(exports, "EventBasedGatewayBehaviour", { Object.defineProperty(exports, "ExclusiveGateway", { enumerable: true, get: function () { - return _ExclusiveGateway.default; + return _ExclusiveGateway.ExclusiveGateway; } }); Object.defineProperty(exports, "ExclusiveGatewayBehaviour", { @@ -30,7 +30,7 @@ Object.defineProperty(exports, "ExclusiveGatewayBehaviour", { Object.defineProperty(exports, "InclusiveGateway", { enumerable: true, get: function () { - return _InclusiveGateway.default; + return _InclusiveGateway.InclusiveGateway; } }); Object.defineProperty(exports, "InclusiveGatewayBehaviour", { @@ -42,7 +42,7 @@ Object.defineProperty(exports, "InclusiveGatewayBehaviour", { Object.defineProperty(exports, "ParallelGateway", { enumerable: true, get: function () { - return _ParallelGateway.default; + return _ParallelGateway.ParallelGateway; } }); Object.defineProperty(exports, "ParallelGatewayBehaviour", { @@ -51,8 +51,7 @@ Object.defineProperty(exports, "ParallelGatewayBehaviour", { return _ParallelGateway.ParallelGatewayBehaviour; } }); -var _EventBasedGateway = _interopRequireWildcard(require("./EventBasedGateway.js")); -var _ExclusiveGateway = _interopRequireWildcard(require("./ExclusiveGateway.js")); -var _InclusiveGateway = _interopRequireWildcard(require("./InclusiveGateway.js")); -var _ParallelGateway = _interopRequireWildcard(require("./ParallelGateway.js")); -function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } \ No newline at end of file +var _EventBasedGateway = require("./EventBasedGateway.js"); +var _ExclusiveGateway = require("./ExclusiveGateway.js"); +var _InclusiveGateway = require("./InclusiveGateway.js"); +var _ParallelGateway = require("./ParallelGateway.js"); \ No newline at end of file diff --git a/dist/getPropertyValue.js b/dist/getPropertyValue.js index bd7b8ae7..9457cadd 100644 --- a/dist/getPropertyValue.js +++ b/dist/getPropertyValue.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = getPropertyValue; +exports.getPropertyValue = getPropertyValue; const propertyPattern = /(\w+)\((.*?)(?:\))|(\.|\[|^)(.+?)(?:\]|\[|\.|$)/; const stringConstantPattern = /^(['"])(.*)\1$/; const numberConstantPattern = /^\W*-?\d+(.\d+)?\W*$/; diff --git a/dist/index.js b/dist/index.js index d0677051..809c5905 100644 --- a/dist/index.js +++ b/dist/index.js @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "Activity", { enumerable: true, get: function () { - return _Activity.default; + return _Activity.Activity; } }); Object.defineProperty(exports, "ActivityError", { @@ -36,7 +36,7 @@ Object.defineProperty(exports, "BoundaryEvent", { Object.defineProperty(exports, "BpmnError", { enumerable: true, get: function () { - return _BpmnError.default; + return _BpmnError.BpmnErrorActivity; } }); Object.defineProperty(exports, "BusinessRuleTask", { @@ -60,7 +60,7 @@ Object.defineProperty(exports, "CancelEventDefinition", { Object.defineProperty(exports, "Category", { enumerable: true, get: function () { - return _Dummy.default; + return _Dummy.DummyActivity; } }); Object.defineProperty(exports, "CompensateEventDefinition", { @@ -78,37 +78,37 @@ Object.defineProperty(exports, "ConditionalEventDefinition", { Object.defineProperty(exports, "Context", { enumerable: true, get: function () { - return _Context.default; + return _Context.Context; } }); Object.defineProperty(exports, "DataObject", { enumerable: true, get: function () { - return _EnvironmentDataObject.default; + return _EnvironmentDataObject.EnvironmentDataObject; } }); Object.defineProperty(exports, "DataStore", { enumerable: true, get: function () { - return _EnvironmentDataStore.default; + return _EnvironmentDataStore.EnvironmentDataStore; } }); Object.defineProperty(exports, "DataStoreReference", { enumerable: true, get: function () { - return _EnvironmentDataStoreReference.default; + return _EnvironmentDataStoreReference.EnvironmentDataStoreReference; } }); Object.defineProperty(exports, "Definition", { enumerable: true, get: function () { - return _Definition.default; + return _Definition.Definition; } }); Object.defineProperty(exports, "Dummy", { enumerable: true, get: function () { - return _Dummy.default; + return _Dummy.DummyActivity; } }); Object.defineProperty(exports, "EndEvent", { @@ -120,7 +120,7 @@ Object.defineProperty(exports, "EndEvent", { Object.defineProperty(exports, "Environment", { enumerable: true, get: function () { - return _Environment.default; + return _Environment.Environment; } }); Object.defineProperty(exports, "ErrorEventDefinition", { @@ -132,7 +132,7 @@ Object.defineProperty(exports, "ErrorEventDefinition", { Object.defineProperty(exports, "Escalation", { enumerable: true, get: function () { - return _Escalation.default; + return _Escalation.Escalation; } }); Object.defineProperty(exports, "EscalationEventDefinition", { @@ -156,7 +156,7 @@ Object.defineProperty(exports, "ExclusiveGateway", { Object.defineProperty(exports, "Group", { enumerable: true, get: function () { - return _Dummy.default; + return _Dummy.DummyActivity; } }); Object.defineProperty(exports, "InclusiveGateway", { @@ -168,7 +168,7 @@ Object.defineProperty(exports, "InclusiveGateway", { Object.defineProperty(exports, "InputOutputSpecification", { enumerable: true, get: function () { - return _InputOutputSpecification.default; + return _InputOutputSpecification.IoSpecification; } }); Object.defineProperty(exports, "IntermediateCatchEvent", { @@ -186,7 +186,7 @@ Object.defineProperty(exports, "IntermediateThrowEvent", { Object.defineProperty(exports, "Lane", { enumerable: true, get: function () { - return _Lane.default; + return _Lane.Lane; } }); Object.defineProperty(exports, "LinkEventDefinition", { @@ -204,7 +204,7 @@ Object.defineProperty(exports, "ManualTask", { Object.defineProperty(exports, "Message", { enumerable: true, get: function () { - return _Message.default; + return _Message.Message; } }); Object.defineProperty(exports, "MessageEventDefinition", { @@ -222,7 +222,7 @@ Object.defineProperty(exports, "MessageFlow", { Object.defineProperty(exports, "MultiInstanceLoopCharacteristics", { enumerable: true, get: function () { - return _LoopCharacteristics.default; + return _LoopCharacteristics.LoopCharacteristics; } }); Object.defineProperty(exports, "ParallelGateway", { @@ -234,13 +234,13 @@ Object.defineProperty(exports, "ParallelGateway", { Object.defineProperty(exports, "Process", { enumerable: true, get: function () { - return _Process.default; + return _Process.Process; } }); Object.defineProperty(exports, "Properties", { enumerable: true, get: function () { - return _Properties.default; + return _Properties.Properties; } }); Object.defineProperty(exports, "ReceiveTask", { @@ -276,7 +276,7 @@ Object.defineProperty(exports, "SequenceFlow", { Object.defineProperty(exports, "ServiceImplementation", { enumerable: true, get: function () { - return _ServiceImplementation.default; + return _ServiceImplementation.ServiceImplementation; } }); Object.defineProperty(exports, "ServiceTask", { @@ -288,7 +288,7 @@ Object.defineProperty(exports, "ServiceTask", { Object.defineProperty(exports, "Signal", { enumerable: true, get: function () { - return _Signal.default; + return _Signal.Signal; } }); Object.defineProperty(exports, "SignalEventDefinition", { @@ -306,7 +306,7 @@ Object.defineProperty(exports, "SignalTask", { Object.defineProperty(exports, "StandardLoopCharacteristics", { enumerable: true, get: function () { - return _StandardLoopCharacteristics.default; + return _StandardLoopCharacteristics.StandardLoopCharacteristics; } }); Object.defineProperty(exports, "StartEvent", { @@ -336,7 +336,7 @@ Object.defineProperty(exports, "TerminateEventDefinition", { Object.defineProperty(exports, "TextAnnotation", { enumerable: true, get: function () { - return _Dummy.default; + return _Dummy.DummyActivity; } }); Object.defineProperty(exports, "TimerEventDefinition", { @@ -363,30 +363,29 @@ Object.defineProperty(exports, "UserTask", { return _index4.SignalTask; } }); -var _Activity = _interopRequireDefault(require("./activity/Activity.js")); -var _BpmnError = _interopRequireDefault(require("./error/BpmnError.js")); -var _Context = _interopRequireDefault(require("./Context.js")); -var _EnvironmentDataObject = _interopRequireDefault(require("./io/EnvironmentDataObject.js")); -var _EnvironmentDataStore = _interopRequireDefault(require("./io/EnvironmentDataStore.js")); -var _EnvironmentDataStoreReference = _interopRequireDefault(require("./io/EnvironmentDataStoreReference.js")); -var _Definition = _interopRequireDefault(require("./definition/Definition.js")); -var _Dummy = _interopRequireDefault(require("./activity/Dummy.js")); -var _Environment = _interopRequireDefault(require("./Environment.js")); -var _Escalation = _interopRequireDefault(require("./activity/Escalation.js")); -var _InputOutputSpecification = _interopRequireDefault(require("./io/InputOutputSpecification.js")); -var _Lane = _interopRequireDefault(require("./process/Lane.js")); -var _LoopCharacteristics = _interopRequireDefault(require("./tasks/LoopCharacteristics.js")); -var _Message = _interopRequireDefault(require("./activity/Message.js")); -var _Process = _interopRequireDefault(require("./process/Process.js")); -var _Properties = _interopRequireDefault(require("./io/Properties.js")); -var _ServiceImplementation = _interopRequireDefault(require("./tasks/ServiceImplementation.js")); -var _Signal = _interopRequireDefault(require("./activity/Signal.js")); -var _StandardLoopCharacteristics = _interopRequireDefault(require("./tasks/StandardLoopCharacteristics.js")); +var _Activity = require("./activity/Activity.js"); +var _BpmnError = require("./error/BpmnError.js"); +var _Context = require("./Context.js"); +var _EnvironmentDataObject = require("./io/EnvironmentDataObject.js"); +var _EnvironmentDataStore = require("./io/EnvironmentDataStore.js"); +var _EnvironmentDataStoreReference = require("./io/EnvironmentDataStoreReference.js"); +var _Definition = require("./definition/Definition.js"); +var _Dummy = require("./activity/Dummy.js"); +var _Environment = require("./Environment.js"); +var _Escalation = require("./activity/Escalation.js"); +var _InputOutputSpecification = require("./io/InputOutputSpecification.js"); +var _Lane = require("./process/Lane.js"); +var _LoopCharacteristics = require("./tasks/LoopCharacteristics.js"); +var _Message = require("./activity/Message.js"); +var _Process = require("./process/Process.js"); +var _Properties = require("./io/Properties.js"); +var _ServiceImplementation = require("./tasks/ServiceImplementation.js"); +var _Signal = require("./activity/Signal.js"); +var _StandardLoopCharacteristics = require("./tasks/StandardLoopCharacteristics.js"); var _index = require("./flows/index.js"); var _index2 = require("./events/index.js"); var _index3 = require("./gateways/index.js"); var _index4 = require("./tasks/index.js"); var _index5 = require("./eventDefinitions/index.js"); var _Timers = require("./Timers.js"); -var _Errors = require("./error/Errors.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } \ No newline at end of file +var _Errors = require("./error/Errors.js"); \ No newline at end of file diff --git a/dist/io/BpmnIO.js b/dist/io/BpmnIO.js index ca4f7807..9e034ece 100644 --- a/dist/io/BpmnIO.js +++ b/dist/io/BpmnIO.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = BpmnIO; +exports.BpmnIO = BpmnIO; function BpmnIO(activity, context) { this.activity = activity; this.context = context; diff --git a/dist/io/EnvironmentDataObject.js b/dist/io/EnvironmentDataObject.js index 2d287a47..07ca4c6e 100644 --- a/dist/io/EnvironmentDataObject.js +++ b/dist/io/EnvironmentDataObject.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = EnvironmentDataObject; +exports.EnvironmentDataObject = EnvironmentDataObject; function EnvironmentDataObject(dataObjectDef, { environment }) { diff --git a/dist/io/EnvironmentDataStore.js b/dist/io/EnvironmentDataStore.js index b34f5f99..9ba645b0 100644 --- a/dist/io/EnvironmentDataStore.js +++ b/dist/io/EnvironmentDataStore.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = EnvironmentDataStore; +exports.EnvironmentDataStore = EnvironmentDataStore; function EnvironmentDataStore(dataStoreDef, { environment }) { diff --git a/dist/io/EnvironmentDataStoreReference.js b/dist/io/EnvironmentDataStoreReference.js index b6d1958a..f97f1fcb 100644 --- a/dist/io/EnvironmentDataStoreReference.js +++ b/dist/io/EnvironmentDataStoreReference.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = EnvironmentDataStoreReference; +exports.EnvironmentDataStoreReference = EnvironmentDataStoreReference; function EnvironmentDataStoreReference(dataObjectDef, { environment }) { diff --git a/dist/io/InputOutputSpecification.js b/dist/io/InputOutputSpecification.js index 7068e811..590d5899 100644 --- a/dist/io/InputOutputSpecification.js +++ b/dist/io/InputOutputSpecification.js @@ -3,11 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = IoSpecification; -var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); +exports.IoSpecification = IoSpecification; +var _getPropertyValue = require("../getPropertyValue.js"); var _shared = require("../shared.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function IoSpecification(activity, ioSpecificationDef, context) { const { id, @@ -74,7 +73,7 @@ IoSpecification.prototype._onFormatEnter = function onFormatOnEnter() { name: ioSource.name }; result.sources.push(source); - const dataObjectId = (0, _getPropertyValue.default)(ioSource, 'behaviour.association.source.dataObject.id'); + const dataObjectId = (0, _getPropertyValue.getPropertyValue)(ioSource, 'behaviour.association.source.dataObject.id'); if (!dataObjectId) return result; const dataObject = this.context.getDataObjectById(dataObjectId); if (!dataObject) return result; @@ -119,8 +118,8 @@ IoSpecification.prototype._onFormatEnter = function onFormatOnEnter() { }; IoSpecification.prototype._onFormatComplete = function formatOnComplete(message) { const safeType = (0, _shared.brokerSafeId)(this.type).toLowerCase(); - const messageInputs = (0, _getPropertyValue.default)(message, 'content.ioSpecification.dataInputs'); - const messageOutputs = (0, _getPropertyValue.default)(message, 'content.output.ioSpecification.dataOutputs') || []; + const messageInputs = (0, _getPropertyValue.getPropertyValue)(message, 'content.ioSpecification.dataInputs'); + const messageOutputs = (0, _getPropertyValue.getPropertyValue)(message, 'content.output.ioSpecification.dataOutputs') || []; const dataOutputs = this.behaviour.dataOutputs; const broker = this.broker; const context = this.context; @@ -138,7 +137,7 @@ IoSpecification.prototype._onFormatComplete = function formatOnComplete(message) value }; result.sources.push(source); - const dataObjectId = (0, _getPropertyValue.default)(ioSource, 'behaviour.association.target.dataObject.id'); + const dataObjectId = (0, _getPropertyValue.getPropertyValue)(ioSource, 'behaviour.association.target.dataObject.id'); if (!dataObjectId) return result; const dataObject = context.getDataObjectById(dataObjectId); if (!dataObject) return result; diff --git a/dist/io/Properties.js b/dist/io/Properties.js index 47f1fe8a..f1809848 100644 --- a/dist/io/Properties.js +++ b/dist/io/Properties.js @@ -3,10 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Properties; -var _getPropertyValue = _interopRequireDefault(require("../getPropertyValue.js")); +exports.Properties = Properties; +var _getPropertyValue = require("../getPropertyValue.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_PROPERTIES = Symbol.for('properties'); function Properties(activity, propertiesDef, context) { this.activity = activity; @@ -26,10 +25,10 @@ function Properties(activity, propertiesDef, context) { name: def.behaviour?.name }; props.properties.add(source); - const inputDataObjectId = (0, _getPropertyValue.default)(def, 'behaviour.dataInput.association.source.dataObject.id'); - const outputDataObjectId = (0, _getPropertyValue.default)(def, 'behaviour.dataOutput.association.target.dataObject.id'); - const inputDataStoreId = (0, _getPropertyValue.default)(def, 'behaviour.dataInput.association.source.dataStore.id'); - const outputDataStoreId = (0, _getPropertyValue.default)(def, 'behaviour.dataOutput.association.target.dataStore.id'); + const inputDataObjectId = (0, _getPropertyValue.getPropertyValue)(def, 'behaviour.dataInput.association.source.dataObject.id'); + const outputDataObjectId = (0, _getPropertyValue.getPropertyValue)(def, 'behaviour.dataOutput.association.target.dataObject.id'); + const inputDataStoreId = (0, _getPropertyValue.getPropertyValue)(def, 'behaviour.dataInput.association.source.dataStore.id'); + const outputDataStoreId = (0, _getPropertyValue.getPropertyValue)(def, 'behaviour.dataOutput.association.target.dataStore.id'); if (inputDataObjectId) { const reference = context.getDataObjectById(inputDataObjectId); props.dataInputObjects.add({ @@ -124,7 +123,7 @@ Properties.prototype._formatOnEnter = function formatOnEnter(message) { }; Properties.prototype._formatOnComplete = function formatOnComplete(message) { const startRoutingKey = 'run.end.bpmn-properties'; - const messageOutput = (0, _getPropertyValue.default)(message, 'content.output.properties') || {}; + const messageOutput = (0, _getPropertyValue.getPropertyValue)(message, 'content.output.properties') || {}; const outputProperties = this._getProperties(message, messageOutput); const dataOutputObjects = this[K_PROPERTIES].dataOutputObjects; const broker = this.broker; diff --git a/dist/process/Lane.js b/dist/process/Lane.js index c50d38b7..1cbcf5ad 100644 --- a/dist/process/Lane.js +++ b/dist/process/Lane.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Lane; +exports.Lane = Lane; const K_PROCESS = Symbol.for('process'); /** diff --git a/dist/process/Process.js b/dist/process/Process.js index 8daa7e22..71adf318 100644 --- a/dist/process/Process.js +++ b/dist/process/Process.js @@ -4,17 +4,15 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Process = Process; -exports.default = void 0; -var _ProcessExecution = _interopRequireDefault(require("./ProcessExecution.js")); +var _ProcessExecution = require("./ProcessExecution.js"); var _shared = require("../shared.js"); var _Api = require("../Api.js"); var _EventBroker = require("../EventBroker.js"); var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_LANES = Symbol.for('lanes'); -var _default = exports.default = Process; + /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. @@ -225,7 +223,7 @@ Process.prototype.recover = function recover(state) { }; this.environment.recover(state.environment); if (state.execution) { - exec.set('execution', new _ProcessExecution.default(this, this.context).recover(state.execution)); + exec.set('execution', new _ProcessExecution.ProcessExecution(this, this.context).recover(state.execution)); } this.broker.recover(state.broker); return this; @@ -237,7 +235,7 @@ Process.prototype.recover = function recover(state) { */ Process.prototype.shake = function shake(startId) { if (this.isRunning) return this.execution.shake(startId); - return new _ProcessExecution.default(this, this.context).shake(startId); + return new _ProcessExecution.ProcessExecution(this, this.context).shake(startId); }; /** @@ -358,7 +356,7 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { exclusive: true, consumerTag: '_process-execution' }); - execution = execution || new _ProcessExecution.default(this, this.context); + execution = execution || new _ProcessExecution.ProcessExecution(this, this.context); exec.set('execution', execution); return execution.execute(executeMessage); } diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 88451658..d500462d 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -3,13 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = void 0; +exports.ProcessExecution = ProcessExecution; var _Api = require("../Api.js"); var _messageHelper = require("../messageHelper.js"); var _shared = require("../shared.js"); var _Tracker = require("../Tracker.js"); var _constants = require("../constants.js"); -var _default = exports.default = ProcessExecution; const K_ACTIVITY_Q = Symbol.for('activityQ'); const K_ELEMENTS = Symbol.for('elements'); const K_PARENT = Symbol.for('parent'); diff --git a/dist/tasks/CallActivity.js b/dist/tasks/CallActivity.js index 9f946eb9..46bf2edc 100644 --- a/dist/tasks/CallActivity.js +++ b/dist/tasks/CallActivity.js @@ -3,14 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.CallActivity = CallActivity; exports.CallActivityBehaviour = CallActivityBehaviour; -exports.default = CallActivity; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function CallActivity(activityDef, context) { - return new _Activity.default(CallActivityBehaviour, activityDef, context); + return new _Activity.Activity(CallActivityBehaviour, activityDef, context); } function CallActivityBehaviour(activity) { const { diff --git a/dist/tasks/LoopCharacteristics.js b/dist/tasks/LoopCharacteristics.js index 4e9262ce..90592878 100644 --- a/dist/tasks/LoopCharacteristics.js +++ b/dist/tasks/LoopCharacteristics.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = LoopCharacteristics; +exports.LoopCharacteristics = LoopCharacteristics; var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); function LoopCharacteristics(activity, loopCharacteristics) { diff --git a/dist/tasks/ReceiveTask.js b/dist/tasks/ReceiveTask.js index bc4ce94e..1db6e5d3 100644 --- a/dist/tasks/ReceiveTask.js +++ b/dist/tasks/ReceiveTask.js @@ -3,14 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.ReceiveTask = ReceiveTask; exports.ReceiveTaskBehaviour = ReceiveTaskBehaviour; -exports.default = ReceiveTask; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function ReceiveTask(activityDef, context) { - const task = new _Activity.default(ReceiveTaskBehaviour, activityDef, context); + const task = new _Activity.Activity(ReceiveTaskBehaviour, activityDef, context); task.broker.assertQueue('message', { autoDelete: false, durable: true diff --git a/dist/tasks/ScriptTask.js b/dist/tasks/ScriptTask.js index 57ac345f..990d570a 100644 --- a/dist/tasks/ScriptTask.js +++ b/dist/tasks/ScriptTask.js @@ -3,15 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.ScriptTask = ScriptTask; exports.ScriptTaskBehaviour = ScriptTaskBehaviour; -exports.default = ScriptTask; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); -var _ExecutionScope = _interopRequireDefault(require("../activity/ExecutionScope.js")); +var _Activity = require("../activity/Activity.js"); +var _ExecutionScope = require("../activity/ExecutionScope.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function ScriptTask(activityDef, context) { - return new _Activity.default(ScriptTaskBehaviour, activityDef, context); + return new _Activity.Activity(ScriptTaskBehaviour, activityDef, context); } function ScriptTaskBehaviour(activity) { const { @@ -39,7 +38,7 @@ ScriptTaskBehaviour.prototype.execute = function execute(executeMessage) { if (!script) { return activity.emitFatal(new _Errors.ActivityError(`Script format ${scriptFormat} is unsupported or was not registered for <${activity.id}>`, executeMessage), executeContent); } - return script.execute((0, _ExecutionScope.default)(activity, executeMessage), scriptCallback); + return script.execute((0, _ExecutionScope.ExecutionScope)(activity, executeMessage), scriptCallback); function scriptCallback(err, output) { if (err) { activity.logger.error(`<${executeContent.executionId} (${activity.id})>`, err); diff --git a/dist/tasks/ServiceImplementation.js b/dist/tasks/ServiceImplementation.js index 09eacb75..b7bcb44d 100644 --- a/dist/tasks/ServiceImplementation.js +++ b/dist/tasks/ServiceImplementation.js @@ -3,9 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = ServiceImplementation; -var _ExecutionScope = _interopRequireDefault(require("../activity/ExecutionScope.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } +exports.ServiceImplementation = ServiceImplementation; +var _ExecutionScope = require("../activity/ExecutionScope.js"); function ServiceImplementation(activity) { this.type = `${activity.type}:implementation`; this.implementation = activity.behaviour.implementation; @@ -16,7 +15,7 @@ ServiceImplementation.prototype.execute = function execute(executionMessage, cal const implementation = this.implementation; const serviceFn = activity.environment.resolveExpression(implementation, executionMessage); if (typeof serviceFn !== 'function') return callback(new Error(`Implementation ${implementation} did not resolve to a function`)); - serviceFn.call(activity, (0, _ExecutionScope.default)(activity, executionMessage), (err, ...args) => { + serviceFn.call(activity, (0, _ExecutionScope.ExecutionScope)(activity, executionMessage), (err, ...args) => { callback(err, args); }); }; \ No newline at end of file diff --git a/dist/tasks/ServiceTask.js b/dist/tasks/ServiceTask.js index 3efc3382..d2d6686e 100644 --- a/dist/tasks/ServiceTask.js +++ b/dist/tasks/ServiceTask.js @@ -3,14 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.ServiceTask = ServiceTask; exports.ServiceTaskBehaviour = ServiceTaskBehaviour; -exports.default = ServiceTask; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function ServiceTask(activityDef, context) { - return new _Activity.default(ServiceTaskBehaviour, activityDef, context); + return new _Activity.Activity(ServiceTaskBehaviour, activityDef, context); } function ServiceTaskBehaviour(activity) { const { diff --git a/dist/tasks/SignalTask.js b/dist/tasks/SignalTask.js index 717ec245..f359fc60 100644 --- a/dist/tasks/SignalTask.js +++ b/dist/tasks/SignalTask.js @@ -3,14 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.SignalTask = SignalTask; exports.SignalTaskBehaviour = SignalTaskBehaviour; -exports.default = SignalTask; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function SignalTask(activityDef, context) { - return new _Activity.default(SignalTaskBehaviour, activityDef, context); + return new _Activity.Activity(SignalTaskBehaviour, activityDef, context); } function SignalTaskBehaviour(activity) { const { diff --git a/dist/tasks/StandardLoopCharacteristics.js b/dist/tasks/StandardLoopCharacteristics.js index 4f4ac3f8..bcca0ac7 100644 --- a/dist/tasks/StandardLoopCharacteristics.js +++ b/dist/tasks/StandardLoopCharacteristics.js @@ -3,9 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = StandardLoopCharacteristics; -var _LoopCharacteristics = _interopRequireDefault(require("./LoopCharacteristics.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } +exports.StandardLoopCharacteristics = StandardLoopCharacteristics; +var _LoopCharacteristics = require("./LoopCharacteristics.js"); function StandardLoopCharacteristics(activity, loopCharacteristics) { let { behaviour @@ -14,7 +13,7 @@ function StandardLoopCharacteristics(activity, loopCharacteristics) { ...behaviour, isSequential: true }; - return new _LoopCharacteristics.default(activity, { + return new _LoopCharacteristics.LoopCharacteristics(activity, { ...loopCharacteristics, behaviour }); diff --git a/dist/tasks/SubProcess.js b/dist/tasks/SubProcess.js index be633ded..3a8a762f 100644 --- a/dist/tasks/SubProcess.js +++ b/dist/tasks/SubProcess.js @@ -3,17 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.SubProcess = SubProcess; exports.SubProcessBehaviour = SubProcessBehaviour; -exports.default = SubProcess; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); -var _ProcessExecution = _interopRequireDefault(require("../process/ProcessExecution.js")); +var _Activity = require("../activity/Activity.js"); +var _ProcessExecution = require("../process/ProcessExecution.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const K_EXECUTIONS = Symbol.for('executions'); const K_ON_EXECUTION_COMPLETED = Symbol.for('execution completed handler'); function SubProcess(activityDef, context) { const triggeredByEvent = activityDef.behaviour && activityDef.behaviour.triggeredByEvent; - const subProcess = new _Activity.default(SubProcessBehaviour, { + const subProcess = new _Activity.Activity(SubProcessBehaviour, { ...activityDef, isSubProcess: true, triggeredByEvent @@ -32,7 +31,7 @@ function SubProcess(activityDef, context) { startId } = message.content; const last = message.content.sequence.pop(); - const sequence = new _ProcessExecution.default(subProcess, context).shake(startId); + const sequence = new _ProcessExecution.ProcessExecution(subProcess, context).shake(startId); message.content.sequence.push({ ...last, isSubProcess: true, @@ -117,7 +116,7 @@ SubProcessBehaviour.prototype.recover = function recover(state) { } const subEnvironment = this.environment.clone().recover(state.environment); const subContext = this.context.clone(subEnvironment, this.activity); - const execution = new _ProcessExecution.default(this.activity, subContext).recover(state); + const execution = new _ProcessExecution.ProcessExecution(this.activity, subContext).recover(state); executions.add(execution); return execution; }; @@ -138,7 +137,7 @@ SubProcessBehaviour.prototype._upsertExecution = function upsertExecution(execut } const subEnvironment = this.environment.clone(); const subContext = this.context.clone(subEnvironment, this.activity); - execution = new _ProcessExecution.default(this.activity, subContext); + execution = new _ProcessExecution.ProcessExecution(this.activity, subContext); /** @private */ this[K_EXECUTIONS].add(execution); this._addListeners(executionId); diff --git a/dist/tasks/Task.js b/dist/tasks/Task.js index ea36538b..682b1720 100644 --- a/dist/tasks/Task.js +++ b/dist/tasks/Task.js @@ -3,13 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); +exports.Task = Task; exports.TaskBehaviour = TaskBehaviour; -exports.default = Task; -var _Activity = _interopRequireDefault(require("../activity/Activity.js")); +var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function Task(activityDef, context) { - return new _Activity.default(TaskBehaviour, activityDef, context); + return new _Activity.Activity(TaskBehaviour, activityDef, context); } function TaskBehaviour(activity) { const { diff --git a/dist/tasks/Transaction.js b/dist/tasks/Transaction.js index 80999dbc..0d4800ec 100644 --- a/dist/tasks/Transaction.js +++ b/dist/tasks/Transaction.js @@ -3,15 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Transaction; -var _SubProcess = _interopRequireDefault(require("./SubProcess.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } +exports.Transaction = Transaction; +var _SubProcess = require("./SubProcess.js"); function Transaction(activityDef, context) { const transaction = { type: 'transaction', ...activityDef, isTransaction: true }; - const activity = (0, _SubProcess.default)(transaction, context); + const activity = (0, _SubProcess.SubProcess)(transaction, context); return activity; } \ No newline at end of file diff --git a/dist/tasks/index.js b/dist/tasks/index.js index 996c9ae0..355fafba 100644 --- a/dist/tasks/index.js +++ b/dist/tasks/index.js @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "CallActivity", { enumerable: true, get: function () { - return _CallActivity.default; + return _CallActivity.CallActivity; } }); Object.defineProperty(exports, "CallActivityBehaviour", { @@ -18,7 +18,7 @@ Object.defineProperty(exports, "CallActivityBehaviour", { Object.defineProperty(exports, "ReceiveTask", { enumerable: true, get: function () { - return _ReceiveTask.default; + return _ReceiveTask.ReceiveTask; } }); Object.defineProperty(exports, "ReceiveTaskBehaviour", { @@ -30,7 +30,7 @@ Object.defineProperty(exports, "ReceiveTaskBehaviour", { Object.defineProperty(exports, "ScriptTask", { enumerable: true, get: function () { - return _ScriptTask.default; + return _ScriptTask.ScriptTask; } }); Object.defineProperty(exports, "ScriptTaskBehaviour", { @@ -42,7 +42,7 @@ Object.defineProperty(exports, "ScriptTaskBehaviour", { Object.defineProperty(exports, "ServiceTask", { enumerable: true, get: function () { - return _ServiceTask.default; + return _ServiceTask.ServiceTask; } }); Object.defineProperty(exports, "ServiceTaskBehaviour", { @@ -54,7 +54,7 @@ Object.defineProperty(exports, "ServiceTaskBehaviour", { Object.defineProperty(exports, "SignalTask", { enumerable: true, get: function () { - return _SignalTask.default; + return _SignalTask.SignalTask; } }); Object.defineProperty(exports, "SignalTaskBehaviour", { @@ -66,7 +66,7 @@ Object.defineProperty(exports, "SignalTaskBehaviour", { Object.defineProperty(exports, "SubProcess", { enumerable: true, get: function () { - return _SubProcess.default; + return _SubProcess.SubProcess; } }); Object.defineProperty(exports, "SubProcessBehaviour", { @@ -78,7 +78,7 @@ Object.defineProperty(exports, "SubProcessBehaviour", { Object.defineProperty(exports, "Task", { enumerable: true, get: function () { - return _Task.default; + return _Task.Task; } }); Object.defineProperty(exports, "TaskBehaviour", { @@ -90,16 +90,14 @@ Object.defineProperty(exports, "TaskBehaviour", { Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { - return _Transaction.default; + return _Transaction.Transaction; } }); -var _CallActivity = _interopRequireWildcard(require("./CallActivity.js")); -var _ReceiveTask = _interopRequireWildcard(require("./ReceiveTask.js")); -var _ScriptTask = _interopRequireWildcard(require("./ScriptTask.js")); -var _ServiceTask = _interopRequireWildcard(require("./ServiceTask.js")); -var _SignalTask = _interopRequireWildcard(require("./SignalTask.js")); -var _SubProcess = _interopRequireWildcard(require("./SubProcess.js")); -var _Task = _interopRequireWildcard(require("./Task.js")); -var _Transaction = _interopRequireDefault(require("./Transaction.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } -function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } \ No newline at end of file +var _CallActivity = require("./CallActivity.js"); +var _ReceiveTask = require("./ReceiveTask.js"); +var _ScriptTask = require("./ScriptTask.js"); +var _ServiceTask = require("./ServiceTask.js"); +var _SignalTask = require("./SignalTask.js"); +var _SubProcess = require("./SubProcess.js"); +var _Task = require("./Task.js"); +var _Transaction = require("./Transaction.js"); \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js index 7e5516d0..e99a78ed 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -11,6 +11,7 @@ const rules = { 'no-caller': 2, 'no-catch-shadow': 2, 'no-console': 1, + 'no-duplicate-imports': 2, 'no-eval': 2, 'no-extend-native': 2, 'no-extra-bind': 2, diff --git a/package.json b/package.json index 321100fc..f3e73473 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,11 @@ "require": "./dist/index.js", "import": "./src/index.js" }, + "./errors": { + "types": "./types/index.d.ts", + "require": "./dist/error/Errors.js", + "import": "./src/error/Errors.js" + }, "./events": { "types": "./types/index.d.ts", "require": "./dist/events/index.js", @@ -115,6 +120,6 @@ }, "dependencies": { "@0dep/piso": "^4.0.0", - "smqp": "^12.0.0" + "smqp": "^13.0.0" } } diff --git a/scripts/build-types.js b/scripts/build-types.js index 25b4374f..fd379068 100644 --- a/scripts/build-types.js +++ b/scripts/build-types.js @@ -1,4 +1,4 @@ -import { readFileSync, appendFileSync } from 'node:fs'; +import { readFileSync, writeFileSync } from 'node:fs'; import { createBundle } from 'dts-buddy'; const output = 'types/index.d.ts'; @@ -9,6 +9,7 @@ createBundle({ output, modules: { 'bpmn-elements': 'src/index.js', + 'bpmn-elements/errors': 'src/error/Errors.js', 'bpmn-elements/events': 'src/events/index.js', 'bpmn-elements/eventDefinitions': 'src/eventDefinitions/index.js', 'bpmn-elements/flows': 'src/flows/index.js', @@ -17,10 +18,22 @@ createBundle({ }, }) .then(() => { + let bundle = readFileSync(output, 'utf8'); + + // tsc emits both `export function Foo(...): Foo;` AND `export class Foo { ... }` + // for constructor functions in JS. The function declaration overshadows the class + // for type-level constructor checks (`Foo extends new (...args) => any`), so strip it. + bundle = bundle.replace( + /^(\s*)(?:export )?function (\w+)\([^)]*\)[^;]*;\n(\s*)((?:export )?class \2\b)/gm, + '$1$3$4' + ); + // Object.defineProperties getters can't be inferred from constructor functions, // so the augmentation file declares them as interface members that merge with // the dts-buddy-emitted classes. - appendFileSync(output, '\n' + readFileSync(augmentations, 'utf8')); + bundle += '\n' + readFileSync(augmentations, 'utf8'); + + writeFileSync(output, bundle); }) .catch((err) => { throw err; diff --git a/src/Context.js b/src/Context.js index 8925da72..b5fdd982 100644 --- a/src/Context.js +++ b/src/Context.js @@ -1,5 +1,5 @@ -import BpmnIO from './io/BpmnIO.js'; -import Environment from './Environment.js'; +import { BpmnIO } from './io/BpmnIO.js'; +import { Environment } from './Environment.js'; import { getUniqueId } from './shared.js'; import { K_ACTIVATED } from './constants.js'; @@ -10,7 +10,7 @@ const K_OWNER = Symbol.for('owner'); * @param {import('moddle-context-serializer').SerializableContext} definitionContext * @param {import('types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted */ -export default function Context(definitionContext, environment) { +export function Context(definitionContext, environment) { environment = environment ? environment.clone() : new Environment(); return new ContextInstance(definitionContext, environment); } @@ -21,7 +21,7 @@ export default function Context(definitionContext, environment) { * @param {import('types').Environment} environment * @param {import('types').Process | import('types').Activity} [owner] Process or sub-process activity that owns this context */ -function ContextInstance(definitionContext, environment, owner) { +export function ContextInstance(definitionContext, environment, owner) { const { id = 'Def', name, type = 'context' } = definitionContext; const sid = getUniqueId(id); this.id = id; diff --git a/src/Environment.js b/src/Environment.js index 43c3db60..06adfcf8 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -1,4 +1,4 @@ -import Expressions from './Expressions.js'; +import { Expressions } from './Expressions.js'; import { Scripts } from './Scripts.js'; import { Timers } from './Timers.js'; @@ -12,7 +12,7 @@ const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. * @param {import('types').EnvironmentOptions} [options] */ -export default function Environment(options = {}) { +export function Environment(options = {}) { this.options = validateOptions(options); this.expressions = options.expressions || Expressions(); diff --git a/src/EventBroker.js b/src/EventBroker.js index f1e88728..927d55f5 100644 --- a/src/EventBroker.js +++ b/src/EventBroker.js @@ -76,7 +76,7 @@ export function EventBroker(brokerOwner, options, onBrokerReturn) { this.options = options; this.eventPrefix = options.prefix; - const broker = (this.broker = Broker(brokerOwner)); + const broker = (this.broker = new Broker(brokerOwner)); broker.assertExchange('event', 'topic', options); broker.on('return', onBrokerReturn ? onBrokerReturn.bind(brokerOwner) : this._onBrokerReturnFn.bind(this)); diff --git a/src/Expressions.js b/src/Expressions.js index 318ad940..fedac898 100644 --- a/src/Expressions.js +++ b/src/Expressions.js @@ -1,9 +1,8 @@ -import getPropertyValue from './getPropertyValue.js'; - +import { getPropertyValue } from './getPropertyValue.js'; const isExpressionPattern = /^\${(.+?)}$/; const expressionPattern = /\${(.+?)}/; -export default function Expressions() { +export function Expressions() { return { resolveExpression, isExpression, diff --git a/src/activity/Activity.js b/src/activity/Activity.js index 337880f3..44de1a5b 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -1,4 +1,4 @@ -import ActivityExecution from './ActivityExecution.js'; +import { ActivityExecution } from './ActivityExecution.js'; import { getUniqueId } from '../shared.js'; import { ActivityApi } from '../Api.js'; import { ActivityBroker } from '../EventBroker.js'; @@ -24,8 +24,6 @@ const K_FLAGS = Symbol.for('flags'); const K_FLOWS = Symbol.for('flows'); const K_FORMATTER = Symbol.for('formatter'); -export default Activity; - /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param {import('types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution diff --git a/src/activity/ActivityExecution.js b/src/activity/ActivityExecution.js index 27285af5..bce7e8a7 100644 --- a/src/activity/ActivityExecution.js +++ b/src/activity/ActivityExecution.js @@ -5,15 +5,13 @@ import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS } from '../constants const K_EXECUTE_Q = Symbol.for('executeQ'); const K_POSTPONED = Symbol.for('postponed'); -export default ActivityExecution; - /** * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour * and drives the execute message flow over the activity broker. * @param {import('types').Activity} activity * @param {import('types').ContextInstance} context */ -function ActivityExecution(activity, context) { +export function ActivityExecution(activity, context) { this.activity = activity; this.context = context; this.id = activity.id; diff --git a/src/activity/Dummy.js b/src/activity/Dummy.js index b5114a8f..6a1512a6 100644 --- a/src/activity/Dummy.js +++ b/src/activity/Dummy.js @@ -1,6 +1,6 @@ import { cloneParent } from '../messageHelper.js'; -export default function DummyActivity(activityDef) { +export function DummyActivity(activityDef) { const { id, type = 'dummy', name, parent, behaviour } = activityDef; return { id, diff --git a/src/activity/Escalation.js b/src/activity/Escalation.js index f4eac897..491f8bcf 100644 --- a/src/activity/Escalation.js +++ b/src/activity/Escalation.js @@ -1,4 +1,4 @@ -export default function Escalation(signalDef, context) { +export function Escalation(signalDef, context) { const { id, type, name, parent: originalParent } = signalDef; const { environment } = context; const parent = { ...originalParent }; diff --git a/src/activity/ExecutionScope.js b/src/activity/ExecutionScope.js index 662fd261..5ac42e97 100644 --- a/src/activity/ExecutionScope.js +++ b/src/activity/ExecutionScope.js @@ -1,7 +1,7 @@ import { cloneMessage } from '../messageHelper.js'; import { ActivityError, BpmnError } from '../error/Errors.js'; -export default function ExecutionScope(activity, initMessage) { +export function ExecutionScope(activity, initMessage) { const { id, type, environment, logger } = activity; const { fields, content, properties } = cloneMessage(initMessage); diff --git a/src/activity/Message.js b/src/activity/Message.js index 91d96237..4821ac11 100644 --- a/src/activity/Message.js +++ b/src/activity/Message.js @@ -1,4 +1,4 @@ -export default function Message(messageDef, context) { +export function Message(messageDef, context) { const { id, type, name, parent: originalParent } = messageDef; const { environment } = context; const parent = { ...originalParent }; diff --git a/src/activity/Signal.js b/src/activity/Signal.js index 4e639692..b38a9de3 100644 --- a/src/activity/Signal.js +++ b/src/activity/Signal.js @@ -1,4 +1,4 @@ -export default function Signal(signalDef, context) { +export function Signal(signalDef, context) { const { id, type = 'Signal', name, parent: originalParent } = signalDef; const { environment } = context; const parent = { ...originalParent }; diff --git a/src/condition.js b/src/condition.js index dfe5e9f8..37bf2c85 100644 --- a/src/condition.js +++ b/src/condition.js @@ -1,5 +1,4 @@ -import ExecutionScope from './activity/ExecutionScope.js'; - +import { ExecutionScope } from './activity/ExecutionScope.js'; /** * Script condition * @param {import('types').ElementBase} owner diff --git a/src/definition/Definition.js b/src/definition/Definition.js index a43ecaca..f5a85329 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -1,4 +1,4 @@ -import DefinitionExecution from './DefinitionExecution.js'; +import { DefinitionExecution } from './DefinitionExecution.js'; import { DefinitionApi } from '../Api.js'; import { DefinitionBroker } from '../EventBroker.js'; import { getUniqueId, getOptionsAndCallback } from '../shared.js'; @@ -15,8 +15,6 @@ import { K_STOPPED, } from '../constants.js'; -export default Definition; - /** * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and * mediates inter-process messaging. @@ -63,6 +61,7 @@ export function Definition(context, options) { }; const { broker, on, once, waitFor, emit, emitFatal } = DefinitionBroker(this, onBrokerReturn); + /** @type {import('smqp').Broker} */ this.broker = broker; this.on = on; diff --git a/src/definition/DefinitionExecution.js b/src/definition/DefinitionExecution.js index 7a99bc4a..ef948fbb 100644 --- a/src/definition/DefinitionExecution.js +++ b/src/definition/DefinitionExecution.js @@ -13,7 +13,7 @@ const K_PROCESSES = Symbol.for('processes'); * @param {import('types').Definition} definition * @param {import('types').ContextInstance} context */ -export default function DefinitionExecution(definition, context) { +export function DefinitionExecution(definition, context) { const broker = definition.broker; /** @private */ diff --git a/src/error/BpmnError.js b/src/error/BpmnError.js index bd5fa04b..dc843879 100644 --- a/src/error/BpmnError.js +++ b/src/error/BpmnError.js @@ -1,4 +1,4 @@ -export default function BpmnErrorActivity(errorDef, context) { +export function BpmnErrorActivity(errorDef, context) { const { id, type, name = 'BpmnError', behaviour = {} } = errorDef; const { environment } = context; diff --git a/src/eventDefinitions/CancelEventDefinition.js b/src/eventDefinitions/CancelEventDefinition.js index 1b00cc9a..0be889a8 100644 --- a/src/eventDefinitions/CancelEventDefinition.js +++ b/src/eventDefinitions/CancelEventDefinition.js @@ -1,7 +1,7 @@ import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE } from '../constants.js'; -export default function CancelEventDefinition(activity, eventDefinition) { +export function CancelEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const type = eventDefinition.type; diff --git a/src/eventDefinitions/CompensateEventDefinition.js b/src/eventDefinitions/CompensateEventDefinition.js index 3a4f3f27..89fce2fa 100644 --- a/src/eventDefinitions/CompensateEventDefinition.js +++ b/src/eventDefinitions/CompensateEventDefinition.js @@ -5,7 +5,7 @@ import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q } from '../constants.js'; const K_COMPENSATE_Q = Symbol.for('compensateQ'); const K_ASSOCIATIONS = Symbol.for('associations'); -export default function CompensateEventDefinition(activity, eventDefinition, context) { +export function CompensateEventDefinition(activity, eventDefinition, context) { const { id, broker, environment, isThrowing } = activity; this.id = id; diff --git a/src/eventDefinitions/ConditionalEventDefinition.js b/src/eventDefinitions/ConditionalEventDefinition.js index 023cc856..2ac0699a 100644 --- a/src/eventDefinitions/ConditionalEventDefinition.js +++ b/src/eventDefinitions/ConditionalEventDefinition.js @@ -3,7 +3,7 @@ import { ActivityError } from '../error/Errors.js'; import { ScriptCondition, ExpressionCondition } from '../condition.js'; import { K_EXECUTE_MESSAGE } from '../constants.js'; -export default function ConditionalEventDefinition(activity, eventDefinition, _context, index) { +export function ConditionalEventDefinition(activity, eventDefinition, _context, index) { const { id, broker, environment } = activity; const { type = 'ConditionalEventDefinition', behaviour = {} } = eventDefinition; diff --git a/src/eventDefinitions/ErrorEventDefinition.js b/src/eventDefinitions/ErrorEventDefinition.js index f108ec45..d91ac043 100644 --- a/src/eventDefinitions/ErrorEventDefinition.js +++ b/src/eventDefinitions/ErrorEventDefinition.js @@ -2,7 +2,7 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; -export default function ErrorEventDefinition(activity, eventDefinition) { +export function ErrorEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type = 'ErrorEventDefinition', behaviour = {} } = eventDefinition; diff --git a/src/eventDefinitions/EscalationEventDefinition.js b/src/eventDefinitions/EscalationEventDefinition.js index fbedae95..db1e237e 100644 --- a/src/eventDefinitions/EscalationEventDefinition.js +++ b/src/eventDefinitions/EscalationEventDefinition.js @@ -1,11 +1,11 @@ -import getPropertyValue from '../getPropertyValue.js'; +import { getPropertyValue } from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT } from '../constants.js'; const K_REFERENCE = Symbol.for('reference'); -export default function EscalationEventDefinition(activity, eventDefinition) { +export function EscalationEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type, behaviour = {} } = eventDefinition; diff --git a/src/eventDefinitions/EventDefinitionExecution.js b/src/eventDefinitions/EventDefinitionExecution.js index f6d8f72d..68c41f1c 100644 --- a/src/eventDefinitions/EventDefinitionExecution.js +++ b/src/eventDefinitions/EventDefinitionExecution.js @@ -1,7 +1,7 @@ import { cloneContent, unshiftParent, shiftParent, cloneParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_STOPPED } from '../constants.js'; -export default function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKey = 'execute.completed') { +export function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKey = 'execute.completed') { this.id = activity.id; this.activity = activity; this.broker = activity.broker; diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 07330065..4c743873 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -2,7 +2,7 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_EXECUTE_MESSAGE } from '../constants.js'; -export default function LinkEventDefinition(activity, eventDefinition) { +export function LinkEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type = 'LinkEventDefinition', behaviour } = eventDefinition; diff --git a/src/eventDefinitions/MessageEventDefinition.js b/src/eventDefinitions/MessageEventDefinition.js index f52d9d29..3cdc6439 100644 --- a/src/eventDefinitions/MessageEventDefinition.js +++ b/src/eventDefinitions/MessageEventDefinition.js @@ -1,9 +1,9 @@ -import getPropertyValue from '../getPropertyValue.js'; +import { getPropertyValue } from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; -export default function MessageEventDefinition(activity, eventDefinition) { +export function MessageEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type = 'MessageEventDefinition', behaviour = {} } = eventDefinition; diff --git a/src/eventDefinitions/SignalEventDefinition.js b/src/eventDefinitions/SignalEventDefinition.js index 5cb144eb..2be46198 100644 --- a/src/eventDefinitions/SignalEventDefinition.js +++ b/src/eventDefinitions/SignalEventDefinition.js @@ -1,9 +1,9 @@ -import getPropertyValue from '../getPropertyValue.js'; +import { getPropertyValue } from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; -export default function SignalEventDefinition(activity, eventDefinition) { +export function SignalEventDefinition(activity, eventDefinition) { const { id, broker, environment, isStart, isThrowing } = activity; const { type, behaviour = {} } = eventDefinition; diff --git a/src/eventDefinitions/TerminateEventDefinition.js b/src/eventDefinitions/TerminateEventDefinition.js index 2b8d6c7e..42dae166 100644 --- a/src/eventDefinitions/TerminateEventDefinition.js +++ b/src/eventDefinitions/TerminateEventDefinition.js @@ -1,6 +1,6 @@ import { cloneContent, shiftParent } from '../messageHelper.js'; -export default function TerminateEventDefinition(activity, eventDefinition) { +export function TerminateEventDefinition(activity, eventDefinition) { const { id, broker, environment } = activity; const { type = 'TerminateEventDefinition' } = eventDefinition; diff --git a/src/eventDefinitions/TimerEventDefinition.js b/src/eventDefinitions/TimerEventDefinition.js index 341743bb..b9b4b3ba 100644 --- a/src/eventDefinitions/TimerEventDefinition.js +++ b/src/eventDefinitions/TimerEventDefinition.js @@ -8,7 +8,7 @@ const K_TIMER = Symbol.for('timer'); const timerTypes = new Set(['timeDuration', 'timeDate', 'timeCycle']); -export default function TimerEventDefinition(activity, eventDefinition) { +export function TimerEventDefinition(activity, eventDefinition) { const type = (this.type = eventDefinition.type || 'TimerEventDefinition'); this.activity = activity; const environment = (this.environment = activity.environment); diff --git a/src/eventDefinitions/index.js b/src/eventDefinitions/index.js index ac10d6fe..76581636 100644 --- a/src/eventDefinitions/index.js +++ b/src/eventDefinitions/index.js @@ -1,14 +1,13 @@ -import CancelEventDefinition from './CancelEventDefinition.js'; -import CompensateEventDefinition from './CompensateEventDefinition.js'; -import ConditionalEventDefinition from './ConditionalEventDefinition.js'; -import ErrorEventDefinition from './ErrorEventDefinition.js'; -import EscalationEventDefinition from './EscalationEventDefinition.js'; -import LinkEventDefinition from './LinkEventDefinition.js'; -import MessageEventDefinition from './MessageEventDefinition.js'; -import SignalEventDefinition from './SignalEventDefinition.js'; -import TerminateEventDefinition from './TerminateEventDefinition.js'; -import TimerEventDefinition from './TimerEventDefinition.js'; - +import { CancelEventDefinition } from './CancelEventDefinition.js'; +import { CompensateEventDefinition } from './CompensateEventDefinition.js'; +import { ConditionalEventDefinition } from './ConditionalEventDefinition.js'; +import { ErrorEventDefinition } from './ErrorEventDefinition.js'; +import { EscalationEventDefinition } from './EscalationEventDefinition.js'; +import { LinkEventDefinition } from './LinkEventDefinition.js'; +import { MessageEventDefinition } from './MessageEventDefinition.js'; +import { SignalEventDefinition } from './SignalEventDefinition.js'; +import { TerminateEventDefinition } from './TerminateEventDefinition.js'; +import { TimerEventDefinition } from './TimerEventDefinition.js'; export { CancelEventDefinition, CompensateEventDefinition, diff --git a/src/events/BoundaryEvent.js b/src/events/BoundaryEvent.js index 55479855..5134a812 100644 --- a/src/events/BoundaryEvent.js +++ b/src/events/BoundaryEvent.js @@ -1,5 +1,5 @@ -import Activity from '../activity/Activity.js'; -import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; +import { Activity } from '../activity/Activity.js'; +import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent, cloneMessage } from '../messageHelper.js'; import { brokerSafeId } from '../shared.js'; import { K_EXECUTE_MESSAGE, K_EXECUTION } from '../constants.js'; @@ -8,7 +8,7 @@ const K_ATTACHED_TAGS = Symbol.for('attachedConsumers'); const K_COMPLETE_CONTENT = Symbol.for('completeContent'); const K_SHOVELS = Symbol.for('shovels'); -export default function BoundaryEvent(activityDef, context) { +export function BoundaryEvent(activityDef, context) { return new Activity(BoundaryEventBehaviour, activityDef, context); } diff --git a/src/events/EndEvent.js b/src/events/EndEvent.js index 2890981e..017e79a2 100644 --- a/src/events/EndEvent.js +++ b/src/events/EndEvent.js @@ -1,9 +1,9 @@ -import Activity from '../activity/Activity.js'; -import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; +import { Activity } from '../activity/Activity.js'; +import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; import { K_EXECUTION } from '../constants.js'; -export default function EndEvent(activityDef, context) { +export function EndEvent(activityDef, context) { return new Activity(EndEventBehaviour, { ...activityDef, isThrowing: true }, context); } diff --git a/src/events/IntermediateCatchEvent.js b/src/events/IntermediateCatchEvent.js index d72e3219..81cadefa 100644 --- a/src/events/IntermediateCatchEvent.js +++ b/src/events/IntermediateCatchEvent.js @@ -1,9 +1,9 @@ -import Activity from '../activity/Activity.js'; -import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; +import { Activity } from '../activity/Activity.js'; +import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; import { K_EXECUTION } from '../constants.js'; -export default function IntermediateCatchEvent(activityDef, context) { +export function IntermediateCatchEvent(activityDef, context) { return new Activity(IntermediateCatchEventBehaviour, { ...activityDef, isCatching: true }, context); } diff --git a/src/events/IntermediateThrowEvent.js b/src/events/IntermediateThrowEvent.js index d32381a1..82a6884b 100644 --- a/src/events/IntermediateThrowEvent.js +++ b/src/events/IntermediateThrowEvent.js @@ -1,9 +1,9 @@ -import Activity from '../activity/Activity.js'; -import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; +import { Activity } from '../activity/Activity.js'; +import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; import { K_EXECUTION } from '../constants.js'; -export default function IntermediateThrowEvent(activityDef, context) { +export function IntermediateThrowEvent(activityDef, context) { return new Activity(IntermediateThrowEventBehaviour, { ...activityDef, isThrowing: true }, context); } diff --git a/src/events/StartEvent.js b/src/events/StartEvent.js index 68fba97e..ae931651 100644 --- a/src/events/StartEvent.js +++ b/src/events/StartEvent.js @@ -1,9 +1,9 @@ -import Activity from '../activity/Activity.js'; -import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecution.js'; +import { Activity } from '../activity/Activity.js'; +import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExecution.js'; import { cloneContent } from '../messageHelper.js'; import { K_EXECUTE_MESSAGE, K_EXECUTION } from '../constants.js'; -export default function StartEvent(activityDef, context) { +export function StartEvent(activityDef, context) { return new Activity(StartEventBehaviour, activityDef, context); } diff --git a/src/events/index.js b/src/events/index.js index 5bc7b453..e3b9b309 100644 --- a/src/events/index.js +++ b/src/events/index.js @@ -1,8 +1,8 @@ -import BoundaryEvent, { BoundaryEventBehaviour } from './BoundaryEvent.js'; -import EndEvent, { EndEventBehaviour } from './EndEvent.js'; -import IntermediateCatchEvent, { IntermediateCatchEventBehaviour } from './IntermediateCatchEvent.js'; -import IntermediateThrowEvent, { IntermediateThrowEventBehaviour } from './IntermediateThrowEvent.js'; -import StartEvent, { StartEventBehaviour } from './StartEvent.js'; +import { BoundaryEvent, BoundaryEventBehaviour } from './BoundaryEvent.js'; +import { EndEvent, EndEventBehaviour } from './EndEvent.js'; +import { IntermediateCatchEvent, IntermediateCatchEventBehaviour } from './IntermediateCatchEvent.js'; +import { IntermediateThrowEvent, IntermediateThrowEventBehaviour } from './IntermediateThrowEvent.js'; +import { StartEvent, StartEventBehaviour } from './StartEvent.js'; export { BoundaryEvent, diff --git a/src/flows/Association.js b/src/flows/Association.js index ed6460a1..bbd850b9 100644 --- a/src/flows/Association.js +++ b/src/flows/Association.js @@ -10,7 +10,7 @@ import { K_COUNTERS } from '../constants.js'; * @param {import('moddle-context-serializer').SerializableElement} associationDef * @param {import('types').ContextInstance} context */ -export default function Association(associationDef, { environment }) { +export function Association(associationDef, { environment }) { const { id, type = 'association', name, parent, targetId, sourceId, behaviour = {} } = associationDef; this.id = id; diff --git a/src/flows/MessageFlow.js b/src/flows/MessageFlow.js index 83f055d6..3be91797 100644 --- a/src/flows/MessageFlow.js +++ b/src/flows/MessageFlow.js @@ -13,7 +13,7 @@ const K_SOURCE_ELEMENT = Symbol.for('sourceElement'); * @param {import('moddle-context-serializer').SerializableElement} flowDef * @param {import('types').ContextInstance} context */ -export default function MessageFlow(flowDef, context) { +export function MessageFlow(flowDef, context) { const { id, type = 'messageflow', name, target, source, behaviour, parent } = flowDef; this.id = id; diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index 99157fe3..1d8adc4c 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -5,8 +5,6 @@ import { FlowApi } from '../Api.js'; import { ScriptCondition, ExpressionCondition } from '../condition.js'; import { K_COUNTERS } from '../constants.js'; -export default SequenceFlow; - /** * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. diff --git a/src/flows/index.js b/src/flows/index.js index 45b48ffa..fca308a3 100644 --- a/src/flows/index.js +++ b/src/flows/index.js @@ -1,5 +1,4 @@ -import Association from './Association.js'; -import MessageFlow from './MessageFlow.js'; -import SequenceFlow from './SequenceFlow.js'; - +import { Association } from './Association.js'; +import { MessageFlow } from './MessageFlow.js'; +import { SequenceFlow } from './SequenceFlow.js'; export { Association, MessageFlow, SequenceFlow }; diff --git a/src/gateways/EventBasedGateway.js b/src/gateways/EventBasedGateway.js index 8fd21c3e..7b4b67df 100644 --- a/src/gateways/EventBasedGateway.js +++ b/src/gateways/EventBasedGateway.js @@ -1,8 +1,8 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; import { K_COMPLETED, K_TARGETS } from '../constants.js'; -export default function EventBasedGateway(activityDef, context) { +export function EventBasedGateway(activityDef, context) { return new Activity(EventBasedGatewayBehaviour, activityDef, context); } diff --git a/src/gateways/ExclusiveGateway.js b/src/gateways/ExclusiveGateway.js index 1f4c0d16..3a57b71a 100644 --- a/src/gateways/ExclusiveGateway.js +++ b/src/gateways/ExclusiveGateway.js @@ -1,7 +1,7 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; -export default function ExclusiveGateway(activityDef, context) { +export function ExclusiveGateway(activityDef, context) { return new Activity(ExclusiveGatewayBehaviour, activityDef, context); } diff --git a/src/gateways/InclusiveGateway.js b/src/gateways/InclusiveGateway.js index 5e6c7b32..26ff692c 100644 --- a/src/gateways/InclusiveGateway.js +++ b/src/gateways/InclusiveGateway.js @@ -1,7 +1,7 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; -export default function InclusiveGateway(activityDef, context) { +export function InclusiveGateway(activityDef, context) { return new Activity(InclusiveGatewayBehaviour, activityDef, context); } diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index 030ca306..cd9653b9 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -1,4 +1,4 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { cloneContent, cloneMessage } from '../messageHelper.js'; import { K_EXECUTE_MESSAGE, K_TARGETS } from '../constants.js'; @@ -8,7 +8,7 @@ const STATE_SETUP = 'setup'; const K_PEERS = Symbol.for('peers'); const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); -export default function ParallelGateway(activityDef, context) { +export function ParallelGateway(activityDef, context) { const activity = new Activity(ParallelGatewayBehaviour, { ...activityDef, isParallelGateway: true }, context); const id = (this.id = activity.id); diff --git a/src/gateways/index.js b/src/gateways/index.js index 8f63f628..27d08a6f 100644 --- a/src/gateways/index.js +++ b/src/gateways/index.js @@ -1,7 +1,7 @@ -import EventBasedGateway, { EventBasedGatewayBehaviour } from './EventBasedGateway.js'; -import ExclusiveGateway, { ExclusiveGatewayBehaviour } from './ExclusiveGateway.js'; -import InclusiveGateway, { InclusiveGatewayBehaviour } from './InclusiveGateway.js'; -import ParallelGateway, { ParallelGatewayBehaviour } from './ParallelGateway.js'; +import { EventBasedGateway, EventBasedGatewayBehaviour } from './EventBasedGateway.js'; +import { ExclusiveGateway, ExclusiveGatewayBehaviour } from './ExclusiveGateway.js'; +import { InclusiveGateway, InclusiveGatewayBehaviour } from './InclusiveGateway.js'; +import { ParallelGateway, ParallelGatewayBehaviour } from './ParallelGateway.js'; export { EventBasedGateway, diff --git a/src/getPropertyValue.js b/src/getPropertyValue.js index ad0704b6..b8074cdf 100644 --- a/src/getPropertyValue.js +++ b/src/getPropertyValue.js @@ -3,7 +3,7 @@ const stringConstantPattern = /^(['"])(.*)\1$/; const numberConstantPattern = /^\W*-?\d+(.\d+)?\W*$/; const negativeIndexPattern = /^-\d+$/; -export default function getPropertyValue(inputContext, propertyPath, fnScope) { +export function getPropertyValue(inputContext, propertyPath, fnScope) { if (!inputContext) return; let resultValue; diff --git a/src/index.js b/src/index.js index e8b90e3a..0a6c4f10 100644 --- a/src/index.js +++ b/src/index.js @@ -1,22 +1,22 @@ -import Activity from './activity/Activity.js'; -import BpmnError from './error/BpmnError.js'; -import Context from './Context.js'; -import DataObject from './io/EnvironmentDataObject.js'; -import DataStore from './io/EnvironmentDataStore.js'; -import DataStoreReference from './io/EnvironmentDataStoreReference.js'; -import Definition from './definition/Definition.js'; -import Dummy from './activity/Dummy.js'; -import Environment from './Environment.js'; -import Escalation from './activity/Escalation.js'; -import InputOutputSpecification from './io/InputOutputSpecification.js'; -import Lane from './process/Lane.js'; -import LoopCharacteristics from './tasks/LoopCharacteristics.js'; -import Message from './activity/Message.js'; -import Process from './process/Process.js'; -import Properties from './io/Properties.js'; -import ServiceImplementation from './tasks/ServiceImplementation.js'; -import Signal from './activity/Signal.js'; -import StandardLoopCharacteristics from './tasks/StandardLoopCharacteristics.js'; +import { Activity } from './activity/Activity.js'; +import { BpmnErrorActivity as BpmnError } from './error/BpmnError.js'; +import { Context } from './Context.js'; +import { EnvironmentDataObject as DataObject } from './io/EnvironmentDataObject.js'; +import { EnvironmentDataStore as DataStore } from './io/EnvironmentDataStore.js'; +import { EnvironmentDataStoreReference as DataStoreReference } from './io/EnvironmentDataStoreReference.js'; +import { Definition } from './definition/Definition.js'; +import { DummyActivity as Dummy } from './activity/Dummy.js'; +import { Environment } from './Environment.js'; +import { Escalation } from './activity/Escalation.js'; +import { IoSpecification as InputOutputSpecification } from './io/InputOutputSpecification.js'; +import { Lane } from './process/Lane.js'; +import { LoopCharacteristics } from './tasks/LoopCharacteristics.js'; +import { Message } from './activity/Message.js'; +import { Process } from './process/Process.js'; +import { Properties } from './io/Properties.js'; +import { ServiceImplementation } from './tasks/ServiceImplementation.js'; +import { Signal } from './activity/Signal.js'; +import { StandardLoopCharacteristics } from './tasks/StandardLoopCharacteristics.js'; import { Association, MessageFlow, SequenceFlow } from './flows/index.js'; import { BoundaryEvent, EndEvent, IntermediateCatchEvent, IntermediateThrowEvent, StartEvent } from './events/index.js'; import { EventBasedGateway, ExclusiveGateway, InclusiveGateway, ParallelGateway } from './gateways/index.js'; diff --git a/src/io/BpmnIO.js b/src/io/BpmnIO.js index fefa5052..fc79d50f 100644 --- a/src/io/BpmnIO.js +++ b/src/io/BpmnIO.js @@ -1,4 +1,4 @@ -export default function BpmnIO(activity, context) { +export function BpmnIO(activity, context) { this.activity = activity; this.context = context; this.type = 'bpmnio'; diff --git a/src/io/EnvironmentDataObject.js b/src/io/EnvironmentDataObject.js index 88a1cf3c..f1a189c6 100644 --- a/src/io/EnvironmentDataObject.js +++ b/src/io/EnvironmentDataObject.js @@ -1,4 +1,4 @@ -export default function EnvironmentDataObject(dataObjectDef, { environment }) { +export function EnvironmentDataObject(dataObjectDef, { environment }) { const { id, type, name, behaviour, parent } = dataObjectDef; this.id = id; this.type = type; diff --git a/src/io/EnvironmentDataStore.js b/src/io/EnvironmentDataStore.js index cd540677..e549d16f 100644 --- a/src/io/EnvironmentDataStore.js +++ b/src/io/EnvironmentDataStore.js @@ -1,4 +1,4 @@ -export default function EnvironmentDataStore(dataStoreDef, { environment }) { +export function EnvironmentDataStore(dataStoreDef, { environment }) { const { id, type, name, behaviour, parent } = dataStoreDef; this.id = id; this.type = type; diff --git a/src/io/EnvironmentDataStoreReference.js b/src/io/EnvironmentDataStoreReference.js index 0c7451d1..94714fe3 100644 --- a/src/io/EnvironmentDataStoreReference.js +++ b/src/io/EnvironmentDataStoreReference.js @@ -1,4 +1,4 @@ -export default function EnvironmentDataStoreReference(dataObjectDef, { environment }) { +export function EnvironmentDataStoreReference(dataObjectDef, { environment }) { const { id, type, name, behaviour, parent } = dataObjectDef; this.id = id; this.type = type; diff --git a/src/io/InputOutputSpecification.js b/src/io/InputOutputSpecification.js index f4fe7f2a..68a19103 100644 --- a/src/io/InputOutputSpecification.js +++ b/src/io/InputOutputSpecification.js @@ -1,8 +1,8 @@ -import getPropertyValue from '../getPropertyValue.js'; +import { getPropertyValue } from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { K_CONSUMING } from '../constants.js'; -export default function IoSpecification(activity, ioSpecificationDef, context) { +export function IoSpecification(activity, ioSpecificationDef, context) { const { id, type = 'iospecification', behaviour = {} } = ioSpecificationDef; this.id = id; this.type = type; diff --git a/src/io/Properties.js b/src/io/Properties.js index 050e122b..33bd5b5b 100644 --- a/src/io/Properties.js +++ b/src/io/Properties.js @@ -1,9 +1,9 @@ -import getPropertyValue from '../getPropertyValue.js'; +import { getPropertyValue } from '../getPropertyValue.js'; import { K_CONSUMING } from '../constants.js'; const K_PROPERTIES = Symbol.for('properties'); -export default function Properties(activity, propertiesDef, context) { +export function Properties(activity, propertiesDef, context) { this.activity = activity; this.broker = activity.broker; diff --git a/src/process/Lane.js b/src/process/Lane.js index 0630ff67..2847107f 100644 --- a/src/process/Lane.js +++ b/src/process/Lane.js @@ -6,7 +6,7 @@ const K_PROCESS = Symbol.for('process'); * @param {import('types').Process} process * @param {import('moddle-context-serializer').SerializableElement} laneDefinition */ -export default function Lane(process, laneDefinition) { +export function Lane(process, laneDefinition) { const { broker, environment } = process; const { id, type, behaviour } = laneDefinition; diff --git a/src/process/Process.js b/src/process/Process.js index 371b9243..3c7a50f2 100644 --- a/src/process/Process.js +++ b/src/process/Process.js @@ -1,4 +1,4 @@ -import ProcessExecution from './ProcessExecution.js'; +import { ProcessExecution } from './ProcessExecution.js'; import { getUniqueId } from '../shared.js'; import { ProcessApi } from '../Api.js'; import { ProcessBroker } from '../EventBroker.js'; @@ -18,8 +18,6 @@ import { const K_LANES = Symbol.for('lanes'); -export default Process; - /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index c7a58cbf..7d379d36 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -4,8 +4,6 @@ import { getUniqueId } from '../shared.js'; import { ActivityTracker } from '../Tracker.js'; import { K_ACTIVATED, K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS, K_STATUS, K_STOPPED } from '../constants.js'; -export default ProcessExecution; - const K_ACTIVITY_Q = Symbol.for('activityQ'); const K_ELEMENTS = Symbol.for('elements'); const K_PARENT = Symbol.for('parent'); @@ -17,7 +15,7 @@ const K_TRACKER = Symbol.for('activity tracker'); * @param {import('types').Process | import('types').Activity} parentActivity * @param {import('types').ContextInstance} context */ -function ProcessExecution(parentActivity, context) { +export function ProcessExecution(parentActivity, context) { const { id, type, broker, isSubProcess, isTransaction } = parentActivity; /** @private */ diff --git a/src/tasks/CallActivity.js b/src/tasks/CallActivity.js index 70a1a572..62d48bae 100644 --- a/src/tasks/CallActivity.js +++ b/src/tasks/CallActivity.js @@ -1,8 +1,8 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { ActivityError } from '../error/Errors.js'; import { cloneContent } from '../messageHelper.js'; -export default function CallActivity(activityDef, context) { +export function CallActivity(activityDef, context) { return new Activity(CallActivityBehaviour, activityDef, context); } diff --git a/src/tasks/LoopCharacteristics.js b/src/tasks/LoopCharacteristics.js index 846c61c4..ec695a50 100644 --- a/src/tasks/LoopCharacteristics.js +++ b/src/tasks/LoopCharacteristics.js @@ -1,7 +1,7 @@ import { RunError } from '../error/Errors.js'; import { cloneContent, cloneMessage, unshiftParent, cloneParent } from '../messageHelper.js'; -export default function LoopCharacteristics(activity, loopCharacteristics) { +export function LoopCharacteristics(activity, loopCharacteristics) { this.activity = activity; this.loopCharacteristics = loopCharacteristics; const { type = 'LoopCharacteristics', behaviour = {} } = loopCharacteristics; diff --git a/src/tasks/ReceiveTask.js b/src/tasks/ReceiveTask.js index 332f8255..b30cb54a 100644 --- a/src/tasks/ReceiveTask.js +++ b/src/tasks/ReceiveTask.js @@ -1,8 +1,8 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; -export default function ReceiveTask(activityDef, context) { +export function ReceiveTask(activityDef, context) { const task = new Activity(ReceiveTaskBehaviour, activityDef, context); task.broker.assertQueue('message', { autoDelete: false, durable: true }); diff --git a/src/tasks/ScriptTask.js b/src/tasks/ScriptTask.js index ab2ef977..c99aeefc 100644 --- a/src/tasks/ScriptTask.js +++ b/src/tasks/ScriptTask.js @@ -1,9 +1,9 @@ -import Activity from '../activity/Activity.js'; -import ExecutionScope from '../activity/ExecutionScope.js'; +import { Activity } from '../activity/Activity.js'; +import { ExecutionScope } from '../activity/ExecutionScope.js'; import { ActivityError } from '../error/Errors.js'; import { cloneContent, cloneMessage } from '../messageHelper.js'; -export default function ScriptTask(activityDef, context) { +export function ScriptTask(activityDef, context) { return new Activity(ScriptTaskBehaviour, activityDef, context); } diff --git a/src/tasks/ServiceImplementation.js b/src/tasks/ServiceImplementation.js index e1a40ff3..03bb4877 100644 --- a/src/tasks/ServiceImplementation.js +++ b/src/tasks/ServiceImplementation.js @@ -1,6 +1,5 @@ -import ExecutionScope from '../activity/ExecutionScope.js'; - -export default function ServiceImplementation(activity) { +import { ExecutionScope } from '../activity/ExecutionScope.js'; +export function ServiceImplementation(activity) { this.type = `${activity.type}:implementation`; this.implementation = activity.behaviour.implementation; this.activity = activity; diff --git a/src/tasks/ServiceTask.js b/src/tasks/ServiceTask.js index ab449630..1f2d9112 100644 --- a/src/tasks/ServiceTask.js +++ b/src/tasks/ServiceTask.js @@ -1,8 +1,8 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { ActivityError } from '../error/Errors.js'; import { cloneMessage, cloneContent } from '../messageHelper.js'; -export default function ServiceTask(activityDef, context) { +export function ServiceTask(activityDef, context) { return new Activity(ServiceTaskBehaviour, activityDef, context); } diff --git a/src/tasks/SignalTask.js b/src/tasks/SignalTask.js index 1e7a4fed..16b53832 100644 --- a/src/tasks/SignalTask.js +++ b/src/tasks/SignalTask.js @@ -1,8 +1,8 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { ActivityError } from '../error/Errors.js'; import { cloneContent } from '../messageHelper.js'; -export default function SignalTask(activityDef, context) { +export function SignalTask(activityDef, context) { return new Activity(SignalTaskBehaviour, activityDef, context); } diff --git a/src/tasks/StandardLoopCharacteristics.js b/src/tasks/StandardLoopCharacteristics.js index 2c4094d7..52a269a6 100644 --- a/src/tasks/StandardLoopCharacteristics.js +++ b/src/tasks/StandardLoopCharacteristics.js @@ -1,6 +1,5 @@ -import LoopCharacteristics from './LoopCharacteristics.js'; - -export default function StandardLoopCharacteristics(activity, loopCharacteristics) { +import { LoopCharacteristics } from './LoopCharacteristics.js'; +export function StandardLoopCharacteristics(activity, loopCharacteristics) { let { behaviour } = loopCharacteristics; behaviour = { ...behaviour, isSequential: true }; return new LoopCharacteristics(activity, { ...loopCharacteristics, behaviour }); diff --git a/src/tasks/SubProcess.js b/src/tasks/SubProcess.js index 17e99c60..9057b1c4 100644 --- a/src/tasks/SubProcess.js +++ b/src/tasks/SubProcess.js @@ -1,11 +1,11 @@ -import Activity from '../activity/Activity.js'; -import ProcessExecution from '../process/ProcessExecution.js'; +import { Activity } from '../activity/Activity.js'; +import { ProcessExecution } from '../process/ProcessExecution.js'; import { cloneContent } from '../messageHelper.js'; const K_EXECUTIONS = Symbol.for('executions'); const K_ON_EXECUTION_COMPLETED = Symbol.for('execution completed handler'); -export default function SubProcess(activityDef, context) { +export function SubProcess(activityDef, context) { const triggeredByEvent = activityDef.behaviour && activityDef.behaviour.triggeredByEvent; const subProcess = new Activity(SubProcessBehaviour, { ...activityDef, isSubProcess: true, triggeredByEvent }, context); diff --git a/src/tasks/Task.js b/src/tasks/Task.js index 91de95cc..1a329874 100644 --- a/src/tasks/Task.js +++ b/src/tasks/Task.js @@ -1,7 +1,7 @@ -import Activity from '../activity/Activity.js'; +import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; -export default function Task(activityDef, context) { +export function Task(activityDef, context) { return new Activity(TaskBehaviour, activityDef, context); } diff --git a/src/tasks/Transaction.js b/src/tasks/Transaction.js index a17dbf98..e5b969ef 100644 --- a/src/tasks/Transaction.js +++ b/src/tasks/Transaction.js @@ -1,6 +1,5 @@ -import SubProcess from './SubProcess.js'; - -export default function Transaction(activityDef, context) { +import { SubProcess } from './SubProcess.js'; +export function Transaction(activityDef, context) { const transaction = { type: 'transaction', ...activityDef, isTransaction: true }; const activity = SubProcess(transaction, context); return activity; diff --git a/src/tasks/index.js b/src/tasks/index.js index 02da82b9..0098c625 100644 --- a/src/tasks/index.js +++ b/src/tasks/index.js @@ -1,12 +1,11 @@ -import CallActivity, { CallActivityBehaviour } from './CallActivity.js'; -import ReceiveTask, { ReceiveTaskBehaviour } from './ReceiveTask.js'; -import ScriptTask, { ScriptTaskBehaviour } from './ScriptTask.js'; -import ServiceTask, { ServiceTaskBehaviour } from './ServiceTask.js'; -import SignalTask, { SignalTaskBehaviour } from './SignalTask.js'; -import SubProcess, { SubProcessBehaviour } from './SubProcess.js'; -import Task, { TaskBehaviour } from './Task.js'; -import Transaction from './Transaction.js'; - +import { CallActivity, CallActivityBehaviour } from './CallActivity.js'; +import { ReceiveTask, ReceiveTaskBehaviour } from './ReceiveTask.js'; +import { ScriptTask, ScriptTaskBehaviour } from './ScriptTask.js'; +import { ServiceTask, ServiceTaskBehaviour } from './ServiceTask.js'; +import { SignalTask, SignalTaskBehaviour } from './SignalTask.js'; +import { SubProcess, SubProcessBehaviour } from './SubProcess.js'; +import { Task, TaskBehaviour } from './Task.js'; +import { Transaction } from './Transaction.js'; export { CallActivity, CallActivityBehaviour, diff --git a/test/Api-test.js b/test/Api-test.js index d383a279..06fa859a 100644 --- a/test/Api-test.js +++ b/test/Api-test.js @@ -1,7 +1,6 @@ import { Broker } from 'smqp'; import { ActivityApi } from '../src/Api.js'; -import Environment from '../src/Environment.js'; - +import { Environment } from '../src/Environment.js'; describe('Api', () => { it('Api without message throws', () => { expect(() => { diff --git a/test/Context-test.js b/test/Context-test.js index 67d72259..84fb4edd 100644 --- a/test/Context-test.js +++ b/test/Context-test.js @@ -1,5 +1,5 @@ -import Activity from '../src/activity/Activity.js'; -import Context from '../src/Context.js'; +import { Activity } from '../src/activity/Activity.js'; +import { Context } from '../src/Context.js'; import factory from './helpers/factory.js'; import testHelpers from './helpers/testHelpers.js'; diff --git a/test/Environment-test.js b/test/Environment-test.js index 30d3eade..51aaba40 100644 --- a/test/Environment-test.js +++ b/test/Environment-test.js @@ -1,4 +1,4 @@ -import Environment from '../src/Environment.js'; +import { Environment } from '../src/Environment.js'; import { Timers } from '../src/Timers.js'; describe('Environment', () => { diff --git a/test/activity-api-test.js b/test/activity-api-test.js index fad37da4..ba44ab2f 100644 --- a/test/activity-api-test.js +++ b/test/activity-api-test.js @@ -1,4 +1,4 @@ -import Activity from '../src/activity/Activity.js'; +import { Activity } from '../src/activity/Activity.js'; import testHelpers from './helpers/testHelpers.js'; import { cloneContent } from '../src/messageHelper.js'; diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index 73a31027..38a4a6ec 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -1,7 +1,7 @@ -import Activity from '../../src/activity/Activity.js'; -import Association from '../../src/flows/Association.js'; -import Environment from '../../src/Environment.js'; -import SequenceFlow from '../../src/flows/SequenceFlow.js'; +import { Activity } from '../../src/activity/Activity.js'; +import { Association } from '../../src/flows/Association.js'; +import { Environment } from '../../src/Environment.js'; +import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { TaskBehaviour, SignalTaskBehaviour } from '../../src/tasks/index.js'; diff --git a/test/activity/ActivityExecution-test.js b/test/activity/ActivityExecution-test.js index 41f9f100..a47b97fc 100644 --- a/test/activity/ActivityExecution-test.js +++ b/test/activity/ActivityExecution-test.js @@ -1,9 +1,9 @@ -import Activity from '../../src/activity/Activity.js'; -import ActivityExecution from '../../src/activity/ActivityExecution.js'; -import Environment from '../../src/Environment.js'; -import EventDefinitionExecution from '../../src/eventDefinitions/EventDefinitionExecution.js'; -import LoopCharacteristics from '../../src/tasks/LoopCharacteristics.js'; -import SequenceFlow from '../../src/flows/SequenceFlow.js'; +import { Activity } from '../../src/activity/Activity.js'; +import { ActivityExecution } from '../../src/activity/ActivityExecution.js'; +import { Environment } from '../../src/Environment.js'; +import { EventDefinitionExecution } from '../../src/eventDefinitions/EventDefinitionExecution.js'; +import { LoopCharacteristics } from '../../src/tasks/LoopCharacteristics.js'; +import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; import testHelpers from '../helpers/testHelpers.js'; const Logger = testHelpers.Logger; diff --git a/test/activity/ExecutionScope-test.js b/test/activity/ExecutionScope-test.js index 70cf6b21..941eac1b 100644 --- a/test/activity/ExecutionScope-test.js +++ b/test/activity/ExecutionScope-test.js @@ -1,5 +1,5 @@ -import Environment from '../../src/Environment.js'; -import ExecutionScope from '../../src/activity/ExecutionScope.js'; +import { Environment } from '../../src/Environment.js'; +import { ExecutionScope } from '../../src/activity/ExecutionScope.js'; import { ActivityError, BpmnError } from '../../src/error/Errors.js'; describe('ExecutionScope', () => { diff --git a/test/activity/activity-run-test.js b/test/activity/activity-run-test.js index 4f09642e..d9e7ee37 100644 --- a/test/activity/activity-run-test.js +++ b/test/activity/activity-run-test.js @@ -1,6 +1,6 @@ -import Activity from '../../src/activity/Activity.js'; -import Environment from '../../src/Environment.js'; -import SequenceFlow from '../../src/flows/SequenceFlow.js'; +import { Activity } from '../../src/activity/Activity.js'; +import { Environment } from '../../src/Environment.js'; +import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; import testHelpers from '../helpers/testHelpers.js'; import { TaskBehaviour } from '../../src/tasks/Task.js'; diff --git a/test/definition/Definition-test.js b/test/definition/Definition-test.js index 6225f0a4..dad5e37e 100644 --- a/test/definition/Definition-test.js +++ b/test/definition/Definition-test.js @@ -1,4 +1,4 @@ -import Environment from '../../src/Environment.js'; +import { Environment } from '../../src/Environment.js'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityError } from '../../src/error/Errors.js'; diff --git a/test/definition/DefinitionExecution-test.js b/test/definition/DefinitionExecution-test.js index 73ca943e..f59aa22e 100644 --- a/test/definition/DefinitionExecution-test.js +++ b/test/definition/DefinitionExecution-test.js @@ -1,5 +1,5 @@ -import Environment from '../../src/Environment.js'; -import DefinitionExecution from '../../src/definition/DefinitionExecution.js'; +import { Environment } from '../../src/Environment.js'; +import { DefinitionExecution } from '../../src/definition/DefinitionExecution.js'; import testHelpers from '../helpers/testHelpers.js'; import { DefinitionBroker, ProcessBroker } from '../../src/EventBroker.js'; diff --git a/test/error/BpmnError-test.js b/test/error/BpmnError-test.js index fb4935fd..39ea56c6 100644 --- a/test/error/BpmnError-test.js +++ b/test/error/BpmnError-test.js @@ -1,6 +1,5 @@ -import BpmnErrorActivity from '../../src/error/BpmnError.js'; -import Environment from '../../src/Environment.js'; - +import { BpmnErrorActivity } from '../../src/error/BpmnError.js'; +import { Environment } from '../../src/Environment.js'; describe('BpmnError', () => { it('returns BpmnError instanceof from error', () => { const bpmnError = BpmnErrorActivity( diff --git a/test/eventDefinitions/CancelEventDefinition-test.js b/test/eventDefinitions/CancelEventDefinition-test.js index c3880263..baa4a440 100644 --- a/test/eventDefinitions/CancelEventDefinition-test.js +++ b/test/eventDefinitions/CancelEventDefinition-test.js @@ -1,5 +1,5 @@ -import CancelEventDefinition from '../../src/eventDefinitions/CancelEventDefinition.js'; -import Environment from '../../src/Environment.js'; +import { CancelEventDefinition } from '../../src/eventDefinitions/CancelEventDefinition.js'; +import { Environment } from '../../src/Environment.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/CompensateEventDefinition-test.js b/test/eventDefinitions/CompensateEventDefinition-test.js index 8fc17b79..8476e0fd 100644 --- a/test/eventDefinitions/CompensateEventDefinition-test.js +++ b/test/eventDefinitions/CompensateEventDefinition-test.js @@ -1,9 +1,9 @@ -import Association from '../../src/flows/Association.js'; -import BoundaryEvent from '../../src/events/BoundaryEvent.js'; -import CompensateEventDefinition from '../../src/eventDefinitions/CompensateEventDefinition.js'; -import EndEvent from '../../src/events/EndEvent.js'; -import IntermediateThrowEvent from '../../src/events/IntermediateThrowEvent.js'; -import Task from '../../src/tasks/Task.js'; +import { Association } from '../../src/flows/Association.js'; +import { BoundaryEvent } from '../../src/events/BoundaryEvent.js'; +import { CompensateEventDefinition } from '../../src/eventDefinitions/CompensateEventDefinition.js'; +import { EndEvent } from '../../src/events/EndEvent.js'; +import { IntermediateThrowEvent } from '../../src/events/IntermediateThrowEvent.js'; +import { Task } from '../../src/tasks/Task.js'; import testHelpers from '../helpers/testHelpers.js'; describe('CompensateEventDefinition', () => { diff --git a/test/eventDefinitions/ConditionalEventDefinition-test.js b/test/eventDefinitions/ConditionalEventDefinition-test.js index 21b0e55b..f68db7fe 100644 --- a/test/eventDefinitions/ConditionalEventDefinition-test.js +++ b/test/eventDefinitions/ConditionalEventDefinition-test.js @@ -1,5 +1,5 @@ -import ConditionalEventDefinition from '../../src/eventDefinitions/ConditionalEventDefinition.js'; -import Environment from '../../src/Environment.js'; +import { ConditionalEventDefinition } from '../../src/eventDefinitions/ConditionalEventDefinition.js'; +import { Environment } from '../../src/Environment.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { ActivityApi } from '../../src/Api.js'; diff --git a/test/eventDefinitions/ErrorEventDefinition-test.js b/test/eventDefinitions/ErrorEventDefinition-test.js index 88fac0a8..45054da1 100644 --- a/test/eventDefinitions/ErrorEventDefinition-test.js +++ b/test/eventDefinitions/ErrorEventDefinition-test.js @@ -1,6 +1,6 @@ -import BpmnError from '../../src/error/BpmnError.js'; -import Environment from '../../src/Environment.js'; -import ErrorEventDefinition from '../../src/eventDefinitions/ErrorEventDefinition.js'; +import { BpmnErrorActivity as BpmnError } from '../../src/error/BpmnError.js'; +import { Environment } from '../../src/Environment.js'; +import { ErrorEventDefinition } from '../../src/eventDefinitions/ErrorEventDefinition.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; diff --git a/test/eventDefinitions/EscalationEventDefinition-test.js b/test/eventDefinitions/EscalationEventDefinition-test.js index 633b3340..f31b63bc 100644 --- a/test/eventDefinitions/EscalationEventDefinition-test.js +++ b/test/eventDefinitions/EscalationEventDefinition-test.js @@ -1,6 +1,6 @@ -import Environment from '../../src/Environment.js'; -import Escalation from '../../src/activity/Escalation.js'; -import EscalationEventDefinition from '../../src/eventDefinitions/EscalationEventDefinition.js'; +import { Environment } from '../../src/Environment.js'; +import { Escalation } from '../../src/activity/Escalation.js'; +import { EscalationEventDefinition } from '../../src/eventDefinitions/EscalationEventDefinition.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/EventDefinitionExecution-test.js b/test/eventDefinitions/EventDefinitionExecution-test.js index fc46294f..2302b202 100644 --- a/test/eventDefinitions/EventDefinitionExecution-test.js +++ b/test/eventDefinitions/EventDefinitionExecution-test.js @@ -1,4 +1,4 @@ -import EventDefinitionExecution from '../../src/eventDefinitions/EventDefinitionExecution.js'; +import { EventDefinitionExecution } from '../../src/eventDefinitions/EventDefinitionExecution.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { cloneContent } from '../../src/messageHelper.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/LinkEventDefinition-test.js b/test/eventDefinitions/LinkEventDefinition-test.js index a3e7e9bf..87d6d7a0 100644 --- a/test/eventDefinitions/LinkEventDefinition-test.js +++ b/test/eventDefinitions/LinkEventDefinition-test.js @@ -1,5 +1,5 @@ -import LinkEventDefinition from '../../src/eventDefinitions/LinkEventDefinition.js'; -import Environment from '../../src/Environment.js'; +import { LinkEventDefinition } from '../../src/eventDefinitions/LinkEventDefinition.js'; +import { Environment } from '../../src/Environment.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/MessageEventDefinition-test.js b/test/eventDefinitions/MessageEventDefinition-test.js index 381fdcd7..06f8290b 100644 --- a/test/eventDefinitions/MessageEventDefinition-test.js +++ b/test/eventDefinitions/MessageEventDefinition-test.js @@ -1,6 +1,6 @@ -import Message from '../../src/activity/Message.js'; -import MessageEventDefinition from '../../src/eventDefinitions/MessageEventDefinition.js'; -import Environment from '../../src/Environment.js'; +import { Message } from '../../src/activity/Message.js'; +import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; +import { Environment } from '../../src/Environment.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/SignalEventDefinition-test.js b/test/eventDefinitions/SignalEventDefinition-test.js index bd886874..9c2fb13d 100644 --- a/test/eventDefinitions/SignalEventDefinition-test.js +++ b/test/eventDefinitions/SignalEventDefinition-test.js @@ -1,9 +1,8 @@ -import Environment from '../../src/Environment.js'; -import SignalEventDefinition from '../../src/eventDefinitions/SignalEventDefinition.js'; -import testHelpers from '../helpers/testHelpers.js'; -import Signal from '../../src/activity/Signal.js'; +import { Environment } from '../../src/Environment.js'; +import { SignalEventDefinition } from '../../src/eventDefinitions/SignalEventDefinition.js'; +import testHelpers, { Logger } from '../helpers/testHelpers.js'; +import { Signal } from '../../src/activity/Signal.js'; import { ActivityBroker } from '../../src/EventBroker.js'; -import { Logger } from '../helpers/testHelpers.js'; describe('SignalEventDefinition', () => { let event; diff --git a/test/eventDefinitions/TerminateEventDefinition-test.js b/test/eventDefinitions/TerminateEventDefinition-test.js index 7b57f8d9..bc698647 100644 --- a/test/eventDefinitions/TerminateEventDefinition-test.js +++ b/test/eventDefinitions/TerminateEventDefinition-test.js @@ -1,5 +1,5 @@ -import Environment from '../../src/Environment.js'; -import TerminateEventDefinition from '../../src/eventDefinitions/TerminateEventDefinition.js'; +import { Environment } from '../../src/Environment.js'; +import { TerminateEventDefinition } from '../../src/eventDefinitions/TerminateEventDefinition.js'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('TerminateEventDefinition', () => { diff --git a/test/eventDefinitions/TimerEventDefinition-test.js b/test/eventDefinitions/TimerEventDefinition-test.js index bed3c40a..ea620427 100644 --- a/test/eventDefinitions/TimerEventDefinition-test.js +++ b/test/eventDefinitions/TimerEventDefinition-test.js @@ -1,7 +1,7 @@ import * as ck from 'chronokinesis'; -import Environment from '../../src/Environment.js'; +import { Environment } from '../../src/Environment.js'; import testHelpers from '../helpers/testHelpers.js'; -import TimerEventDefinition from '../../src/eventDefinitions/TimerEventDefinition.js'; +import { TimerEventDefinition } from '../../src/eventDefinitions/TimerEventDefinition.js'; import { ActivityApi, DefinitionApi } from '../../src/Api.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Timers } from '../../src/Timers.js'; diff --git a/test/events/BoundaryEvent-test.js b/test/events/BoundaryEvent-test.js index 93147834..87358e30 100644 --- a/test/events/BoundaryEvent-test.js +++ b/test/events/BoundaryEvent-test.js @@ -1,9 +1,9 @@ import testHelpers from '../helpers/testHelpers.js'; -import Environment from '../../src/Environment.js'; -import ErrorEventDefinition from '../../src/eventDefinitions/ErrorEventDefinition.js'; -import MessageEventDefinition from '../../src/eventDefinitions/MessageEventDefinition.js'; -import SignalTask from '../../src/tasks/SignalTask.js'; -import BoundaryEvent, { BoundaryEventBehaviour } from '../../src/events/BoundaryEvent.js'; +import { Environment } from '../../src/Environment.js'; +import { ErrorEventDefinition } from '../../src/eventDefinitions/ErrorEventDefinition.js'; +import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; +import { SignalTask } from '../../src/tasks/SignalTask.js'; +import { BoundaryEvent, BoundaryEventBehaviour } from '../../src/events/BoundaryEvent.js'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('BoundaryEvent', () => { diff --git a/test/events/EndEvent-test.js b/test/events/EndEvent-test.js index ea6ec8e1..0608df92 100644 --- a/test/events/EndEvent-test.js +++ b/test/events/EndEvent-test.js @@ -1,5 +1,5 @@ -import EndEvent from '../../src/events/EndEvent.js'; -import SequenceFlow from '../../src/flows/SequenceFlow.js'; +import { EndEvent } from '../../src/events/EndEvent.js'; +import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; import testHelpers from '../helpers/testHelpers.js'; describe('EndEvent', () => { diff --git a/test/events/IntermediateCatchEvent-test.js b/test/events/IntermediateCatchEvent-test.js index 2661b24d..13404f42 100644 --- a/test/events/IntermediateCatchEvent-test.js +++ b/test/events/IntermediateCatchEvent-test.js @@ -1,4 +1,4 @@ -import IntermediateCatchEvent from '../../src/events/IntermediateCatchEvent.js'; +import { IntermediateCatchEvent } from '../../src/events/IntermediateCatchEvent.js'; import testHelpers from '../helpers/testHelpers.js'; describe('IntermediateCatchEvent', () => { diff --git a/test/events/StartEvent-test.js b/test/events/StartEvent-test.js index cfbef9ff..3b8ccb32 100644 --- a/test/events/StartEvent-test.js +++ b/test/events/StartEvent-test.js @@ -1,6 +1,6 @@ import JsExtension from '../resources/extensions/JsExtension.js'; -import MessageEventDefinition from '../../src/eventDefinitions/MessageEventDefinition.js'; -import StartEvent from '../../src/events/StartEvent.js'; +import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; +import { StartEvent } from '../../src/events/StartEvent.js'; import testHelpers from '../helpers/testHelpers.js'; describe('StartEvent', () => { diff --git a/test/expressions-test.js b/test/expressions-test.js index 91d85bba..fb301621 100644 --- a/test/expressions-test.js +++ b/test/expressions-test.js @@ -1,4 +1,4 @@ -import Expressions from '../src/Expressions.js'; +import { Expressions } from '../src/Expressions.js'; import { resolveExpression } from '@aircall/expression-parser'; const expressions = Expressions(); diff --git a/test/feature/Definition-feature.js b/test/feature/Definition-feature.js index 41eb11b9..08536270 100644 --- a/test/feature/Definition-feature.js +++ b/test/feature/Definition-feature.js @@ -1,7 +1,6 @@ import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; -import Definition from '../../src/definition/Definition.js'; - +import { Definition } from 'bpmn-elements'; const extensions = { camunda: { moddleOptions: testHelpers.camundaBpmnModdle, diff --git a/test/feature/EventBasedGateway-feature.js b/test/feature/EventBasedGateway-feature.js index e87310a8..a90378f4 100644 --- a/test/feature/EventBasedGateway-feature.js +++ b/test/feature/EventBasedGateway-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/activity-feature.js b/test/feature/activity-feature.js index 7614ada6..35914f50 100644 --- a/test/feature/activity-feature.js +++ b/test/feature/activity-feature.js @@ -1,9 +1,10 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; Feature('Activity', () => { Scenario('When a task is discarded by multiple flows', () => { + /** @type {Definition} */ let definition; Given('a process with several decisions all ending up in one manual task', async () => { diff --git a/test/feature/activity-io-feature.js b/test/feature/activity-io-feature.js index 5139a848..9ae26036 100644 --- a/test/feature/activity-io-feature.js +++ b/test/feature/activity-io-feature.js @@ -1,10 +1,12 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; Feature('Activity IO', () => { Scenario('Activity with property that references input DataObject', () => { - let definition, taskMessage; + /** @type {Definition} */ + let definition; + let taskMessage; Given('a process with an activity with property', async () => { const source = factory.resource('engine-issue-139.bpmn'); const context = await testHelpers.context(source); @@ -43,7 +45,9 @@ Feature('Activity IO', () => { }); Scenario('Activity with properties that references output DataObject by association', () => { - let definition, taskMessage; + /** @type {import('../../src/definition/Definition.js').Definition} */ + let definition; + let taskMessage; Given('a process with an activity with property', async () => { const source = ` { }); Scenario('Activity with properties that references output DataObject by directly', () => { - let definition, taskMessage; + /** @type {Definition} */ + let definition; + let taskMessage; Given('a process with an activity with property', async () => { const source = ` { }); Scenario('both IO specification and properties', () => { - let definition, taskMessage; + /** @type {Definition} */ + let definition; + let taskMessage; Given('a user task with properties and IO specification', async () => { const source = ` { after(ck.reset); diff --git a/test/feature/compensation-feature.js b/test/feature/compensation-feature.js index c3161b8a..f61ecd94 100644 --- a/test/feature/compensation-feature.js +++ b/test/feature/compensation-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; Feature('Compensation', () => { diff --git a/test/feature/conditional-event-feature.js b/test/feature/conditional-event-feature.js index 506d51ff..8505c362 100644 --- a/test/feature/conditional-event-feature.js +++ b/test/feature/conditional-event-feature.js @@ -1,4 +1,4 @@ -import { Definition } from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; import js from '../resources/extensions/JsExtension.js'; diff --git a/test/feature/definition-output-feature.js b/test/feature/definition-output-feature.js index d869c789..d38b9a45 100644 --- a/test/feature/definition-output-feature.js +++ b/test/feature/definition-output-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; Feature('Definition output', () => { diff --git a/test/feature/dummy-feature.js b/test/feature/dummy-feature.js index 815e5a3d..b53c3ac0 100644 --- a/test/feature/dummy-feature.js +++ b/test/feature/dummy-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/environment-feature.js b/test/feature/environment-feature.js index c7ddba33..5c6fd614 100644 --- a/test/feature/environment-feature.js +++ b/test/feature/environment-feature.js @@ -1,6 +1,5 @@ import testHelpers from '../helpers/testHelpers.js'; -import Definition from '../../src/definition/Definition.js'; - +import { Definition } from 'bpmn-elements'; Feature('Environment', () => { Scenario('A definition with one process and a user task', () => { const source = ` diff --git a/test/feature/errors-feature.js b/test/feature/errors-feature.js index c53220c2..c4c9f0e1 100644 --- a/test/feature/errors-feature.js +++ b/test/feature/errors-feature.js @@ -1,9 +1,8 @@ import CamundaExtension from '../resources/extensions/CamundaExtension.js'; -import Definition from '../../src/definition/Definition.js'; +import { ActivityError, Definition } from 'bpmn-elements'; +import { BpmnError } from 'bpmn-elements/errors'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; -import { ActivityError, BpmnError } from '../../src/error/Errors.js'; - const bpmnErrorSource = factory.resource('bpmn-error.bpmn'); class CustomError extends Error { diff --git a/test/feature/escalation-feature.js b/test/feature/escalation-feature.js index 5ba8ed67..1e8bac2e 100644 --- a/test/feature/escalation-feature.js +++ b/test/feature/escalation-feature.js @@ -1,5 +1,5 @@ import CamundaExtension from '../resources/extensions/CamundaExtension.js'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/expression-feature.js b/test/feature/expression-feature.js index 46b98f2e..eb5c7880 100644 --- a/test/feature/expression-feature.js +++ b/test/feature/expression-feature.js @@ -1,5 +1,5 @@ import testHelpers from '../helpers/testHelpers.js'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import { resolveExpression } from '@aircall/expression-parser'; Feature('expressions', () => { diff --git a/test/feature/extension-feature.js b/test/feature/extension-feature.js index 495f4e0a..95291f0b 100644 --- a/test/feature/extension-feature.js +++ b/test/feature/extension-feature.js @@ -1,6 +1,5 @@ import testHelpers from '../helpers/testHelpers.js'; -import Definition from '../../src/definition/Definition.js'; - +import { Definition } from 'bpmn-elements'; const camunda = testHelpers.camundaBpmnModdle; const extensions = { diff --git a/test/feature/format-feature.js b/test/feature/format-feature.js index 9b9791ae..7b3ff7a3 100644 --- a/test/feature/format-feature.js +++ b/test/feature/format-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; Feature('Format', () => { diff --git a/test/feature/io-feature.js b/test/feature/io-feature.js index 606ac8a4..345cf737 100644 --- a/test/feature/io-feature.js +++ b/test/feature/io-feature.js @@ -1,5 +1,5 @@ import camunda from '../resources/extensions/CamundaExtension.js'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/issues/issues-feature.js b/test/feature/issues/issues-feature.js index a6f8a6ec..7557f6f7 100644 --- a/test/feature/issues/issues-feature.js +++ b/test/feature/issues/issues-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../../helpers/factory.js'; import testHelpers from '../../helpers/testHelpers.js'; import js from '../../resources/extensions/JsExtension.js'; diff --git a/test/feature/messaging-feature.js b/test/feature/messaging-feature.js index f6fbd782..8cc86ef5 100644 --- a/test/feature/messaging-feature.js +++ b/test/feature/messaging-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; diff --git a/test/feature/multiple-startevent-feature.js b/test/feature/multiple-startevent-feature.js index 015e80d9..26597ea2 100644 --- a/test/feature/multiple-startevent-feature.js +++ b/test/feature/multiple-startevent-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; diff --git a/test/feature/noExecutableProcess-feature.js b/test/feature/noExecutableProcess-feature.js index 4d238592..7f2afe31 100644 --- a/test/feature/noExecutableProcess-feature.js +++ b/test/feature/noExecutableProcess-feature.js @@ -1,7 +1,6 @@ import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; -import Definition from '../../src/definition/Definition.js'; - +import { Definition } from 'bpmn-elements'; const extensions = { camunda: { moddleOptions: testHelpers.camundaBpmnModdle, diff --git a/test/feature/outbound-flows-feature.js b/test/feature/outbound-flows-feature.js index 34dc659d..efa5be40 100644 --- a/test/feature/outbound-flows-feature.js +++ b/test/feature/outbound-flows-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/performance-feature.js b/test/feature/performance-feature.js index 12fd2a70..1bd2fe78 100644 --- a/test/feature/performance-feature.js +++ b/test/feature/performance-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/recover-resume-feature.js b/test/feature/recover-resume-feature.js index c50c8169..1f5447f6 100644 --- a/test/feature/recover-resume-feature.js +++ b/test/feature/recover-resume-feature.js @@ -1,5 +1,5 @@ import testHelpers from '../helpers/testHelpers.js'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; const motherOfAll = factory.resource('mother-of-all.bpmn'); diff --git a/test/feature/script-feature.js b/test/feature/script-feature.js index 1ce87118..234cdb18 100644 --- a/test/feature/script-feature.js +++ b/test/feature/script-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; class Scripts { diff --git a/test/feature/sequence-flow-feature.js b/test/feature/sequence-flow-feature.js index 271ec27a..815d9d09 100644 --- a/test/feature/sequence-flow-feature.js +++ b/test/feature/sequence-flow-feature.js @@ -1,7 +1,5 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition, SequenceFlow } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; -import SequenceFlow from '../../src/flows/SequenceFlow.js'; - const camunda = testHelpers.camundaBpmnModdle; const extensions = { diff --git a/test/feature/service-task-feature.js b/test/feature/service-task-feature.js index 57e2332d..8b0a5314 100644 --- a/test/feature/service-task-feature.js +++ b/test/feature/service-task-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; Feature('Service task', () => { diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index f02c0f43..eb4a93ed 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; Feature('Shaking', () => { diff --git a/test/feature/signal-feature.js b/test/feature/signal-feature.js index da7f3520..dfb3de38 100644 --- a/test/feature/signal-feature.js +++ b/test/feature/signal-feature.js @@ -1,5 +1,5 @@ import camunda from '../resources/extensions/CamundaExtension.js'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import JsExtension from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/stop-and-resume-feature.js b/test/feature/stop-and-resume-feature.js index 0316dc14..32a6ffb9 100644 --- a/test/feature/stop-and-resume-feature.js +++ b/test/feature/stop-and-resume-feature.js @@ -1,5 +1,5 @@ import * as ck from 'chronokinesis'; -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import JsExtension from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/sub-process-feature.js b/test/feature/sub-process-feature.js index e28b79cc..14b3ba66 100644 --- a/test/feature/sub-process-feature.js +++ b/test/feature/sub-process-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import js from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; diff --git a/test/feature/task-loop-feature.js b/test/feature/task-loop-feature.js index 78035ef5..9e00f14c 100644 --- a/test/feature/task-loop-feature.js +++ b/test/feature/task-loop-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import js from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/feature/timers-feature.js b/test/feature/timers-feature.js index 40a2047f..e595def6 100644 --- a/test/feature/timers-feature.js +++ b/test/feature/timers-feature.js @@ -1,12 +1,9 @@ import * as ck from 'chronokinesis'; -import Definition from '../../src/definition/Definition.js'; +import { Definition, RunError, TimerEventDefinition } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; import CamundaExtension from '../resources/extensions/CamundaExtension.js'; import { resolveExpression } from '@aircall/expression-parser'; -import { RunError } from '../../src/error/Errors.js'; -import TimerEventDefinition from '../../src/eventDefinitions/TimerEventDefinition.js'; - const extensions = { camunda: CamundaExtension, }; diff --git a/test/feature/transaction-feature.js b/test/feature/transaction-feature.js index 87e784c7..759cfbbd 100644 --- a/test/feature/transaction-feature.js +++ b/test/feature/transaction-feature.js @@ -1,4 +1,4 @@ -import Definition from '../../src/definition/Definition.js'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/flows/Association-test.js b/test/flows/Association-test.js index 7d9e728c..ea16fdb8 100644 --- a/test/flows/Association-test.js +++ b/test/flows/Association-test.js @@ -1,5 +1,5 @@ -import Environment from '../../src/Environment.js'; -import Association from '../../src/flows/Association.js'; +import { Environment } from '../../src/Environment.js'; +import { Association } from '../../src/flows/Association.js'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('Association', () => { diff --git a/test/flows/MessageFlow-test.js b/test/flows/MessageFlow-test.js index 34143621..93e29d67 100644 --- a/test/flows/MessageFlow-test.js +++ b/test/flows/MessageFlow-test.js @@ -1,6 +1,6 @@ -import Environment from '../../src/Environment.js'; +import { Environment } from '../../src/Environment.js'; import factory from '../helpers/factory.js'; -import MessageFlow from '../../src/flows/MessageFlow.js'; +import { MessageFlow } from '../../src/flows/MessageFlow.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; diff --git a/test/flows/SequenceFlow-test.js b/test/flows/SequenceFlow-test.js index fd813166..da37980b 100644 --- a/test/flows/SequenceFlow-test.js +++ b/test/flows/SequenceFlow-test.js @@ -1,8 +1,8 @@ -import Environment from '../../src/Environment.js'; +import { Environment } from '../../src/Environment.js'; import factory from '../helpers/factory.js'; import js from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; -import SequenceFlow from '../../src/flows/SequenceFlow.js'; +import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; import { resolveExpression } from '@aircall/expression-parser'; import { Scripts } from '../helpers/JavaScripts.js'; diff --git a/test/getPropertyValue-test.js b/test/getPropertyValue-test.js index c570f414..8aa97a1b 100644 --- a/test/getPropertyValue-test.js +++ b/test/getPropertyValue-test.js @@ -1,5 +1,4 @@ -import getPropertyValue from '../src/getPropertyValue.js'; - +import { getPropertyValue } from '../src/getPropertyValue.js'; describe('getPropertyValue', () => { describe('property path', () => { it('returns object value', () => { diff --git a/test/helpers/testHelpers.js b/test/helpers/testHelpers.js index 77f8d9d4..779f7423 100644 --- a/test/helpers/testHelpers.js +++ b/test/helpers/testHelpers.js @@ -2,8 +2,8 @@ import fs from 'fs'; import Debug from 'debug'; import * as types from 'bpmn-elements'; import BpmnModdle from 'bpmn-moddle'; -import Context from '../../src/Context.js'; -import Environment from '../../src/Environment.js'; +import { Context } from '../../src/Context.js'; +import { Environment } from '../../src/Environment.js'; import { Serializer, TypeResolver } from 'moddle-context-serializer'; import { Scripts } from './JavaScripts.js'; diff --git a/test/io/DataObject-test.js b/test/io/DataObject-test.js index 7330bcd9..76a16568 100644 --- a/test/io/DataObject-test.js +++ b/test/io/DataObject-test.js @@ -1,5 +1,5 @@ -import DataObject from '../../src/io/EnvironmentDataObject.js'; -import Environment from '../../src/Environment.js'; +import { EnvironmentDataObject as DataObject } from '../../src/io/EnvironmentDataObject.js'; +import { Environment } from '../../src/Environment.js'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('DataObject', () => { diff --git a/test/io/InputOutputSpecification-test.js b/test/io/InputOutputSpecification-test.js index a084b664..b8d46ae1 100644 --- a/test/io/InputOutputSpecification-test.js +++ b/test/io/InputOutputSpecification-test.js @@ -1,4 +1,4 @@ -import InputOutputSpecification from '../../src/io/InputOutputSpecification.js'; +import { IoSpecification as InputOutputSpecification } from '../../src/io/InputOutputSpecification.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; diff --git a/test/io/Properties-test.js b/test/io/Properties-test.js index fd9a5c46..67a389d4 100644 --- a/test/io/Properties-test.js +++ b/test/io/Properties-test.js @@ -1,5 +1,5 @@ -import Environment from '../../src/Environment.js'; -import Properties from '../../src/io/Properties.js'; +import { Environment } from '../../src/Environment.js'; +import { Properties } from '../../src/io/Properties.js'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('Properties', () => { diff --git a/test/process/Process-test.js b/test/process/Process-test.js index 5721862f..df1b6195 100644 --- a/test/process/Process-test.js +++ b/test/process/Process-test.js @@ -1,6 +1,6 @@ import factory from '../helpers/factory.js'; import JsExtension from '../resources/extensions/JsExtension.js'; -import SignalTask from '../../src/tasks/SignalTask.js'; +import { SignalTask } from '../../src/tasks/SignalTask.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityError } from '../../src/error/Errors.js'; import { Process } from '../../src/process/Process.js'; diff --git a/test/process/ProcessExecution-test.js b/test/process/ProcessExecution-test.js index 6f56e2d5..1025e46d 100644 --- a/test/process/ProcessExecution-test.js +++ b/test/process/ProcessExecution-test.js @@ -1,16 +1,16 @@ -import BoundaryEvent from '../../src/events/BoundaryEvent.js'; -import EndEvent from '../../src/events/EndEvent.js'; -import ErrorEventDefinition from '../../src/eventDefinitions/ErrorEventDefinition.js'; -import MessageEventDefinition from '../../src/eventDefinitions/MessageEventDefinition.js'; -import TimerEventDefinition from '../../src/eventDefinitions/TimerEventDefinition.js'; -import ProcessExecution from '../../src/process/ProcessExecution.js'; -import Process from '../../src/process/Process.js'; -import ServiceTask from '../../src/tasks/ServiceTask.js'; -import SequenceFlow from '../../src/flows/SequenceFlow.js'; -import SignalTask from '../../src/tasks/SignalTask.js'; -import StartEvent from '../../src/events/StartEvent.js'; -import SubProcess from '../../src/tasks/SubProcess.js'; -import TerminateEventDefinition from '../../src/eventDefinitions/TerminateEventDefinition.js'; +import { BoundaryEvent } from '../../src/events/BoundaryEvent.js'; +import { EndEvent } from '../../src/events/EndEvent.js'; +import { ErrorEventDefinition } from '../../src/eventDefinitions/ErrorEventDefinition.js'; +import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; +import { TimerEventDefinition } from '../../src/eventDefinitions/TimerEventDefinition.js'; +import { ProcessExecution } from '../../src/process/ProcessExecution.js'; +import { Process } from '../../src/process/Process.js'; +import { ServiceTask } from '../../src/tasks/ServiceTask.js'; +import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; +import { SignalTask } from '../../src/tasks/SignalTask.js'; +import { StartEvent } from '../../src/events/StartEvent.js'; +import { SubProcess } from '../../src/tasks/SubProcess.js'; +import { TerminateEventDefinition } from '../../src/eventDefinitions/TerminateEventDefinition.js'; import testHelpers from '../helpers/testHelpers.js'; describe('Process execution', () => { diff --git a/test/tasks/LoopCharacteristics-test.js b/test/tasks/LoopCharacteristics-test.js index df8f2b62..49634131 100644 --- a/test/tasks/LoopCharacteristics-test.js +++ b/test/tasks/LoopCharacteristics-test.js @@ -1,5 +1,5 @@ -import Environment from '../../src/Environment.js'; -import LoopCharacteristics from '../../src/tasks/LoopCharacteristics.js'; +import { Environment } from '../../src/Environment.js'; +import { LoopCharacteristics } from '../../src/tasks/LoopCharacteristics.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; import { ActivityError } from '../../src/error/Errors.js'; diff --git a/test/tasks/ReceiveTask-test.js b/test/tasks/ReceiveTask-test.js index fab9c635..038fcc79 100644 --- a/test/tasks/ReceiveTask-test.js +++ b/test/tasks/ReceiveTask-test.js @@ -1,5 +1,5 @@ -import Message from '../../src/activity/Message.js'; -import ReceiveTask from '../../src/tasks/ReceiveTask.js'; +import { Message } from '../../src/activity/Message.js'; +import { ReceiveTask } from '../../src/tasks/ReceiveTask.js'; import testHelpers from '../helpers/testHelpers.js'; describe('ReceiveTask', () => { diff --git a/test/tasks/ServiceTask-test.js b/test/tasks/ServiceTask-test.js index 02b83b7f..5a99b998 100644 --- a/test/tasks/ServiceTask-test.js +++ b/test/tasks/ServiceTask-test.js @@ -1,6 +1,6 @@ import JsExtension from '../resources/extensions/JsExtension.js'; import nock from 'nock'; -import ServiceTask from '../../src/tasks/ServiceTask.js'; +import { ServiceTask } from '../../src/tasks/ServiceTask.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityError } from '../../src/error/Errors.js'; diff --git a/test/tasks/SubProcess-test.js b/test/tasks/SubProcess-test.js index e9ff3a17..e418f0bb 100644 --- a/test/tasks/SubProcess-test.js +++ b/test/tasks/SubProcess-test.js @@ -1,7 +1,7 @@ import factory from '../helpers/factory.js'; import JsExtension from '../resources/extensions/JsExtension.js'; -import SignalTask from '../../src/tasks/SignalTask.js'; -import SubProcess from '../../src/tasks/SubProcess.js'; +import { SignalTask } from '../../src/tasks/SignalTask.js'; +import { SubProcess } from '../../src/tasks/SubProcess.js'; import testHelpers from '../helpers/testHelpers.js'; import { BpmnError } from '../../src/error/Errors.js'; diff --git a/test/tasks/Transaction-test.js b/test/tasks/Transaction-test.js index a2611da5..74961554 100644 --- a/test/tasks/Transaction-test.js +++ b/test/tasks/Transaction-test.js @@ -1,4 +1,4 @@ -import Transaction from '../../src/tasks/Transaction.js'; +import { Transaction } from '../../src/tasks/Transaction.js'; import testHelpers from '../helpers/testHelpers.js'; describe('Transaction', () => { diff --git a/test/tasks/isForCompensation-test.js b/test/tasks/isForCompensation-test.js index a81e4cb5..a759cf7e 100644 --- a/test/tasks/isForCompensation-test.js +++ b/test/tasks/isForCompensation-test.js @@ -1,5 +1,5 @@ -import Association from '../../src/flows/Association.js'; -import ServiceTask from '../../src/tasks/ServiceTask.js'; +import { Association } from '../../src/flows/Association.js'; +import { ServiceTask } from '../../src/tasks/ServiceTask.js'; import testHelpers from '../helpers/testHelpers.js'; describe('isForCompensation task', () => { diff --git a/types/index.d.ts b/types/index.d.ts index fe21f1c9..15335581 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,14 +1,13 @@ declare module 'bpmn-elements' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + import type { SerializableElement } from 'moddle-context-serializer'; /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param Behaviour Element-specific behaviour constructor invoked per execution * @param activityDef Parsed BPMN element definition * @param context Per-execution registry and factory */ - export function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - export class Activity { + export class Activity { /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param Behaviour Element-specific behaviour constructor invoked per execution @@ -24,10 +23,14 @@ declare module 'bpmn-elements' { }; Behaviour: IActivityBehaviour; parent: any; - logger: ILogger; - environment: Environment_1; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + environment: Environment; context: ContextInstance; - broker: import("smqp").default | undefined; + broker: import("smqp").Broker; on: any; once: any; waitFor: any; @@ -157,7 +160,7 @@ declare module 'bpmn-elements' { _createMessage(override: any): any; - _getOutboundSequenceFlowById(flowId: any): SequenceFlow_1 | undefined; + _getOutboundSequenceFlowById(flowId: any): any; _deactivateRunConsumers(): void; @@ -210,27 +213,26 @@ declare module 'bpmn-elements' { * Build a runtime Context from a parsed BPMN definition. * @param environment Existing environment to clone; a fresh one is created when omitted */ - export function Context(definitionContext: import("moddle-context-serializer").SerializableContext, environment?: Environment_1): ContextInstance_1; + export function Context(definitionContext: import("moddle-context-serializer").SerializableContext, environment?: Environment): ContextInstance; /** * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. * @param owner Process or sub-process activity that owns this context */ - function ContextInstance_1(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment_1, owner?: Process_1 | Activity): void; - class ContextInstance_1 { + class ContextInstance { /** * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. * @param owner Process or sub-process activity that owns this context */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment_1, owner?: Process_1 | Activity); + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); id: string; name: string; type: string; sid: string; definitionContext: import("moddle-context-serializer").SerializableContext; - environment: Environment_1; + environment: Environment; extensionsMapper: ExtensionsMapper; refs: Map>; - get owner(): Activity | Process_1 | undefined; + get owner(): Activity | Process | undefined; /** * Get or create the activity instance for the given id. * */ @@ -275,7 +277,7 @@ declare module 'bpmn-elements' { * Create a new context that shares the parsed definition but optionally swaps environment and owner. * */ - clone(newEnvironment?: Environment_1, newOwner?: Process_1 | Activity): ContextInstance_1; + clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; /** * Get or create the process instance for the given id. Each process gets its own cloned environment. * */ @@ -322,16 +324,14 @@ declare module 'bpmn-elements' { private [K_OWNER]; } - function ExtensionsMapper(context: any): void; - class ExtensionsMapper { + class ExtensionsMapper { constructor(context: any); context: any; get(activity: any): Extensions; _getExtensions(): any[]; } - function Extensions(activity: any, context: any, extensions: any): void; - class Extensions { + class Extensions { constructor(activity: any, context: any, extensions: any); extensions: any[]; get count(): number; @@ -341,10 +341,7 @@ declare module 'bpmn-elements' { private [K_ACTIVATED]; } const K_OWNER: unique symbol; - export function DataObject(dataObjectDef: any, { environment }: { - environment: any; - }): void; - export class DataObject { + export class DataObject { constructor(dataObjectDef: any, { environment }: { environment: any; }); @@ -363,10 +360,7 @@ declare module 'bpmn-elements' { value: any; }; } - export function DataStore(dataStoreDef: any, { environment }: { - environment: any; - }): void; - export class DataStore { + export class DataStore { constructor(dataStoreDef: any, { environment }: { environment: any; }); @@ -385,10 +379,7 @@ declare module 'bpmn-elements' { value: any; }; } - export function DataStoreReference(dataObjectDef: any, { environment }: { - environment: any; - }): void; - export class DataStoreReference { + export class DataStoreReference { constructor(dataObjectDef: any, { environment }: { environment: any; }); @@ -412,8 +403,7 @@ declare module 'bpmn-elements' { * mediates inter-process messaging. * @param options When provided, environment is cloned and settings merged */ - export function Definition(context: ContextInstance, options?: EnvironmentOptions): Definition; - export class Definition { + export class Definition { /** * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and * mediates inter-process messaging. @@ -423,15 +413,16 @@ declare module 'bpmn-elements' { id: string | undefined; type: string | undefined; name: string | undefined; - environment: Environment_1 | undefined; + environment: any; context: ContextInstance | undefined; - broker: import("smqp").default | undefined; + + broker: import("smqp").Broker; on: any; once: any; waitFor: any; emit: any; emitFatal: any; - logger: ILogger | undefined; + logger: any; /** * Start running the definition. Accepts run options, a callback, or both. * The callback fires once on leave, stop, or error. @@ -568,8 +559,7 @@ declare module 'bpmn-elements' { * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. * */ - export function Environment(options?: EnvironmentOptions): void; - export class Environment { + export class Environment { /** * Holds global execution config: variables, injected services, timers, scripts engine, * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. @@ -674,8 +664,7 @@ declare module 'bpmn-elements' { parent: any; }; }; - export function InputOutputSpecification(activity: any, ioSpecificationDef: any, context: any): void; - export class InputOutputSpecification { + export class InputOutputSpecification { constructor(activity: any, ioSpecificationDef: any, context: any); id: any; type: any; @@ -703,34 +692,36 @@ declare module 'bpmn-elements' { * Process lane. Wraps a `` definition and points back to its owning process; * activities reference their lane through `Activity.lane`. * */ - export function Lane(process: Process_1, laneDefinition: import("moddle-context-serializer").SerializableElement): void; - export class Lane { + export class Lane { /** * Process lane. Wraps a `` definition and points back to its owning process; * activities reference their lane through `Activity.lane`. * */ - constructor(process: Process_1, laneDefinition: import("moddle-context-serializer").SerializableElement); + constructor(process: Process, laneDefinition: import("moddle-context-serializer").SerializableElement); id: string | undefined; type: string | undefined; name: any; parent: { - id: string; + id: string | undefined; type: string; }; behaviour: { [x: string]: any; }; - environment: Environment_1; - broker: ElementBroker; + environment: Environment; + broker: import("smqp").Broker; context: ContextInstance; - logger: ILogger; - get process(): Process_1; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + get process(): Process; private [K_PROCESS]; } const K_PROCESS: unique symbol; - export function MultiInstanceLoopCharacteristics(activity: any, loopCharacteristics: any): void; - export class MultiInstanceLoopCharacteristics { + export class MultiInstanceLoopCharacteristics { constructor(activity: any, loopCharacteristics: any); activity: any; loopCharacteristics: any; @@ -748,8 +739,7 @@ declare module 'bpmn-elements' { * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. * */ - export function Process(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - export class Process { + export class Process { /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. @@ -761,13 +751,17 @@ declare module 'bpmn-elements' { parent: any; behaviour: Record; isExecutable: any; - environment: Environment_1; + environment: Environment; context: ContextInstance; - broker: import("smqp").default | undefined; + broker: import("smqp").Broker; on: any; once: any; waitFor: any; - logger: ILogger; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; /** * Allocate an executionId and emit init event without starting the run. * @param useAsExecutionId Override for the generated execution id @@ -791,7 +785,20 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; executionId: any; - environment: EnvironmentState; + environment: { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; status: any; stopped: any; counters: any; @@ -882,7 +889,7 @@ declare module 'bpmn-elements' { * Get start activities, optionally filtered by referenced event definition. * */ - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; + getStartActivities(filterOptions?: startActivityFilterOptions): any[]; /** * Get sequence flows in the process scope. */ @@ -924,8 +931,7 @@ declare module 'bpmn-elements' { private [K_EXECUTE_MESSAGE]; } const K_LANES: unique symbol; - export function Properties(activity: any, propertiesDef: any, context: any): void; - export class Properties { + export class Properties { constructor(activity: any, propertiesDef: any, context: any); activity: any; broker: any; @@ -944,8 +950,7 @@ declare module 'bpmn-elements' { private [K_CONSUMING]; } const K_PROPERTIES: unique symbol; - export function ServiceImplementation(activity: any): void; - export class ServiceImplementation { + export class ServiceImplementation { constructor(activity: any); type: string; implementation: any; @@ -960,8 +965,7 @@ declare module 'bpmn-elements' { resolve: (executionMessage: any) => any; }; export function StandardLoopCharacteristics(activity: any, loopCharacteristics: any): MultiInstanceLoopCharacteristics; - export function Timers(options: any): void; - export class Timers { + export class Timers { constructor(options: any); count: number; options: any; @@ -974,8 +978,7 @@ declare module 'bpmn-elements' { private [K_EXECUTING]; } - function RegisteredTimers(timersApi: any, owner: any): void; - class RegisteredTimers { + class RegisteredTimers { constructor(timersApi: any, owner: any); owner: any; setTimeout: any; @@ -983,8 +986,7 @@ declare module 'bpmn-elements' { private [K_TIMER_API]; } - function Timer_1(owner: any, timerId: any, callback: any, delay: any, args: any): void; - class Timer_1 { + class Timer_1 { constructor(owner: any, timerId: any, callback: any, delay: any, args: any); callback: any; delay: any; @@ -1024,8 +1026,7 @@ declare module 'bpmn-elements' { * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. * */ - export function Association(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; - export class Association { + export class Association { /** * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. @@ -1039,9 +1040,13 @@ declare module 'bpmn-elements' { sourceId: any; targetId: any; isAssociation: boolean; - environment: Environment_1; - logger: ILogger; - broker: import("smqp").default | undefined; + environment: Environment; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + broker: import("smqp").Broker; on: any; once: any; waitFor: any; @@ -1072,7 +1077,7 @@ declare module 'bpmn-elements' { * Resolve an association-scoped Api wrapper. * */ - getApi(message?: ElementBrokerMessage): Api_1; + getApi(message?: ElementBrokerMessage): Api; /** * Stop the association's broker. */ @@ -1089,8 +1094,7 @@ declare module 'bpmn-elements' { * source's `end` event and publishes `message.outbound` whenever the source completes, * carrying any message payload through to the target. * */ - export function MessageFlow(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - export class MessageFlow { + export class MessageFlow { /** * Message flow connecting a source activity (or process) to a target. Subscribes to the * source's `end` event and publishes `message.outbound` whenever the source completes, @@ -1104,14 +1108,18 @@ declare module 'bpmn-elements' { source: any; target: any; behaviour: Record; - environment: Environment_1; + environment: Environment; context: ContextInstance; - broker: import("smqp").default | undefined; + broker: import("smqp").Broker; on: any; once: any; emit: any; waitFor: any; - logger: ILogger; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; get counters(): { messages: number; }; @@ -1128,7 +1136,7 @@ declare module 'bpmn-elements' { * Resolve a message-scoped Api wrapper. * */ - getApi(message?: ElementBrokerMessage): Api_1; + getApi(message?: ElementBrokerMessage): Api; /** * Subscribe to the source element's message and end events to bridge the message across. */ @@ -1161,8 +1169,7 @@ declare module 'bpmn-elements' { * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. * */ - export function SequenceFlow(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; - export class SequenceFlow { + export class SequenceFlow { /** * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. @@ -1177,9 +1184,13 @@ declare module 'bpmn-elements' { targetId: any; isDefault: any; isSequenceFlow: boolean; - environment: Environment_1; - logger: ILogger; - broker: import("smqp").default | undefined; + environment: Environment; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + broker: import("smqp").Broker; on: any; once: any; waitFor: any; @@ -1213,7 +1224,7 @@ declare module 'bpmn-elements' { * Resolve a Flow Api wrapper. * */ - getApi(message?: ElementBrokerMessage): Api_1; + getApi(message?: ElementBrokerMessage): Api; /** * Stop the flow's broker. */ @@ -1253,205 +1264,6 @@ declare module 'bpmn-elements' { private [K_COUNTERS]; } - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment_1; - get context(): ContextInstance; - get logger(): ILogger; - } - - class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): Api; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; - } - - interface Api extends ElementBrokerMessage { - get id(): string; - get type(): string; - get name(): string; - get executionId(): string; - get environment(): Environment_1; - get broker(): ElementBroker; - get owner(): T; - cancel(message?: signalMessage, options?: any): void; - discard(): void; - fail(error: Error): void; - signal(message?: signalMessage, options?: any): void; - stop(): void; - resolveExpression(expression: string): any; - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - getPostponed(...args: any[]): any[]; - createMessage(content?: Record): any; - getExecuting(): Api[]; - } - - class Environment_1 { - constructor(options?: EnvironmentOptions); - options: Record; - expressions: IExpressions; - extensions: Record; - scripts: IScripts; - timers: ITimers; - Logger: LoggerFactory; - get settings(): EnvironmentSettings; - get variables(): Record; - get output(): Record; - set services(arg: any); - get services(): any; - getState(): EnvironmentState; - recover(state?: EnvironmentState): Environment_1; - clone(overrideOptions?: EnvironmentOptions): Environment_1; - assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): Environment_1; - registerScript(activity: any): Script; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - getServiceByName(serviceName: string): CallableFunction; - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - addService(name: string, fn: CallableFunction): void; - } - class ContextInstance { - constructor(definitionContext: SerializableContext, environment?: Environment_1); - get id(): string; - get name(): string; - get type(): string; - /** Unique context instance id */ - get sid(): string; - get definitionContext(): SerializableContext; - get environment(): Environment_1; - /** Context owner, Process or SubProcess activity */ - get owner(): Process_1 | Activity | undefined; - getActivityById(activityId: string): T; - getSequenceFlowById(sequenceFlowId: string): SequenceFlow_1; - getInboundSequenceFlows(activityId: string): SequenceFlow_1[]; - getOutboundSequenceFlows(activityId: string): SequenceFlow_1[]; - getInboundAssociations(activityId: string): Association_1[]; - getOutboundAssociations(activityId: string): Association_1[]; - getActivities(scopeId?: string): ElementBase[]; - getSequenceFlows(scopeId?: string): SequenceFlow_1[]; - getAssociations(scopeId?: string): Association_1[]; - clone(newEnvironment?: Environment_1): ContextInstance; - getProcessById(processId: string): Process_1; - getNewProcessById(processId: string): Process_1; - getProcesses(): Process_1[]; - getExecutableProcesses(): Process_1[]; - getMessageFlows(sourceId: string): MessageFlow_1[]; - getDataObjectById(referenceId: string): any; - getDataStoreById(referenceId: string): any; - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; - loadExtensions(activity: ElementBase): IExtension; - } - - class Process_1 extends Element { - constructor(processDef: SerializableElement, context: ContextInstance); - get isExecutable(): boolean; - get counters(): completedCounters; - get lanes(): Lane_1[] | undefined; - get extensions(): IExtension; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string; - get execution(): ProcessExecution; - get status(): ProcessRunStatus | undefined; - get activityStatus(): ActivityStatus; - init(useAsExecutionId?: string): void; - run(runContent?: Record): void; - getState(): ProcessState; - recover(state?: ProcessState): Process_1; - shake(startId?: string): void; - signal(message: any): any; - cancelActivity(message: any): any; - sendMessage(message: any): void; - getActivityById(childId: string): T; - getActivities(): Activity[]; - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; - getSequenceFlows(): SequenceFlow_1[]; - getLaneById(laneId: string): Lane_1 | undefined; - getPostponed(filterFn: filterPostponed): Api[]; - } - - interface ProcessExecution { - get isSubProcess(): boolean; - get broker(): Broker; - get environment(): Environment_1; - get context(): ContextInstance; - get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; - execute(executeMessage: ElementBrokerMessage): void; - getPostponed(filterFn: filterPostponed): Api[]; - getActivities(): Activity[]; - getActivityById(activityId: string): T; - getSequenceFlows(): SequenceFlow_1[]; - getApi(message?: ElementBrokerMessage): Api; - } - - class Lane_1 extends ElementBase { - constructor(process: Process_1, laneDefinition: SerializableElement); - /** Process broker */ - get broker(): Broker; - get process(): Process_1; - } - - class SequenceFlow_1 extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isDefault(): boolean; - get isSequenceFlow(): boolean; - get counters(): { take: number; discard: number; looped: number }; - take(content?: any): boolean; - discard(content?: any): void; - shake(message: any): number; - getCondition(): ISequenceFlowCondition | null; - createMessage(override?: any): object; - /** - * Evaluate flow - * Executes condition if any, default flow is - * @param fromMessage Activity message - * @param callback Callback with evaluation result, if truthy flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - getState(): SequenceFlowState | undefined; - } - - class MessageFlow_1 extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get source(): MessageFlowReference; - get target(): MessageFlowReference; - get counters(): { messages: number }; - activate(): void; - deactivate(): void; - getState(): MessageFlowState | undefined; - } - - class Association_1 extends Element { - constructor(associationDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isAssociation(): boolean; - get counters(): { take: number; discard: number }; - take(content?: any): boolean; - discard(content?: any): boolean; - getState(): AssociationState | undefined; - } - interface ElementBroker extends Broker { - get owner(): T; - } - type signalMessage = { /** * Optional signal id @@ -1487,6 +1299,20 @@ declare module 'bpmn-elements' { get path(): ElementParent[]; } + // --- Element abstract bases --------------------------------------------------- + + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + interface ISequenceFlowCondition { /** Condition type, e.g. script or expression */ get type(): string; @@ -1498,6 +1324,8 @@ declare module 'bpmn-elements' { execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; } + // --- Activity behaviour & extensions ------------------------------------------ + interface IActivityBehaviour { id: string; type: string; @@ -1517,6 +1345,8 @@ declare module 'bpmn-elements' { resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; } + // --- Environment -------------------------------------------------------------- + interface EnvironmentSettings { /** true returns dummy service function for service task if not found */ enableDummyService?: boolean; @@ -1554,6 +1384,8 @@ declare module 'bpmn-elements' { expressions?: IExpressions; } + // --- Filter / callback shapes ------------------------------------------------- + type startActivityFilterOptions = { /** Event definition id, i.e. Message, Signal, Error, etc */ referenceId?: string; @@ -1561,40 +1393,9 @@ declare module 'bpmn-elements' { referenceType?: string; }; - type filterPostponed = (elementApi: any) => boolean; - - enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', - } + type runCallback = (err: Error, definitionApi: any) => void; - /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ - enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', - /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc - */ - Wait = 'wait', - } + // --- State snapshots ---------------------------------------------------------- interface ElementState { id: string; @@ -1673,13 +1474,7 @@ declare module 'bpmn-elements' { execution?: DefinitionExecutionState; } - type runCallback = (err: Error, definitionApi: any) => void; - - interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; - } + // --- Logging ------------------------------------------------------------------ type LoggerFactory = (scope: string) => ILogger; @@ -1690,6 +1485,8 @@ declare module 'bpmn-elements' { [x: string]: any; } + // --- Timers ------------------------------------------------------------------- + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; type wrappedClearTimeout = (ref: any) => void; @@ -1722,6 +1519,8 @@ declare module 'bpmn-elements' { [x: string]: any; } + // --- Scripts ------------------------------------------------------------------ + interface IScripts { register(activity: any): Script | undefined; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; @@ -1730,6 +1529,13 @@ declare module 'bpmn-elements' { interface Script { execute(executionContext: any, callback: CallableFunction): void; } + + /** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ const K_ACTIVATED: unique symbol; const K_COMPLETED: unique symbol; const K_CONSUMING: unique symbol; @@ -1749,8 +1555,7 @@ declare module 'bpmn-elements' { export function IntermediateCatchEvent(activityDef: any, context: any): Activity; export function IntermediateThrowEvent(activityDef: any, context: any): Activity; export function StartEvent(activityDef: any, context: any): Activity; - export function CancelEventDefinition(activity: any, eventDefinition: any): void; - export class CancelEventDefinition { + export class CancelEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; @@ -1776,8 +1581,7 @@ declare module 'bpmn-elements' { private [K_COMPLETED]; } - export function CompensateEventDefinition(activity: any, eventDefinition: any, context: any): void; - export class CompensateEventDefinition { + export class CompensateEventDefinition { constructor(activity: any, eventDefinition: any, context: any); id: any; type: any; @@ -1814,8 +1618,7 @@ declare module 'bpmn-elements' { } const K_ASSOCIATIONS: unique symbol; const K_COMPENSATE_Q: unique symbol; - export function ConditionalEventDefinition(activity: any, eventDefinition: any, _context: any, index: any): void; - export class ConditionalEventDefinition { + export class ConditionalEventDefinition { constructor(activity: any, eventDefinition: any, _context: any, index: any); id: any; type: any; @@ -1850,8 +1653,7 @@ declare module 'bpmn-elements' { private [K_EXECUTE_MESSAGE]; } - export function ErrorEventDefinition(activity: any, eventDefinition: any): void; - export class ErrorEventDefinition { + export class ErrorEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; @@ -1891,8 +1693,7 @@ declare module 'bpmn-elements' { description: string; } | undefined; } - export function EscalationEventDefinition(activity: any, eventDefinition: any): void; - export class EscalationEventDefinition { + export class EscalationEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; @@ -1930,8 +1731,7 @@ declare module 'bpmn-elements' { } | undefined; } const K_REFERENCE: unique symbol; - export function LinkEventDefinition(activity: any, eventDefinition: any): void; - export class LinkEventDefinition { + export class LinkEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; @@ -1953,8 +1753,7 @@ declare module 'bpmn-elements' { private [K_EXECUTE_MESSAGE]; } - export function MessageEventDefinition(activity: any, eventDefinition: any): void; - export class MessageEventDefinition { + export class MessageEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; @@ -1992,8 +1791,7 @@ declare module 'bpmn-elements' { description: string; } | undefined; } - export function SignalEventDefinition(activity: any, eventDefinition: any): void; - export class SignalEventDefinition { + export class SignalEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; @@ -2031,8 +1829,7 @@ declare module 'bpmn-elements' { description: string; } | undefined; } - export function TerminateEventDefinition(activity: any, eventDefinition: any): void; - export class TerminateEventDefinition { + export class TerminateEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; @@ -2041,8 +1838,7 @@ declare module 'bpmn-elements' { logger: any; execute(executeMessage: any): void; } - export function TimerEventDefinition(activity: any, eventDefinition: any): void; - export class TimerEventDefinition { + export class TimerEventDefinition { constructor(activity: any, eventDefinition: any); type: any; activity: any; @@ -2077,16 +1873,14 @@ declare module 'bpmn-elements' { } const K_TIMER: unique symbol; const K_TIMER_CONTENT: unique symbol; - function Scripts(): void; - class Scripts { + class Scripts { getScript(): void; register(): void; } export function EventBasedGateway(activityDef: any, context: any): Activity; export function ExclusiveGateway(activityDef: any, context: any): Activity; export function InclusiveGateway(activityDef: any, context: any): Activity; - export function ParallelGateway(activityDef: any, context: any): Activity; - export class ParallelGateway { + export class ParallelGateway { constructor(activityDef: any, context: any); id: string | undefined; } @@ -2097,8 +1891,7 @@ declare module 'bpmn-elements' { * @param environment Defaults to `broker.owner.environment` * @throws {Error} when sourceMessage is missing */ - function Api_1(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment_1): void; - class Api_1 { + class Api { /** * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` @@ -2106,7 +1899,7 @@ declare module 'bpmn-elements' { * @param environment Defaults to `broker.owner.environment` * @throws {Error} when sourceMessage is missing */ - constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment_1); + constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment); id: any; type: any; name: any; @@ -2165,8 +1958,7 @@ declare module 'bpmn-elements' { /** * Script condition * */ - function ScriptCondition(owner: ElementBase, script: any, language: string): void; - class ScriptCondition { + class ScriptCondition { /** * Script condition * */ @@ -2183,8 +1975,7 @@ declare module 'bpmn-elements' { /** * Expression condition * */ - function ExpressionCondition(owner: ElementBase, expression: string): void; - class ExpressionCondition { + class ExpressionCondition { /** * Expression condition * */ @@ -2201,12 +1992,47 @@ declare module 'bpmn-elements' { export {}; } +declare module 'bpmn-elements/errors' { + export function makeErrorFromMessage(errorMessage: any): any; + export class ActivityError extends Error { + constructor(description: any, sourceMessage: any, inner: any); + type: string; + name: any; + description: any; + source: { + fields: any; + content: any; + properties: any; + } | undefined; + inner: any; + code: any; + } + export class RunError extends ActivityError { + constructor(...args: any[]); + } + export class BpmnError extends Error { + constructor(description: any, behaviour: any, sourceMessage: any, inner: any); + type: string; + name: any; + description: any; + code: any; + id: any; + source: { + fields: any; + content: any; + properties: any; + } | undefined; + inner: any; + } + + export {}; +} + declare module 'bpmn-elements/events' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + import type { SerializableElement } from 'moddle-context-serializer'; export function BoundaryEvent(activityDef: any, context: any): Activity; - export function BoundaryEventBehaviour(activity: any): void; - export class BoundaryEventBehaviour { + export class BoundaryEventBehaviour { constructor(activity: any); id: any; type: any; @@ -2244,8 +2070,7 @@ declare module 'bpmn-elements/events' { const K_ATTACHED_TAGS: unique symbol; const K_COMPLETE_CONTENT: unique symbol; export function EndEvent(activityDef: any, context: any): Activity; - export function EndEventBehaviour(activity: any): void; - export class EndEventBehaviour { + export class EndEventBehaviour { constructor(activity: any); id: any; type: any; @@ -2255,8 +2080,7 @@ declare module 'bpmn-elements/events' { private [K_EXECUTION]; } export function IntermediateCatchEvent(activityDef: any, context: any): Activity; - export function IntermediateCatchEventBehaviour(activity: any): void; - export class IntermediateCatchEventBehaviour { + export class IntermediateCatchEventBehaviour { constructor(activity: any); id: any; type: any; @@ -2267,8 +2091,7 @@ declare module 'bpmn-elements/events' { private [K_EXECUTION]; } export function IntermediateThrowEvent(activityDef: any, context: any): Activity; - export function IntermediateThrowEventBehaviour(activity: any): void; - export class IntermediateThrowEventBehaviour { + export class IntermediateThrowEventBehaviour { constructor(activity: any); id: any; type: any; @@ -2278,8 +2101,7 @@ declare module 'bpmn-elements/events' { private [K_EXECUTION]; } export function StartEvent(activityDef: any, context: any): Activity; - export function StartEventBehaviour(activity: any): void; - export class StartEventBehaviour { + export class StartEventBehaviour { constructor(activity: any); id: any; type: any; @@ -2301,8 +2123,7 @@ declare module 'bpmn-elements/events' { * @param activityDef Parsed BPMN element definition * @param context Per-execution registry and factory */ - function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - class Activity { + class Activity { /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param Behaviour Element-specific behaviour constructor invoked per execution @@ -2318,10 +2139,14 @@ declare module 'bpmn-elements/events' { }; Behaviour: IActivityBehaviour; parent: any; - logger: ILogger; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; environment: Environment; context: ContextInstance; - broker: import("smqp").default | undefined; + broker: import("smqp").Broker; on: any; once: any; waitFor: any; @@ -2451,7 +2276,7 @@ declare module 'bpmn-elements/events' { _createMessage(override: any): any; - _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; + _getOutboundSequenceFlowById(flowId: any): any; _deactivateRunConsumers(): void; @@ -2495,205 +2320,8 @@ declare module 'bpmn-elements/events' { const K_EXTENSIONS: unique symbol; const K_MESSAGE_HANDLERS: unique symbol; const K_STATE_MESSAGE: unique symbol; - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): Api; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; - } - - interface Api extends ElementBrokerMessage { - get id(): string; - get type(): string; - get name(): string; - get executionId(): string; - get environment(): Environment; - get broker(): ElementBroker; - get owner(): T; - cancel(message?: signalMessage, options?: any): void; - discard(): void; - fail(error: Error): void; - signal(message?: signalMessage, options?: any): void; - stop(): void; - resolveExpression(expression: string): any; - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - getPostponed(...args: any[]): any[]; - createMessage(content?: Record): any; - getExecuting(): Api[]; - } - - class Environment { - constructor(options?: EnvironmentOptions); - options: Record; - expressions: IExpressions; - extensions: Record; - scripts: IScripts; - timers: ITimers; - Logger: LoggerFactory; - get settings(): EnvironmentSettings; - get variables(): Record; - get output(): Record; - set services(arg: any); - get services(): any; - getState(): EnvironmentState; - recover(state?: EnvironmentState): Environment; - clone(overrideOptions?: EnvironmentOptions): Environment; - assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): Environment; - registerScript(activity: any): Script; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - getServiceByName(serviceName: string): CallableFunction; - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - addService(name: string, fn: CallableFunction): void; - } - class ContextInstance { - constructor(definitionContext: SerializableContext, environment?: Environment); - get id(): string; - get name(): string; - get type(): string; - /** Unique context instance id */ - get sid(): string; - get definitionContext(): SerializableContext; - get environment(): Environment; - /** Context owner, Process or SubProcess activity */ - get owner(): Process | Activity | undefined; - getActivityById(activityId: string): T; - getSequenceFlowById(sequenceFlowId: string): SequenceFlow; - getInboundSequenceFlows(activityId: string): SequenceFlow[]; - getOutboundSequenceFlows(activityId: string): SequenceFlow[]; - getInboundAssociations(activityId: string): Association[]; - getOutboundAssociations(activityId: string): Association[]; - getActivities(scopeId?: string): ElementBase[]; - getSequenceFlows(scopeId?: string): SequenceFlow[]; - getAssociations(scopeId?: string): Association[]; - clone(newEnvironment?: Environment): ContextInstance; - getProcessById(processId: string): Process; - getNewProcessById(processId: string): Process; - getProcesses(): Process[]; - getExecutableProcesses(): Process[]; - getMessageFlows(sourceId: string): MessageFlow[]; - getDataObjectById(referenceId: string): any; - getDataStoreById(referenceId: string): any; - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; - loadExtensions(activity: ElementBase): IExtension; - } - - class Process extends Element { - constructor(processDef: SerializableElement, context: ContextInstance); - get isExecutable(): boolean; - get counters(): completedCounters; - get lanes(): Lane[] | undefined; - get extensions(): IExtension; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string; - get execution(): ProcessExecution; - get status(): ProcessRunStatus | undefined; - get activityStatus(): ActivityStatus; - init(useAsExecutionId?: string): void; - run(runContent?: Record): void; - getState(): ProcessState; - recover(state?: ProcessState): Process; - shake(startId?: string): void; - signal(message: any): any; - cancelActivity(message: any): any; - sendMessage(message: any): void; - getActivityById(childId: string): T; - getActivities(): Activity[]; - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; - getSequenceFlows(): SequenceFlow[]; - getLaneById(laneId: string): Lane | undefined; - getPostponed(filterFn: filterPostponed): Api[]; - } - - interface ProcessExecution { - get isSubProcess(): boolean; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; - execute(executeMessage: ElementBrokerMessage): void; - getPostponed(filterFn: filterPostponed): Api[]; - getActivities(): Activity[]; - getActivityById(activityId: string): T; - getSequenceFlows(): SequenceFlow[]; - getApi(message?: ElementBrokerMessage): Api; - } - - class Lane extends ElementBase { - constructor(process: Process, laneDefinition: SerializableElement); - /** Process broker */ - get broker(): Broker; - get process(): Process; - } - - class SequenceFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isDefault(): boolean; - get isSequenceFlow(): boolean; - get counters(): { take: number; discard: number; looped: number }; - take(content?: any): boolean; - discard(content?: any): void; - shake(message: any): number; - getCondition(): ISequenceFlowCondition | null; - createMessage(override?: any): object; - /** - * Evaluate flow - * Executes condition if any, default flow is - * @param fromMessage Activity message - * @param callback Callback with evaluation result, if truthy flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - getState(): SequenceFlowState | undefined; - } - - class MessageFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get source(): MessageFlowReference; - get target(): MessageFlowReference; - get counters(): { messages: number }; - activate(): void; - deactivate(): void; - getState(): MessageFlowState | undefined; - } - - class Association extends Element { - constructor(associationDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isAssociation(): boolean; - get counters(): { take: number; discard: number }; - take(content?: any): boolean; - discard(content?: any): boolean; - getState(): AssociationState | undefined; - } - interface ElementBroker extends Broker { - get owner(): T; - } - + const K_STATUS: unique symbol; + const K_STOPPED: unique symbol; type signalMessage = { /** * Optional signal id @@ -2729,17 +2357,22 @@ declare module 'bpmn-elements/events' { get path(): ElementParent[]; } - interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ + // --- Element abstract bases --------------------------------------------------- + + class ElementBase { + get id(): string; get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; } + // --- Activity behaviour & extensions ------------------------------------------ + interface IActivityBehaviour { id: string; type: string; @@ -2759,6 +2392,8 @@ declare module 'bpmn-elements/events' { resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; } + // --- Environment -------------------------------------------------------------- + interface EnvironmentSettings { /** true returns dummy service function for service task if not found */ enableDummyService?: boolean; @@ -2796,6 +2431,8 @@ declare module 'bpmn-elements/events' { expressions?: IExpressions; } + // --- Filter / callback shapes ------------------------------------------------- + type startActivityFilterOptions = { /** Event definition id, i.e. Message, Signal, Error, etc */ referenceId?: string; @@ -2803,40 +2440,7 @@ declare module 'bpmn-elements/events' { referenceType?: string; }; - type filterPostponed = (elementApi: any) => boolean; - - enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', - } - - /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ - enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', - /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc - */ - Wait = 'wait', - } + // --- State snapshots ---------------------------------------------------------- interface ElementState { id: string; @@ -2898,11 +2502,7 @@ declare module 'bpmn-elements/events' { execution?: ProcessExecutionState; } - interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; - } + // --- Logging ------------------------------------------------------------------ type LoggerFactory = (scope: string) => ILogger; @@ -2913,6 +2513,8 @@ declare module 'bpmn-elements/events' { [x: string]: any; } + // --- Timers ------------------------------------------------------------------- + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; type wrappedClearTimeout = (ref: any) => void; @@ -2945,6 +2547,8 @@ declare module 'bpmn-elements/events' { [x: string]: any; } + // --- Scripts ------------------------------------------------------------------ + interface IScripts { register(activity: any): Script | undefined; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; @@ -2954,552 +2558,1054 @@ declare module 'bpmn-elements/events' { execute(executionContext: any, callback: CallableFunction): void; } - export {}; -} - -declare module 'bpmn-elements/eventDefinitions' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; - export function CancelEventDefinition(activity: any, eventDefinition: any): void; - export class CancelEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(_: any, message: any): any; - _complete(output: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _debug(msg: any): void; - - private [K_EXECUTE_MESSAGE]; - - private [K_COMPLETED]; - } - export function CompensateEventDefinition(activity: any, eventDefinition: any, context: any): void; - export class CompensateEventDefinition { - constructor(activity: any, eventDefinition: any, context: any); - id: any; - type: any; - reference: { - referenceType: string; + /** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + class Environment { + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + constructor(options?: EnvironmentOptions); + options: {}; + expressions: IExpressions; + extensions: Record | undefined; + output: any; + scripts: IScripts | Scripts; + timers: ITimers | Timers; + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; - _onCollect(routingKey: any, message: any): any; - _onCompensateApiMessage(routingKey: any, message: any): any; - _compensate(): any; - _onCollected(routingKey: any, message: any): any; - _onDiscardApiMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stopCollect(): void; - _stop(): void; - _debug(msg: any): void; - - private [K_COMPLETED]; - - private [K_ASSOCIATIONS]; - - private [K_MESSAGE_Q]; - - private [K_COMPENSATE_Q]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ASSOCIATIONS: unique symbol; - const K_COMPENSATE_Q: unique symbol; - export function ConditionalEventDefinition(activity: any, eventDefinition: any, _context: any, index: any): void; - export class ConditionalEventDefinition { - constructor(activity: any, eventDefinition: any, _context: any, index: any); - id: any; - type: any; - behaviour: any; - activity: any; - environment: any; - broker: any; - logger: any; - condition: ScriptCondition | ExpressionCondition | null; - get executionId(): any; - execute(executeMessage: any): void; - _setup(executeMessage: any): void; + Logger: LoggerFactory | typeof DummyLogger; /** - * Evaluate condition + * Snapshot environment state for recover. + */ + getState(): { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + /** + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. * */ - evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; + recover(state?: EnvironmentState): this; /** - * Handle evaluate result or error - * @param err Condition evaluation error - * @param result Result from evaluated condition, completes execution if truthy + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. + * */ - evaluateCallback(err: Error | null, result: any): any; + clone(overrideOptions?: EnvironmentOptions): any; /** - * Get condition - * @param index Eventdefinition sequence number, used to name registered script + * Merge variables into the environment. Non-objects are ignored. * */ - getCondition(index: number): ExpressionCondition | ScriptCondition | null; - _onDelegateApiMessage(routingKey: any, message: any): void; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _debug(msg: any): void; + assignVariables(newVars: Record): void; + /** + * Merge settings into the environment. Non-objects are ignored. + * */ + assignSettings(newSettings: EnvironmentSettings): this; + /** + * Resolve a registered script by language and identifier. + * */ + getScript(...args: any[]): void | Script; + /** + * Register a script for an activity, delegating to the configured scripts engine. + * */ + registerScript(...args: any[]): void | Script; + /** + * Lookup a registered service by name. + * */ + getServiceByName(serviceName: string): CallableFunction; + /** + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param message Element message merged onto the resolution scope + * + */ + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + /** + * Register a service callable by name. + * */ + addService(name: string, fn: CallableFunction): void; - private [K_EXECUTE_MESSAGE]; + private [K_SERVICES]; + + private [K_VARIABLES]; } - export function ErrorEventDefinition(activity: any, eventDefinition: any): void; - export class ErrorEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onErrorMessage(routingKey: any, message: any): any; - _onThrowApiMessage(routingKey: any, message: any): any; - _catchError(routingKey: any, message: any, error: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; + function DummyLogger(): { + debug: () => void; + error: () => void; + warn: () => void; + }; + const K_SERVICES: unique symbol; + const K_VARIABLES: unique symbol; + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + class ContextInstance { + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); + id: string; + name: string; + type: string; + sid: string; + definitionContext: import("moddle-context-serializer").SerializableContext; + environment: Environment; + extensionsMapper: ExtensionsMapper; + refs: Map>; + get owner(): Activity | Process | undefined; + /** + * Get or create the activity instance for the given id. + * */ + getActivityById(activityId: string): any; + /** + * Return the cached activity instance, instantiating it the first time it is referenced. + * */ + upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + /** + * Get or create the sequence flow instance for the given id. + * */ + getSequenceFlowById(sequenceFlowId: string): any; - private [K_COMPLETED]; + getInboundSequenceFlows(activityId: string): any[]; - private [K_MESSAGE_Q]; + getOutboundSequenceFlows(activityId: string): any[]; - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - export function EscalationEventDefinition(activity: any, eventDefinition: any): void; - export class EscalationEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; + getInboundAssociations(activityId: string): any[]; - private [K_COMPLETED]; + getOutboundAssociations(activityId: string): any[]; + /** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getActivities(scopeId?: string): any[]; + /** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getSequenceFlows(scopeId?: string): any[]; + /** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * */ + upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * @param scopeId Process or sub-process id + */ + getAssociations(scopeId?: string): any[]; - private [K_MESSAGE_Q]; + upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * + */ + clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; + /** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * */ + getProcessById(processId: string): any; + /** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * */ + getNewProcessById(processId: string): any; + /** + * Get every process in the definition. + */ + getProcesses(): any[]; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any[]; + /** + * Get message flows that originate from the given process id. + * @param sourceId Source process id + */ + getMessageFlows(sourceId: string): any[]; + /** + * Get or create a data object instance for the given reference id. + * */ + getDataObjectById(referenceId: string): any; + /** + * Get or create a data store instance for the given reference id. + * */ + getDataStoreById(referenceId: string): any; + /** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param scopeId Process or sub-process id + */ + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + /** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * */ + loadExtensions(activity: ElementBase): Extensions | undefined; + /** + * Resolve the parent process or sub-process activity that owns the given activity. + * */ + getActivityParentById(activityId: string): any; - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE]: { - message: any; - } | { - message: any; - description: string; - } | undefined; + private [K_OWNER]; } - const K_REFERENCE: unique symbol; - export function LinkEventDefinition(activity: any, eventDefinition: any): void; - export class LinkEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - id: any; - linkName: any; - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; - _onLinkApiMessage(_: any, message: any): void; - _onShakeMessage(_: any, message: any): void; + class ExtensionsMapper { + constructor(context: any); + context: any; + get(activity: any): Extensions; - private [K_EXECUTE_MESSAGE]; + _getExtensions(): any[]; } - export function MessageEventDefinition(activity: any, eventDefinition: any): void; - export class MessageEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): void; - _onApiMessage(routingKey: any, message: any): any; - _complete(verb: any, output: any, options: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; + class Extensions { + constructor(activity: any, context: any, extensions: any); + extensions: any[]; + get count(): number; + activate(message: any): void; + deactivate(message: any): void; - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; + private [K_ACTIVATED]; } - export function SignalEventDefinition(activity: any, eventDefinition: any): void; - export class SignalEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _complete(output: any, options: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; + const K_OWNER: unique symbol; + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + class Process { + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + isExecutable: any; + environment: Environment; + context: ContextInstance; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; + /** + * Allocate an executionId and emit init event without starting the run. + * @param useAsExecutionId Override for the generated execution id + */ + init(useAsExecutionId?: string): void; + /** + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param runContent Optional content merged into the run message + * @throws {Error} when the process is already running + */ + run(runContent?: Record): void; + /** + * Resume after recover by republishing the last run message. + * @throws {Error} when called on a running process + */ + resume(): this; + /** + * Snapshot process state for recover. + */ + getState(): { + id: string | undefined; + type: string; + executionId: any; + environment: { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + status: any; + stopped: any; + counters: any; + broker: { + exchanges: { + bindings?: { + id: string; + options: { + priority: number; + }; + queueName: string; + pattern: string; + }[] | undefined; + deliveryQueue?: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + } | undefined; + name: string; + type: import("smqp").exchangeType; + options: { + [x: string]: any; + durable?: boolean; + autoDelete?: boolean; + }; + }[] | undefined; + queues: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + }[] | undefined; + } | undefined; + execution: any; + }; + /** + * Restore process state captured by getState. + * @throws {Error} when called on a running process + */ + recover(state?: ProcessState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. + * + */ + shake(startId?: string): any; + /** + * Stop the process if running. + */ + stop(): void; + /** + * Resolve a Process Api wrapper, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Send a delegated signal to the running process. + * + */ + signal(message?: signalMessage): any; + /** + * Cancel a running activity inside the process by delegated api message. + * + */ + cancelActivity(message?: signalMessage): any; - private [K_COMPLETED]; + _activateRunConsumers(): void; - private [K_MESSAGE_Q]; + _deactivateRunConsumers(): void; + + _onRunMessage(routingKey: any, message: any): any; + + _onResumeMessage(message: any): any; + + _onExecutionMessage(routingKey: any, message: any): void; + + _publishEvent(state: any, content: any): void; + /** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. + * */ + sendMessage(message: ElementBrokerMessage): void; + + getActivityById(childId: string): any; + /** + * Get every activity in the process scope. + */ + getActivities(): any; + /** + * Get start activities, optionally filtered by referenced event definition. + * + */ + getStartActivities(filterOptions?: startActivityFilterOptions): any[]; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any; + + getLaneById(laneId: string): any; + /** + * List currently postponed activities as Api wrappers. + * + */ + getPostponed(...args: any[]): any; + + _onApiMessage(routingKey: any, message: any): void; + + _onStop(): void; + + _createMessage(override: any): any; + + _debug(msg: any): void; + + private [K_COUNTERS]; + + private [K_CONSUMING]; + + private [K_EXECUTION]; + + private [K_STATUS]; + + private [K_STOPPED]; + + private [K_MESSAGE_HANDLERS]; + + private [K_LANES]; + + private [K_EXTENSIONS]; + + private [K_STATE_MESSAGE]; private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; } - export function TerminateEventDefinition(activity: any, eventDefinition: any): void; - export class TerminateEventDefinition { + const K_LANES: unique symbol; + class Timers { + constructor(options: any); + count: number; + options: any; + setTimeout: any; + clearTimeout: any; + get executing(): any[]; + register(owner: any): RegisteredTimers; + _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; + _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; + + private [K_EXECUTING]; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + + private [K_TIMER_API]; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + const K_EXECUTING: unique symbol; + const K_TIMER_API: unique symbol; + class Scripts { + getScript(): void; + register(): void; + } + + export {}; +} + +declare module 'bpmn-elements/eventDefinitions' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; + export class CancelEventDefinition { constructor(activity: any, eventDefinition: any); id: any; type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + environment: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(_: any, message: any): any; + _complete(output: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _debug(msg: any): void; + + private [K_EXECUTE_MESSAGE]; + + private [K_COMPLETED]; + } + export class CompensateEventDefinition { + constructor(activity: any, eventDefinition: any, context: any); + id: any; + type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + _onCollect(routingKey: any, message: any): any; + _onCompensateApiMessage(routingKey: any, message: any): any; + _compensate(): any; + _onCollected(routingKey: any, message: any): any; + _onDiscardApiMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stopCollect(): void; + _stop(): void; + _debug(msg: any): void; + + private [K_COMPLETED]; + + private [K_ASSOCIATIONS]; + + private [K_MESSAGE_Q]; + + private [K_COMPENSATE_Q]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ASSOCIATIONS: unique symbol; + const K_COMPENSATE_Q: unique symbol; + export class ConditionalEventDefinition { + constructor(activity: any, eventDefinition: any, _context: any, index: any); + id: any; + type: any; + behaviour: any; activity: any; + environment: any; broker: any; logger: any; + condition: ScriptCondition | ExpressionCondition | null; + get executionId(): any; execute(executeMessage: any): void; + _setup(executeMessage: any): void; + /** + * Evaluate condition + * */ + evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; + /** + * Handle evaluate result or error + * @param err Condition evaluation error + * @param result Result from evaluated condition, completes execution if truthy + */ + evaluateCallback(err: Error | null, result: any): any; + /** + * Get condition + * @param index Eventdefinition sequence number, used to name registered script + * */ + getCondition(index: number): ExpressionCondition | ScriptCondition | null; + _onDelegateApiMessage(routingKey: any, message: any): void; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _debug(msg: any): void; + + private [K_EXECUTE_MESSAGE]; } - export function TimerEventDefinition(activity: any, eventDefinition: any): void; - export class TimerEventDefinition { + export class ErrorEventDefinition { constructor(activity: any, eventDefinition: any); + id: any; type: any; + reference: any; + isThrowing: any; activity: any; environment: any; - eventDefinition: any; - timeDuration: any; - timeCycle: any; - timeDate: any; broker: any; logger: any; - execute(executeMessage: any): void; - startedAt: Date | undefined; - stop(): void; - _completed(completeContent: any, options: any): void; - _onDelegatedApiMessage(routingKey: any, message: any): any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onErrorMessage(routingKey: any, message: any): any; + _onThrowApiMessage(routingKey: any, message: any): any; + _catchError(routingKey: any, message: any, error: any): any; _onApiMessage(routingKey: any, message: any): any; _stop(): void; - parse(timerType: any, value: any): { - expireAt: Date | undefined; - repeat: number | undefined; - delay: number | undefined; - }; - _getTimers(executeMessage: any): { - expireAt?: Date | undefined; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; }; _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; - private [K_STOPPED]; + private [K_COMPLETED]; - private [K_TIMER]; - [K_TIMER_CONTENT]: any; + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; } - const K_TIMER: unique symbol; - const K_TIMER_CONTENT: unique symbol; - const K_ACTIVATED: unique symbol; - const K_COMPLETED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_MESSAGE_Q: unique symbol; - const K_REFERENCE_ELEMENT: unique symbol; - const K_REFERENCE_INFO: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STOPPED: unique symbol; - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; + export class EscalationEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + const K_REFERENCE: unique symbol; + export class LinkEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: { + id: any; + linkName: any; + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + _onLinkApiMessage(_: any, message: any): void; + _onShakeMessage(_: any, message: any): void; + + private [K_EXECUTE_MESSAGE]; + } + export class MessageEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): void; + _onApiMessage(routingKey: any, message: any): any; + _complete(verb: any, output: any, options: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export class SignalEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + _onCatchMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _complete(output: any, options: any): any; + _stop(): void; + _getReferenceInfo(message: any): { + message: any; + } | { + message: any; + description: string; + }; + _debug(msg: any): void; + [K_REFERENCE_ELEMENT]: any; + + private [K_COMPLETED]; + + private [K_MESSAGE_Q]; + + private [K_EXECUTE_MESSAGE]; + [K_REFERENCE_INFO]: { + message: any; + } | { + message: any; + description: string; + } | undefined; + } + export class TerminateEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + activity: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + } + export class TimerEventDefinition { + constructor(activity: any, eventDefinition: any); + type: any; + activity: any; + environment: any; + eventDefinition: any; + timeDuration: any; + timeCycle: any; + timeDate: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + startedAt: Date | undefined; + stop(): void; + _completed(completeContent: any, options: any): void; + _onDelegatedApiMessage(routingKey: any, message: any): any; + _onApiMessage(routingKey: any, message: any): any; + _stop(): void; + parse(timerType: any, value: any): { + expireAt: Date | undefined; + repeat: number | undefined; + delay: number | undefined; + }; + _getTimers(executeMessage: any): { + expireAt?: Date | undefined; + }; + _debug(msg: any): void; + + private [K_STOPPED]; + + private [K_TIMER]; + [K_TIMER_CONTENT]: any; + } + const K_TIMER: unique symbol; + const K_TIMER_CONTENT: unique symbol; + const K_ACTIVATED: unique symbol; + const K_COMPLETED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXECUTION: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_MESSAGE_Q: unique symbol; + const K_REFERENCE_ELEMENT: unique symbol; + const K_REFERENCE_INFO: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_STATUS: unique symbol; + const K_STOPPED: unique symbol; + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; } - class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): Api; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; } - interface Api extends ElementBrokerMessage { + interface ElementParent { get id(): string; get type(): string; - get name(): string; get executionId(): string; - get environment(): Environment; - get broker(): ElementBroker; - get owner(): T; - cancel(message?: signalMessage, options?: any): void; - discard(): void; - fail(error: Error): void; - signal(message?: signalMessage, options?: any): void; - stop(): void; - resolveExpression(expression: string): any; - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - getPostponed(...args: any[]): any[]; - createMessage(content?: Record): any; - getExecuting(): Api[]; - } - - class Environment { - constructor(options?: EnvironmentOptions); - options: Record; - expressions: IExpressions; - extensions: Record; - scripts: IScripts; - timers: ITimers; - Logger: LoggerFactory; - get settings(): EnvironmentSettings; - get variables(): Record; - get output(): Record; - set services(arg: any); - get services(): any; - getState(): EnvironmentState; - recover(state?: EnvironmentState): Environment; - clone(overrideOptions?: EnvironmentOptions): Environment; - assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): Environment; - registerScript(activity: any): Script; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - getServiceByName(serviceName: string): CallableFunction; - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - addService(name: string, fn: CallableFunction): void; + get path(): ElementParent[]; } - class ContextInstance { - constructor(definitionContext: SerializableContext, environment?: Environment); + + // --- Element abstract bases --------------------------------------------------- + + class ElementBase { get id(): string; - get name(): string; get type(): string; - /** Unique context instance id */ - get sid(): string; - get definitionContext(): SerializableContext; - get environment(): Environment; - /** Context owner, Process or SubProcess activity */ - get owner(): Process | Activity | undefined; - getActivityById(activityId: string): T; - getSequenceFlowById(sequenceFlowId: string): SequenceFlow; - getInboundSequenceFlows(activityId: string): SequenceFlow[]; - getOutboundSequenceFlows(activityId: string): SequenceFlow[]; - getInboundAssociations(activityId: string): Association[]; - getOutboundAssociations(activityId: string): Association[]; - getActivities(scopeId?: string): ElementBase[]; - getSequenceFlows(scopeId?: string): SequenceFlow[]; - getAssociations(scopeId?: string): Association[]; - clone(newEnvironment?: Environment): ContextInstance; - getProcessById(processId: string): Process; - getNewProcessById(processId: string): Process; - getProcesses(): Process[]; - getExecutableProcesses(): Process[]; - getMessageFlows(sourceId: string): MessageFlow[]; - getDataObjectById(referenceId: string): any; - getDataStoreById(referenceId: string): any; - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; - loadExtensions(activity: ElementBase): IExtension; - } - - class Process extends Element { - constructor(processDef: SerializableElement, context: ContextInstance); - get isExecutable(): boolean; - get counters(): completedCounters; - get lanes(): Lane[] | undefined; - get extensions(): IExtension; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string; - get execution(): ProcessExecution; - get status(): ProcessRunStatus | undefined; - get activityStatus(): ActivityStatus; - init(useAsExecutionId?: string): void; - run(runContent?: Record): void; - getState(): ProcessState; - recover(state?: ProcessState): Process; - shake(startId?: string): void; - signal(message: any): any; - cancelActivity(message: any): any; - sendMessage(message: any): void; - getActivityById(childId: string): T; - getActivities(): Activity[]; - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; - getSequenceFlows(): SequenceFlow[]; - getLaneById(laneId: string): Lane | undefined; - getPostponed(filterFn: filterPostponed): Api[]; - } - - interface ProcessExecution { - get isSubProcess(): boolean; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; get broker(): Broker; get environment(): Environment; get context(): ContextInstance; - get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; + get logger(): ILogger; + } + + // --- Activity behaviour & extensions ------------------------------------------ + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; execute(executeMessage: ElementBrokerMessage): void; - getPostponed(filterFn: filterPostponed): Api[]; - getActivities(): Activity[]; - getActivityById(activityId: string): T; - getSequenceFlows(): SequenceFlow[]; - getApi(message?: ElementBrokerMessage): Api; } - class Lane extends ElementBase { - constructor(process: Process, laneDefinition: SerializableElement); - /** Process broker */ - get broker(): Broker; - get process(): Process; - } - - class SequenceFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isDefault(): boolean; - get isSequenceFlow(): boolean; - get counters(): { take: number; discard: number; looped: number }; - take(content?: any): boolean; - discard(content?: any): void; - shake(message: any): number; - getCondition(): ISequenceFlowCondition | null; - createMessage(override?: any): object; - /** - * Evaluate flow - * Executes condition if any, default flow is - * @param fromMessage Activity message - * @param callback Callback with evaluation result, if truthy flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - getState(): SequenceFlowState | undefined; - } - - class MessageFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get source(): MessageFlowReference; - get target(): MessageFlowReference; - get counters(): { messages: number }; - activate(): void; - deactivate(): void; - getState(): MessageFlowState | undefined; - } - - class Association extends Element { - constructor(associationDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isAssociation(): boolean; - get counters(): { take: number; discard: number }; - take(content?: any): boolean; - discard(content?: any): boolean; - getState(): AssociationState | undefined; + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; } - /** - * Script condition - * */ - function ScriptCondition(owner: ElementBase, script: any, language: string): void; - class ScriptCondition { + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + // --- Environment -------------------------------------------------------------- + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + // --- Filter / callback shapes ------------------------------------------------- + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + // --- State snapshots ---------------------------------------------------------- + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + // --- Logging ------------------------------------------------------------------ + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + // --- Timers ------------------------------------------------------------------- + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + // --- Scripts ------------------------------------------------------------------ + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + + /** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ + /** + * Script condition + * */ + class ScriptCondition { /** * Script condition * */ @@ -3516,8 +3622,7 @@ declare module 'bpmn-elements/eventDefinitions' { /** * Expression condition * */ - function ExpressionCondition(owner: ElementBase, expression: string): void; - class ExpressionCondition { + class ExpressionCondition { /** * Expression condition * */ @@ -3536,8 +3641,7 @@ declare module 'bpmn-elements/eventDefinitions' { * @param activityDef Parsed BPMN element definition * @param context Per-execution registry and factory */ - function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - class Activity { + class Activity { /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param Behaviour Element-specific behaviour constructor invoked per execution @@ -3553,10 +3657,14 @@ declare module 'bpmn-elements/eventDefinitions' { }; Behaviour: IActivityBehaviour; parent: any; - logger: ILogger; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; environment: Environment; context: ContextInstance; - broker: import("smqp").default | undefined; + broker: import("smqp").Broker; on: any; once: any; waitFor: any; @@ -3686,7 +3794,7 @@ declare module 'bpmn-elements/eventDefinitions' { _createMessage(override: any): any; - _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; + _getOutboundSequenceFlowById(flowId: any): any; _deactivateRunConsumers(): void; @@ -3722,1777 +3830,774 @@ declare module 'bpmn-elements/eventDefinitions' { const K_EXEC: unique symbol; const K_EVENT_DEFINITIONS: unique symbol; const K_CONSUMING_RUN_Q: unique symbol; - interface ElementBroker extends Broker { - get owner(): T; - } - - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - } - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - type filterPostponed = (elementApi: any) => boolean; - - enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', - } - - /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ - enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', - /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc - */ - Wait = 'wait', - } - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; - } - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - - export {}; -} - -declare module 'bpmn-elements/flows' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; - /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. * */ - export function Association(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; - export class Association { + class Process { /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. * */ - constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); id: string | undefined; type: string; name: any; parent: any; behaviour: Record; - sourceId: any; - targetId: any; - isAssociation: boolean; + isExecutable: any; environment: Environment; - logger: ILogger; - broker: import("smqp").default | undefined; + context: ContextInstance; + broker: import("smqp").Broker; on: any; once: any; waitFor: any; - get counters(): { - take: number; - discard: number; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; }; /** - * Take the association and publish association.take. - * + * Allocate an executionId and emit init event without starting the run. + * @param useAsExecutionId Override for the generated execution id */ - take(content?: Record): boolean; + init(useAsExecutionId?: string): void; /** - * Discard the association and publish association.discard. - * + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param runContent Optional content merged into the run message + * @throws {Error} when the process is already running */ - discard(content?: Record): boolean; + run(runContent?: Record): void; /** - * Snapshot association state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): AssociationState | undefined; + * Resume after recover by republishing the last run message. + * @throws {Error} when called on a running process + */ + resume(): this; /** - * Restore association state captured by getState. - * */ - recover(state: AssociationState): void; + * Snapshot process state for recover. + */ + getState(): { + id: string | undefined; + type: string; + executionId: any; + environment: { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + status: any; + stopped: any; + counters: any; + broker: { + exchanges: { + bindings?: { + id: string; + options: { + priority: number; + }; + queueName: string; + pattern: string; + }[] | undefined; + deliveryQueue?: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + } | undefined; + name: string; + type: import("smqp").exchangeType; + options: { + [x: string]: any; + durable?: boolean; + autoDelete?: boolean; + }; + }[] | undefined; + queues: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + }[] | undefined; + } | undefined; + execution: any; + }; /** - * Resolve an association-scoped Api wrapper. + * Restore process state captured by getState. + * @throws {Error} when called on a running process + */ + recover(state?: ProcessState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. * */ - getApi(message?: ElementBrokerMessage): Api_1; + shake(startId?: string): any; /** - * Stop the association's broker. + * Stop the process if running. */ stop(): void; - - _publishEvent(action: any, content: any): void; - - _createMessageContent(override: any): any; - - private [K_COUNTERS]; - } - /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - export function MessageFlow(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - export class MessageFlow { /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - source: any; - target: any; - behaviour: Record; - environment: Environment; - context: ContextInstance; - broker: import("smqp").default | undefined; - on: any; - once: any; - emit: any; - waitFor: any; - logger: ILogger; - get counters(): { - messages: number; - }; + * Resolve a Process Api wrapper, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; /** - * Snapshot message-flow state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): MessageFlowState | undefined; + * Send a delegated signal to the running process. + * + */ + signal(message?: signalMessage): any; /** - * Restore message-flow state captured by getState. + * Cancel a running activity inside the process by delegated api message. + * + */ + cancelActivity(message?: signalMessage): any; + + _activateRunConsumers(): void; + + _deactivateRunConsumers(): void; + + _onRunMessage(routingKey: any, message: any): any; + + _onResumeMessage(message: any): any; + + _onExecutionMessage(routingKey: any, message: any): void; + + _publishEvent(state: any, content: any): void; + /** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. * */ - recover(state: MessageFlowState): void; + sendMessage(message: ElementBrokerMessage): void; + + getActivityById(childId: string): any; /** - * Resolve a message-scoped Api wrapper. + * Get every activity in the process scope. + */ + getActivities(): any; + /** + * Get start activities, optionally filtered by referenced event definition. * */ - getApi(message?: ElementBrokerMessage): Api_1; + getStartActivities(filterOptions?: startActivityFilterOptions): any[]; /** - * Subscribe to the source element's message and end events to bridge the message across. + * Get sequence flows in the process scope. */ - activate(): void; + getSequenceFlows(): any; + + getLaneById(laneId: string): any; /** - * Cancel the source element subscriptions added by activate. + * List currently postponed activities as Api wrappers. + * */ - deactivate(): void; + getPostponed(...args: any[]): any; - _onSourceEnd({ content }: { - content: any; - }): void; + _onApiMessage(routingKey: any, message: any): void; - _createMessageContent(message: any): { - id: string | undefined; - type: string; - name: any; - source: any; - target: any; - parent: any; - message: any; - }; + _onStop(): void; + + _createMessage(override: any): any; + + _debug(msg: any): void; private [K_COUNTERS]; - private [K_SOURCE_ELEMENT]; + private [K_CONSUMING]; + + private [K_EXECUTION]; + + private [K_STATUS]; + + private [K_STOPPED]; + + private [K_MESSAGE_HANDLERS]; + + private [K_LANES]; + + private [K_EXTENSIONS]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; } - const K_SOURCE_ELEMENT: unique symbol; + const K_LANES: unique symbol; /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - export function SequenceFlow(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance): void; - export class SequenceFlow { + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + class Environment { /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - sourceId: any; - targetId: any; - isDefault: any; - isSequenceFlow: boolean; - environment: Environment; - logger: ILogger; - broker: import("smqp").default | undefined; - on: any; - once: any; - waitFor: any; - emitFatal: any; - get counters(): { - take: number; - discard: number; - looped: number; + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + constructor(options?: EnvironmentOptions); + options: {}; + expressions: IExpressions; + extensions: Record | undefined; + output: any; + scripts: IScripts | Scripts; + timers: ITimers | Timers; + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; }; + Logger: LoggerFactory | typeof DummyLogger; /** - * Take the flow and publish flow.take. - * + * Snapshot environment state for recover. */ - take(content?: Record): boolean; + getState(): { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; /** - * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits - * flow.looped instead when the target id is already in the sequence. + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. + * */ + recover(state?: EnvironmentState): this; + /** + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. * */ - discard(content?: Record): void; + clone(overrideOptions?: EnvironmentOptions): any; /** - * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` - * is set. + * Merge variables into the environment. Non-objects are ignored. * */ - getState(): SequenceFlowState | undefined; + assignVariables(newVars: Record): void; /** - * Restore flow state captured by getState. + * Merge settings into the environment. Non-objects are ignored. * */ - recover(state: SequenceFlowState): void; - /** - * Resolve a Flow Api wrapper. - * - */ - getApi(message?: ElementBrokerMessage): Api_1; + assignSettings(newSettings: EnvironmentSettings): this; /** - * Stop the flow's broker. - */ - stop(): void; + * Resolve a registered script by language and identifier. + * */ + getScript(...args: any[]): void | Script; /** - * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop - * when the target was already visited, otherwise flow.shake. + * Register a script for an activity, delegating to the configured scripts engine. * */ - shake(message: ElementBrokerMessage): any; + registerScript(...args: any[]): void | Script; /** - * Resolve the flow's condition (script or expression). Returns null when no condition is set. - * Emits a fatal error when the script language is missing or unsupported. + * Lookup a registered service by name. * */ - getCondition(): ISequenceFlowCondition | null; + getServiceByName(serviceName: string): CallableFunction; /** - * Build a flow event message body, optionally merging override content. + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param message Element message merged onto the resolution scope * */ - createMessage(override?: Record): { - id: string | undefined; - type: string; - name: any; - sourceId: any; - targetId: any; - isSequenceFlow: boolean; - isDefault: any; - parent: any; - }; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; /** - * Evaluate the flow's condition for the source activity message. Default flows are always taken. - * @param fromMessage Source activity message - * @param callback Callback with truthy result if flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; + * Register a service callable by name. + * */ + addService(name: string, fn: CallableFunction): void; - _publishEvent(action: any, content: any): void; + private [K_SERVICES]; - private [K_COUNTERS]; + private [K_VARIABLES]; } - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): Api; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; - } - - interface Api extends ElementBrokerMessage { - get id(): string; - get type(): string; - get name(): string; - get executionId(): string; - get environment(): Environment; - get broker(): ElementBroker; - get owner(): T; - cancel(message?: signalMessage, options?: any): void; - discard(): void; - fail(error: Error): void; - signal(message?: signalMessage, options?: any): void; - stop(): void; - resolveExpression(expression: string): any; - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - getPostponed(...args: any[]): any[]; - createMessage(content?: Record): any; - getExecuting(): Api[]; - } - - class Environment { - constructor(options?: EnvironmentOptions); - options: Record; - expressions: IExpressions; - extensions: Record; - scripts: IScripts; - timers: ITimers; - Logger: LoggerFactory; - get settings(): EnvironmentSettings; - get variables(): Record; - get output(): Record; - set services(arg: any); - get services(): any; - getState(): EnvironmentState; - recover(state?: EnvironmentState): Environment; - clone(overrideOptions?: EnvironmentOptions): Environment; - assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): Environment; - registerScript(activity: any): Script; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - getServiceByName(serviceName: string): CallableFunction; - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - addService(name: string, fn: CallableFunction): void; - } - class ContextInstance { - constructor(definitionContext: SerializableContext, environment?: Environment); - get id(): string; - get name(): string; - get type(): string; - /** Unique context instance id */ - get sid(): string; - get definitionContext(): SerializableContext; - get environment(): Environment; - /** Context owner, Process or SubProcess activity */ - get owner(): Process | Activity | undefined; - getActivityById(activityId: string): T; - getSequenceFlowById(sequenceFlowId: string): SequenceFlow_1; - getInboundSequenceFlows(activityId: string): SequenceFlow_1[]; - getOutboundSequenceFlows(activityId: string): SequenceFlow_1[]; - getInboundAssociations(activityId: string): Association_1[]; - getOutboundAssociations(activityId: string): Association_1[]; - getActivities(scopeId?: string): ElementBase[]; - getSequenceFlows(scopeId?: string): SequenceFlow_1[]; - getAssociations(scopeId?: string): Association_1[]; - clone(newEnvironment?: Environment): ContextInstance; - getProcessById(processId: string): Process; - getNewProcessById(processId: string): Process; - getProcesses(): Process[]; - getExecutableProcesses(): Process[]; - getMessageFlows(sourceId: string): MessageFlow_1[]; - getDataObjectById(referenceId: string): any; - getDataStoreById(referenceId: string): any; - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; - loadExtensions(activity: ElementBase): IExtension; - } - - class Process extends Element { - constructor(processDef: SerializableElement, context: ContextInstance); - get isExecutable(): boolean; - get counters(): completedCounters; - get lanes(): Lane[] | undefined; - get extensions(): IExtension; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string; - get execution(): ProcessExecution; - get status(): ProcessRunStatus | undefined; - get activityStatus(): ActivityStatus; - init(useAsExecutionId?: string): void; - run(runContent?: Record): void; - getState(): ProcessState; - recover(state?: ProcessState): Process; - shake(startId?: string): void; - signal(message: any): any; - cancelActivity(message: any): any; - sendMessage(message: any): void; - getActivityById(childId: string): T; - getActivities(): Activity[]; - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; - getSequenceFlows(): SequenceFlow_1[]; - getLaneById(laneId: string): Lane | undefined; - getPostponed(filterFn: filterPostponed): Api[]; - } - - interface ProcessExecution { - get isSubProcess(): boolean; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; - execute(executeMessage: ElementBrokerMessage): void; - getPostponed(filterFn: filterPostponed): Api[]; - getActivities(): Activity[]; - getActivityById(activityId: string): T; - getSequenceFlows(): SequenceFlow_1[]; - getApi(message?: ElementBrokerMessage): Api; - } - - class Lane extends ElementBase { - constructor(process: Process, laneDefinition: SerializableElement); - /** Process broker */ - get broker(): Broker; - get process(): Process; - } - - class SequenceFlow_1 extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isDefault(): boolean; - get isSequenceFlow(): boolean; - get counters(): { take: number; discard: number; looped: number }; - take(content?: any): boolean; - discard(content?: any): void; - shake(message: any): number; - getCondition(): ISequenceFlowCondition | null; - createMessage(override?: any): object; - /** - * Evaluate flow - * Executes condition if any, default flow is - * @param fromMessage Activity message - * @param callback Callback with evaluation result, if truthy flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - getState(): SequenceFlowState | undefined; - } - - class MessageFlow_1 extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get source(): MessageFlowReference; - get target(): MessageFlowReference; - get counters(): { messages: number }; - activate(): void; - deactivate(): void; - getState(): MessageFlowState | undefined; - } - - class Association_1 extends Element { - constructor(associationDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isAssociation(): boolean; - get counters(): { take: number; discard: number }; - take(content?: any): boolean; - discard(content?: any): boolean; - getState(): AssociationState | undefined; - } - interface ElementBroker extends Broker { - get owner(): T; - } - - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; + function DummyLogger(): { + debug: () => void; + error: () => void; + warn: () => void; + }; + const K_SERVICES: unique symbol; + const K_VARIABLES: unique symbol; /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } + class ContextInstance { + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); + id: string; + name: string; + type: string; + sid: string; + definitionContext: import("moddle-context-serializer").SerializableContext; + environment: Environment; + extensionsMapper: ExtensionsMapper; + refs: Map>; + get owner(): Activity | Process | undefined; + /** + * Get or create the activity instance for the given id. + * */ + getActivityById(activityId: string): any; + /** + * Return the cached activity instance, instantiating it the first time it is referenced. + * */ + upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + /** + * Get or create the sequence flow instance for the given id. + * */ + getSequenceFlowById(sequenceFlowId: string): any; + + getInboundSequenceFlows(activityId: string): any[]; + + getOutboundSequenceFlows(activityId: string): any[]; + + getInboundAssociations(activityId: string): any[]; + + getOutboundAssociations(activityId: string): any[]; + /** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getActivities(scopeId?: string): any[]; + /** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getSequenceFlows(scopeId?: string): any[]; + /** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * */ + upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * @param scopeId Process or sub-process id + */ + getAssociations(scopeId?: string): any[]; + + upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * + */ + clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; + /** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * */ + getProcessById(processId: string): any; + /** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * */ + getNewProcessById(processId: string): any; + /** + * Get every process in the definition. + */ + getProcesses(): any[]; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any[]; + /** + * Get message flows that originate from the given process id. + * @param sourceId Source process id + */ + getMessageFlows(sourceId: string): any[]; + /** + * Get or create a data object instance for the given reference id. + * */ + getDataObjectById(referenceId: string): any; + /** + * Get or create a data store instance for the given reference id. + * */ + getDataStoreById(referenceId: string): any; + /** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param scopeId Process or sub-process id + */ + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + /** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * */ + loadExtensions(activity: ElementBase): Extensions | undefined; + /** + * Resolve the parent process or sub-process activity that owns the given activity. + * */ + getActivityParentById(activityId: string): any; + + private [K_OWNER]; + } + class ExtensionsMapper { + constructor(context: any); + context: any; + get(activity: any): Extensions; + + _getExtensions(): any[]; + } + class Extensions { + constructor(activity: any, context: any, extensions: any); + extensions: any[]; + get count(): number; + activate(message: any): void; + deactivate(message: any): void; + + private [K_ACTIVATED]; + } + const K_OWNER: unique symbol; + class Timers { + constructor(options: any); + count: number; + options: any; + setTimeout: any; + clearTimeout: any; + get executing(): any[]; + register(owner: any): RegisteredTimers; + _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; + _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; + + private [K_EXECUTING]; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + + private [K_TIMER_API]; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + const K_EXECUTING: unique symbol; + const K_TIMER_API: unique symbol; + class Scripts { + getScript(): void; + register(): void; + } - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } + export {}; +} - interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; +declare module 'bpmn-elements/flows' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - } - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - type filterPostponed = (elementApi: any) => boolean; - - enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', - } - - /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ - enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', - /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc - */ - Wait = 'wait', - } - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; - } - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - /** - * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. - * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` - * @param sourceMessage Cloned to back the api - * @param environment Defaults to `broker.owner.environment` - * @throws {Error} when sourceMessage is missing - */ - function Api_1(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment): void; - class Api_1 { + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + export class Association { /** - * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. - * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` - * @param sourceMessage Cloned to back the api - * @param environment Defaults to `broker.owner.environment` - * @throws {Error} when sourceMessage is missing - */ - constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment); - id: any; - type: any; + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; name: any; - executionId: any; - environment: any; - content: any; - fields: any; - messageProperties: any; - broker: any; - owner: any; - messagePrefix: string; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isAssociation: boolean; + environment: Environment; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + get counters(): { + take: number; + discard: number; + }; /** - * Send a cancel api message. + * Take the association and publish association.take. * */ - cancel(message?: signalMessage, options?: any): void; + take(content?: Record): boolean; /** - * Send a discard api message. + * Discard the association and publish association.discard. + * */ - discard(): void; + discard(content?: Record): boolean; /** - * Send an error api message that fails the activity. + * Snapshot association state. Returns undefined when broker has no state and + * `disableTrackState` is set. * */ - fail(error: Error): void; + getState(): AssociationState | undefined; /** - * Send a signal api message. + * Restore association state captured by getState. + * */ + recover(state: AssociationState): void; + /** + * Resolve an association-scoped Api wrapper. * */ - signal(message?: signalMessage, options?: any): void; + getApi(message?: ElementBrokerMessage): Api; /** - * Send a stop api message. + * Stop the association's broker. */ stop(): void; - /** - * Resolve an expression with the api message as scope and the broker owner as context. - * */ - resolveExpression(expression: string): any; - /** - * Publish a custom api message to the broker. - * @param action Routing key suffix, e.g. `signal`, `cancel` - * @param content Merged into the message content - * - */ - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - /** - * List currently postponed activities, falling back to a sub-process execution when applicable. - * - */ - getPostponed(...args: any[]): any; - /** - * Build a message body by merging the given content onto the source content. - * - */ - createMessage(content?: Record): any; + + _publishEvent(action: any, content: any): void; + + _createMessageContent(override: any): any; + + private [K_COUNTERS]; } - const K_ACTIVATED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_STATE_MESSAGE: unique symbol; /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - class Activity { + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + export class MessageFlow { /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); id: string | undefined; type: string; name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; parent: any; - logger: ILogger; + source: any; + target: any; + behaviour: Record; environment: Environment; context: ContextInstance; - broker: import("smqp").default | undefined; + broker: import("smqp").Broker; on: any; once: any; + emit: any; waitFor: any; - emitFatal: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + get counters(): { + messages: number; + }; /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; + * Snapshot message-flow state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): MessageFlowState | undefined; /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; + * Restore message-flow state captured by getState. + * */ + recover(state: MessageFlowState): void; /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message + * Resolve a message-scoped Api wrapper. + * */ - init(initContent?: Record): void; + getApi(message?: ElementBrokerMessage): Api; /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running + * Subscribe to the source element's message and end events to bridge the message across. */ - run(runContent?: Record): void; + activate(): void; /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. + * Cancel the source element subscriptions added by activate. */ - getState(): any; + deactivate(): void; + + _onSourceEnd({ content }: { + content: any; + }): void; + + _createMessageContent(message: any): { + id: string | undefined; + type: string; + name: any; + source: any; + target: any; + parent: any; + message: any; + }; + + private [K_COUNTERS]; + + private [K_SOURCE_ELEMENT]; + } + const K_SOURCE_ELEMENT: unique symbol; + /** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + export class SequenceFlow { /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isDefault: any; + isSequenceFlow: boolean; + environment: Environment; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + emitFatal: any; + get counters(): { + take: number; + discard: number; + looped: number; + }; /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity + * Take the flow and publish flow.take. + * */ - resume(): 0 | import("smqp").Consumer | undefined; + take(content?: Record): boolean; /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard + * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits + * flow.looped instead when the target id is already in the sequence. + * */ - discard(discardContent?: Record): any; + discard(content?: Record): void; /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; + * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` + * is set. + * */ + getState(): SequenceFlowState | undefined; /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; + * Restore flow state captured by getState. + * */ + recover(state: SequenceFlowState): void; /** - * Stop the activity. If not currently running, just cancels the inbound consumer. + * Resolve a Flow Api wrapper. + * */ - stop(): any; + getApi(message?: ElementBrokerMessage): Api; /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. + * Stop the flow's broker. */ - next(): any; + stop(): void; /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; + * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop + * when the target was already visited, otherwise flow.shake. + * */ + shake(message: ElementBrokerMessage): any; /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * Resolve the flow's condition (script or expression). Returns null when no condition is set. + * Emits a fatal error when the script language is missing or unsupported. * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + getCondition(): ISequenceFlowCondition | null; /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. + * Build a flow event message body, optionally merging override content. * */ - getApi(message?: ElementBrokerMessage): any; + createMessage(override?: Record): { + id: string | undefined; + type: string; + name: any; + sourceId: any; + targetId: any; + isSequenceFlow: boolean; + isDefault: any; + parent: any; + }; /** - * Look up another activity in the same context. - * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; + * Evaluate the flow's condition for the source activity message. Default flows are always taken. + * @param fromMessage Source activity message + * @param callback Callback with truthy result if flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): SequenceFlow_1 | undefined; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; + _publishEvent(action: any, content: any): void; private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; - export {}; -} + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } -declare module 'bpmn-elements/gateways' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; - export function EventBasedGateway(activityDef: any, context: any): Activity; - export function EventBasedGatewayBehaviour(activity: any, context: any): void; - export class EventBasedGatewayBehaviour { - constructor(activity: any, context: any); - id: any; - type: any; - activity: any; - broker: any; - context: any; - execute(executeMessage: any): any; - _onTargetCompleted(executeMessage: any, _: any, message: any, owner: any): void; - _complete(completedContent: any): void; - _stop(): void; - - private [K_TARGETS]; - - private [K_COMPLETED]; - } - export function ExclusiveGateway(activityDef: any, context: any): Activity; - export function ExclusiveGatewayBehaviour(activity: any): void; - export class ExclusiveGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute({ content }: { - content: any; - }): void; - } - export function InclusiveGateway(activityDef: any, context: any): Activity; - export function InclusiveGatewayBehaviour(activity: any): void; - export class InclusiveGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute({ content }: { - content: any; - }): void; - } - export function ParallelGateway(activityDef: any, context: any): Activity; - export class ParallelGateway { - constructor(activityDef: any, context: any); - id: string | undefined; - } - export function ParallelGatewayBehaviour(activity: any): void; - export class ParallelGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - activity: any; - broker: any; - inbound: Set; - isConverging: boolean; - execute(executeMessage: any): any; - setup(executeMessage: any): any; - peerMonitor: PeerMonitor | undefined; - _onExecuteMessage(routingKey: any, message: any): any; - _onPeerEnterMessage(_: any, message: any): void; - _complete(): any; - _stop(): void; - - private [K_EXECUTE_MESSAGE]; - - private [K_TARGETS]; - } - function PeerMonitor(activity: any, peers: any, targets: any): void; - class PeerMonitor { - constructor(activity: any, peers: any, targets: any); - activity: any; - id: any; - broker: any; - running: Map; - index: number; - discarded: number; - watching: Map; - peers: any; - targets: any; - touched: Set; - inbound: any[]; - get isRunning(): boolean; - execute(executeMessage: any): number; - monitor(peerActivity: any): void; - _onCompleteMessage(_routingKey: any, message: any): boolean; - stop(): void; - } + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + // --- Element abstract bases --------------------------------------------------- + + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - class Activity { - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger; - environment: Environment; - context: ContextInstance; - broker: import("smqp").default | undefined; - on: any; - once: any; - waitFor: any; - emitFatal: any; - /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; - /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; - /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message - */ - init(initContent?: Record): void; - /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; - /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; - /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; - /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; - /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; - /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; - /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; - /** - * Stop the activity. If not currently running, just cancels the inbound consumer. - */ - stop(): any; - /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. - */ - next(): any; - /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; - /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest - * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; - /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Look up another activity in the same context. - * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; - - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; - - private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; - const K_ACTIVATED: unique symbol; - const K_COMPLETED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_TARGETS: unique symbol; - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): Api; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; - } - - interface Api extends ElementBrokerMessage { - get id(): string; - get type(): string; - get name(): string; - get executionId(): string; - get environment(): Environment; - get broker(): ElementBroker; - get owner(): T; - cancel(message?: signalMessage, options?: any): void; - discard(): void; - fail(error: Error): void; - signal(message?: signalMessage, options?: any): void; - stop(): void; - resolveExpression(expression: string): any; - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - getPostponed(...args: any[]): any[]; - createMessage(content?: Record): any; - getExecuting(): Api[]; - } - - class Environment { - constructor(options?: EnvironmentOptions); - options: Record; - expressions: IExpressions; - extensions: Record; - scripts: IScripts; - timers: ITimers; - Logger: LoggerFactory; - get settings(): EnvironmentSettings; - get variables(): Record; - get output(): Record; - set services(arg: any); - get services(): any; - getState(): EnvironmentState; - recover(state?: EnvironmentState): Environment; - clone(overrideOptions?: EnvironmentOptions): Environment; - assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): Environment; - registerScript(activity: any): Script; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - getServiceByName(serviceName: string): CallableFunction; - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - addService(name: string, fn: CallableFunction): void; - } - class ContextInstance { - constructor(definitionContext: SerializableContext, environment?: Environment); - get id(): string; - get name(): string; - get type(): string; - /** Unique context instance id */ - get sid(): string; - get definitionContext(): SerializableContext; - get environment(): Environment; - /** Context owner, Process or SubProcess activity */ - get owner(): Process | Activity | undefined; - getActivityById(activityId: string): T; - getSequenceFlowById(sequenceFlowId: string): SequenceFlow; - getInboundSequenceFlows(activityId: string): SequenceFlow[]; - getOutboundSequenceFlows(activityId: string): SequenceFlow[]; - getInboundAssociations(activityId: string): Association[]; - getOutboundAssociations(activityId: string): Association[]; - getActivities(scopeId?: string): ElementBase[]; - getSequenceFlows(scopeId?: string): SequenceFlow[]; - getAssociations(scopeId?: string): Association[]; - clone(newEnvironment?: Environment): ContextInstance; - getProcessById(processId: string): Process; - getNewProcessById(processId: string): Process; - getProcesses(): Process[]; - getExecutableProcesses(): Process[]; - getMessageFlows(sourceId: string): MessageFlow[]; - getDataObjectById(referenceId: string): any; - getDataStoreById(referenceId: string): any; - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; - loadExtensions(activity: ElementBase): IExtension; - } - - class Process extends Element { - constructor(processDef: SerializableElement, context: ContextInstance); - get isExecutable(): boolean; - get counters(): completedCounters; - get lanes(): Lane[] | undefined; - get extensions(): IExtension; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string; - get execution(): ProcessExecution; - get status(): ProcessRunStatus | undefined; - get activityStatus(): ActivityStatus; - init(useAsExecutionId?: string): void; - run(runContent?: Record): void; - getState(): ProcessState; - recover(state?: ProcessState): Process; - shake(startId?: string): void; - signal(message: any): any; - cancelActivity(message: any): any; - sendMessage(message: any): void; - getActivityById(childId: string): T; - getActivities(): Activity[]; - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; - getSequenceFlows(): SequenceFlow[]; - getLaneById(laneId: string): Lane | undefined; - getPostponed(filterFn: filterPostponed): Api[]; - } - - interface ProcessExecution { - get isSubProcess(): boolean; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; - execute(executeMessage: ElementBrokerMessage): void; - getPostponed(filterFn: filterPostponed): Api[]; - getActivities(): Activity[]; - getActivityById(activityId: string): T; - getSequenceFlows(): SequenceFlow[]; - getApi(message?: ElementBrokerMessage): Api; - } - - class Lane extends ElementBase { - constructor(process: Process, laneDefinition: SerializableElement); - /** Process broker */ - get broker(): Broker; - get process(): Process; - } - - class SequenceFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isDefault(): boolean; - get isSequenceFlow(): boolean; - get counters(): { take: number; discard: number; looped: number }; - take(content?: any): boolean; - discard(content?: any): void; - shake(message: any): number; - getCondition(): ISequenceFlowCondition | null; - createMessage(override?: any): object; - /** - * Evaluate flow - * Executes condition if any, default flow is - * @param fromMessage Activity message - * @param callback Callback with evaluation result, if truthy flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - getState(): SequenceFlowState | undefined; - } - - class MessageFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get source(): MessageFlowReference; - get target(): MessageFlowReference; - get counters(): { messages: number }; - activate(): void; - deactivate(): void; - getState(): MessageFlowState | undefined; - } - - class Association extends Element { - constructor(associationDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isAssociation(): boolean; - get counters(): { take: number; discard: number }; - take(content?: any): boolean; - discard(content?: any): boolean; - getState(): AssociationState | undefined; - } - interface ElementBroker extends Broker { - get owner(): T; - } - - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken */ execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; } + // --- Activity behaviour & extensions ------------------------------------------ + interface IActivityBehaviour { id: string; type: string; @@ -5512,6 +4617,8 @@ declare module 'bpmn-elements/gateways' { resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; } + // --- Environment -------------------------------------------------------------- + interface EnvironmentSettings { /** true returns dummy service function for service task if not found */ enableDummyService?: boolean; @@ -5549,6 +4656,8 @@ declare module 'bpmn-elements/gateways' { expressions?: IExpressions; } + // --- Filter / callback shapes ------------------------------------------------- + type startActivityFilterOptions = { /** Event definition id, i.e. Message, Signal, Error, etc */ referenceId?: string; @@ -5556,40 +4665,7 @@ declare module 'bpmn-elements/gateways' { referenceType?: string; }; - type filterPostponed = (elementApi: any) => boolean; - - enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', - } - - /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ - enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', - /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc - */ - Wait = 'wait', - } + // --- State snapshots ---------------------------------------------------------- interface ElementState { id: string; @@ -5651,11 +4727,7 @@ declare module 'bpmn-elements/gateways' { execution?: ProcessExecutionState; } - interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; - } + // --- Logging ------------------------------------------------------------------ type LoggerFactory = (scope: string) => ILogger; @@ -5666,6 +4738,8 @@ declare module 'bpmn-elements/gateways' { [x: string]: any; } + // --- Timers ------------------------------------------------------------------- + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; type wrappedClearTimeout = (ref: any) => void; @@ -5698,6 +4772,8 @@ declare module 'bpmn-elements/gateways' { [x: string]: any; } + // --- Scripts ------------------------------------------------------------------ + interface IScripts { register(activity: any): Script | undefined; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; @@ -5707,231 +4783,428 @@ declare module 'bpmn-elements/gateways' { execute(executionContext: any, callback: CallableFunction): void; } - export {}; -} - -declare module 'bpmn-elements/tasks' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; - export function CallActivity(activityDef: any, context: any): Activity; - export function CallActivityBehaviour(activity: any): void; - export class CallActivityBehaviour { - constructor(activity: any); - id: any; - type: any; - calledElement: any; - loopCharacteristics: any; - activity: any; - broker: any; - environment: any; - execute(executeMessage: any): any; - _onDelegatedApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; - _onApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; - _stop(executionId: any): void; - } - export function ReceiveTask(activityDef: any, context: any): Activity; - export function ReceiveTaskBehaviour(activity: any): void; - export class ReceiveTaskBehaviour { - constructor(activity: any); - id: any; - type: any; - reference: any; - loopCharacteristics: any; - activity: any; - broker: any; - execute(executeMessage: any): any; - - private [K_REFERENCE_ELEMENT]; - } - export function ScriptTask(activityDef: any, context: any): Activity; - export function ScriptTaskBehaviour(activity: any): void; - export class ScriptTaskBehaviour { - constructor(activity: any); - id: any; - type: any; - scriptFormat: any; - loopCharacteristics: any; - activity: any; - environment: any; - execute(executeMessage: any): any; - } - export function ServiceTask(activityDef: any, context: any): Activity; - export function ServiceTaskBehaviour(activity: any): void; - export class ServiceTaskBehaviour { - constructor(activity: any); - id: any; - type: any; - loopCharacteristics: any; - activity: any; - environment: any; - broker: any; - execute(executeMessage: any): any; - service: any; - getService(message: any): any; - _onApiMessage(executeMessage: any, _: any, message: any): any; - } - export function SignalTask(activityDef: any, context: any): Activity; - export function SignalTaskBehaviour(activity: any): void; - export class SignalTaskBehaviour { - constructor(activity: any); - id: any; - type: any; - loopCharacteristics: any; - activity: any; - broker: any; - execute(executeMessage: any): any; - _onDelegatedApiMessage(executeMessage: any, routingKey: any, message: any): any; - _onApiMessage(executeMessage: any, routingKey: any, message: any): any; - _stop(executionId: any): void; - } - export function SubProcess(activityDef: any, context: any): Activity; - export function SubProcessBehaviour(activity: any, context: any): void; - export class SubProcessBehaviour { - constructor(activity: any, context: any); - id: any; - type: any; - loopCharacteristics: any; - activity: any; - context: any; - environment: any; - broker: any; - executionId: any; - execute(executeMessage: any): any; - getState(): any; - recover(state: any): ProcessExecution_1 | undefined; - getPostponed(): any[]; - _upsertExecution(executeMessage: any): any; - _addListeners(executionId: any): void; - _onExecutionCompleted(_: any, message: any): any; - _completeExecution(completeRoutingKey: any, content: any): void; - getApi(apiMessage: any): any; - _getExecutionById(executionId: any): any; - - private [K_EXECUTIONS]; - - private [K_ON_EXECUTION_COMPLETED]; - } - const K_EXECUTIONS: unique symbol; - const K_ON_EXECUTION_COMPLETED: unique symbol; - export function Task(activityDef: any, context: any): Activity; - export function TaskBehaviour(activity: any): void; - export class TaskBehaviour { - constructor(activity: any); - id: any; - type: any; - loopCharacteristics: any; - broker: any; - execute(executeMessage: any): any; - } - export function Transaction(activityDef: any, context: any): Activity; + /** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * */ - function Activity(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): void; - class Activity { + class Environment { /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; + constructor(options?: EnvironmentOptions); + options: {}; + expressions: IExpressions; + extensions: Record | undefined; + output: any; + scripts: IScripts | Scripts; + timers: ITimers | Timers; + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger; - environment: Environment; - context: ContextInstance; - broker: import("smqp").default | undefined; - on: any; - once: any; - waitFor: any; - emitFatal: any; + Logger: LoggerFactory | typeof DummyLogger; /** - * Subscribe to inbound flows and start consuming the inbound queue. + * Snapshot environment state for recover. */ - activate(): 0 | import("smqp").Consumer | undefined; + getState(): { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. + * */ + recover(state?: EnvironmentState): this; /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. + * */ - init(initContent?: Record): void; + clone(overrideOptions?: EnvironmentOptions): any; /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; + * Merge variables into the environment. Non-objects are ignored. + * */ + assignVariables(newVars: Record): void; /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; + * Merge settings into the environment. Non-objects are ignored. + * */ + assignSettings(newSettings: EnvironmentSettings): this; /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; + * Resolve a registered script by language and identifier. + * */ + getScript(...args: any[]): void | Script; /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; + * Register a script for an activity, delegating to the configured scripts engine. + * */ + registerScript(...args: any[]): void | Script; /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard + * Lookup a registered service by name. + * */ + getServiceByName(serviceName: string): CallableFunction; + /** + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param message Element message merged onto the resolution scope + * */ - discard(discardContent?: Record): any; + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers + * Register a service callable by name. + * */ + addService(name: string, fn: CallableFunction): void; + + private [K_SERVICES]; + + private [K_VARIABLES]; + } + function DummyLogger(): { + debug: () => void; + error: () => void; + warn: () => void; + }; + const K_SERVICES: unique symbol; + const K_VARIABLES: unique symbol; + /** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param sourceMessage Cloned to back the api + * @param environment Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing + */ + class Api { + /** + * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. + * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` + * @param sourceMessage Cloned to back the api + * @param environment Defaults to `broker.owner.environment` + * @throws {Error} when sourceMessage is missing */ - addInboundListeners(): number; + constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment); + id: any; + type: any; + name: any; + executionId: any; + environment: any; + content: any; + fields: any; + messageProperties: any; + broker: any; + owner: any; + messagePrefix: string; /** - * Cancel inbound trigger subscriptions added by addInboundListeners. + * Send a cancel api message. + * */ - removeInboundListeners(): void; + cancel(message?: signalMessage, options?: any): void; /** - * Stop the activity. If not currently running, just cancels the inbound consumer. + * Send a discard api message. */ - stop(): any; + discard(): void; /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. + * Send an error api message that fails the activity. + * */ + fail(error: Error): void; + /** + * Send a signal api message. + * */ - next(): any; + signal(message?: signalMessage, options?: any): void; /** - * Walk outbound flows to discover the activity graph from this point. + * Send a stop api message. */ - shake(): void; + stop(): void; /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * Resolve an expression with the api message as scope and the broker owner as context. * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + resolveExpression(expression: string): any; /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. + * Publish a custom api message to the broker. + * @param action Routing key suffix, e.g. `signal`, `cancel` + * @param content Merged into the message content * */ - getApi(message?: ElementBrokerMessage): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; /** - * Look up another activity in the same context. - * */ + * List currently postponed activities, falling back to a sub-process execution when applicable. + * + */ + getPostponed(...args: any[]): any; + /** + * Build a message body by merging the given content onto the source content. + * + */ + createMessage(content?: Record): any; + } + const K_ACTIVATED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXECUTION: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_STATUS: unique symbol; + const K_STOPPED: unique symbol; + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + class ContextInstance { + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); + id: string; + name: string; + type: string; + sid: string; + definitionContext: import("moddle-context-serializer").SerializableContext; + environment: Environment; + extensionsMapper: ExtensionsMapper; + refs: Map>; + get owner(): Activity | Process | undefined; + /** + * Get or create the activity instance for the given id. + * */ + getActivityById(activityId: string): any; + /** + * Return the cached activity instance, instantiating it the first time it is referenced. + * */ + upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + /** + * Get or create the sequence flow instance for the given id. + * */ + getSequenceFlowById(sequenceFlowId: string): any; + + getInboundSequenceFlows(activityId: string): any[]; + + getOutboundSequenceFlows(activityId: string): any[]; + + getInboundAssociations(activityId: string): any[]; + + getOutboundAssociations(activityId: string): any[]; + /** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getActivities(scopeId?: string): any[]; + /** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getSequenceFlows(scopeId?: string): any[]; + /** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * */ + upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * @param scopeId Process or sub-process id + */ + getAssociations(scopeId?: string): any[]; + + upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * + */ + clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; + /** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * */ + getProcessById(processId: string): any; + /** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * */ + getNewProcessById(processId: string): any; + /** + * Get every process in the definition. + */ + getProcesses(): any[]; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any[]; + /** + * Get message flows that originate from the given process id. + * @param sourceId Source process id + */ + getMessageFlows(sourceId: string): any[]; + /** + * Get or create a data object instance for the given reference id. + * */ + getDataObjectById(referenceId: string): any; + /** + * Get or create a data store instance for the given reference id. + * */ + getDataStoreById(referenceId: string): any; + /** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param scopeId Process or sub-process id + */ + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + /** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * */ + loadExtensions(activity: ElementBase): Extensions | undefined; + /** + * Resolve the parent process or sub-process activity that owns the given activity. + * */ + getActivityParentById(activityId: string): any; + + private [K_OWNER]; + } + class ExtensionsMapper { + constructor(context: any); + context: any; + get(activity: any): Extensions; + + _getExtensions(): any[]; + } + class Extensions { + constructor(activity: any, context: any, extensions: any); + extensions: any[]; + get count(): number; + activate(message: any): void; + deactivate(message: any): void; + + private [K_ACTIVATED]; + } + const K_OWNER: unique symbol; + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + environment: Environment; + context: ContextInstance; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ getActivityById(elementId: string): any; _runDiscard(discardContent: any): void; @@ -5980,7 +5253,7 @@ declare module 'bpmn-elements/tasks' { _createMessage(override: any): any; - _getOutboundSequenceFlowById(flowId: any): SequenceFlow | undefined; + _getOutboundSequenceFlowById(flowId: any): any; _deactivateRunConsumers(): void; @@ -6016,595 +5289,716 @@ declare module 'bpmn-elements/tasks' { const K_EXEC: unique symbol; const K_EVENT_DEFINITIONS: unique symbol; const K_CONSUMING_RUN_Q: unique symbol; - const K_ACTIVATED: unique symbol; - const K_COMPLETED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_REFERENCE_ELEMENT: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STATUS: unique symbol; - const K_STOPPED: unique symbol; /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. * */ - function ProcessExecution_1(parentActivity: Process | Activity, context: ContextInstance): void; - class ProcessExecution_1 { + class Process { /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. * */ - constructor(parentActivity: Process | Activity, context: ContextInstance); + constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); id: string | undefined; type: string; - isSubProcess: any; - isTransaction: any; - broker: import("smqp").default | ElementBroker | undefined; + name: any; + parent: any; + behaviour: Record; + isExecutable: any; environment: Environment; context: ContextInstance; - _exchangeName: string; - executionId: string | undefined; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; /** - * Activate children and start the process execution. Resumes if the message is redelivered. - * @throws {Error} when message or executionId is missing + * Allocate an executionId and emit init event without starting the run. + * @param useAsExecutionId Override for the generated execution id */ - execute(executeMessage: ElementBrokerMessage): any; + init(useAsExecutionId?: string): void; /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param runContent Optional content merged into the run message + * @throws {Error} when the process is already running */ - resume(): any; + run(runContent?: Record): void; /** - * Snapshot execution state including children, flows, message flows, and associations. + * Resume after recover by republishing the last run message. + * @throws {Error} when called on a running process + */ + resume(): this; + /** + * Snapshot process state for recover. */ getState(): { - associations?: (AssociationState | undefined)[] | undefined; - messageFlows?: (MessageFlowState | undefined)[] | undefined; - flows?: any[] | undefined; - executionId: string | undefined; - stopped: boolean; - completed: boolean; + id: string | undefined; + type: string; + executionId: any; + environment: { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; status: any; - children: never[]; + stopped: any; + counters: any; + broker: { + exchanges: { + bindings?: { + id: string; + options: { + priority: number; + }; + queueName: string; + pattern: string; + }[] | undefined; + deliveryQueue?: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + } | undefined; + name: string; + type: import("smqp").exchangeType; + options: { + [x: string]: any; + durable?: boolean; + autoDelete?: boolean; + }; + }[] | undefined; + queues: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + }[] | undefined; + } | undefined; + execution: any; }; /** - * Restore execution state captured by getState. - * */ - recover(state?: ProcessExecutionState): this; + * Restore process state captured by getState. + * @throws {Error} when called on a running process + */ + recover(state?: ProcessState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. * */ - shake(fromId?: string): any; + shake(startId?: string): any; /** - * Stop the running process execution via the api. + * Stop the process if running. */ stop(): void; /** - * List currently postponed children as Api wrappers. + * Resolve a Process Api wrapper, preferring the running execution if any. * */ - getPostponed(filterFn?: filterPostponed): any[]; - /** - * Queue a discard message that propagates to all running children. - */ - discard(): number | undefined; - /** - * Queue a cancel message that propagates to all running children. - */ - cancel(): number | undefined; - /** - * Get child activities in the process scope. - */ - getActivities(): ElementBase[]; - - getActivityById(activityId: string): ElementBase | undefined; - /** - * Get sequence flows in the process scope. - */ - getSequenceFlows(): SequenceFlow[]; + getApi(message?: ElementBrokerMessage): any; /** - * Get associations in the process scope. + * Send a delegated signal to the running process. + * */ - getAssociations(): Association[]; + signal(message?: signalMessage): any; /** - * Resolve a process or child Api for the given message. + * Cancel a running activity inside the process by delegated api message. * */ - getApi(message?: ElementBrokerMessage): any; - - _start(): any; - - _activate(): void; - - _deactivate(): void; - - _shakeElements(fromId: any): { - settings: { - skipDiscard: boolean | undefined; - }; - sequences: Map; - }; - - _onDelegateEvent(message: any): boolean; - - _onMessageFlowEvent(routingKey: any, message: any): void; - - _onActivityEvent(routingKey: any, message: any): number | void; - - _onChildMessage(routingKey: any, message: any): any; - - _stateChangeMessage(message: any, postponeMessage: any): void; - - _popPostponed(byContent: any): any; - - _onChildCompleted(message: any): any; - - _stopExecution(message: any): any; + cancelActivity(message?: signalMessage): any; - _onDiscard(): any; + _activateRunConsumers(): void; - _onCancel(): void; + _deactivateRunConsumers(): void; - _onApiMessage(routingKey: any, message: any): any; + _onRunMessage(routingKey: any, message: any): any; - _delegateApiMessage(routingKey: any, message: any, continueOnConsumed: any): boolean; + _onResumeMessage(message: any): any; - _complete(completionType: any, content: any): any; + _onExecutionMessage(routingKey: any, message: any): void; - _terminate(message: any): void; + _publishEvent(state: any, content: any): void; + /** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. + * */ + sendMessage(message: ElementBrokerMessage): void; - _getFlowById(flowId: any): SequenceFlow | undefined; + getActivityById(childId: string): any; + /** + * Get every activity in the process scope. + */ + getActivities(): any; + /** + * Get start activities, optionally filtered by referenced event definition. + * + */ + getStartActivities(filterOptions?: startActivityFilterOptions): any[]; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any; - _getAssociationById(associationId: any): Association | undefined; + getLaneById(laneId: string): any; + /** + * List currently postponed activities as Api wrappers. + * + */ + getPostponed(...args: any[]): any; - _getMessageFlowById(flowId: any): MessageFlow | undefined; + _onApiMessage(routingKey: any, message: any): void; - _getChildById(childId: any): ElementBase | SequenceFlow | undefined; + _onStop(): void; - _getChildApi(message: any): any; + _createMessage(override: any): any; - _onShakeMessage(message: any): void; + _debug(msg: any): void; - _debug(logMessage: any): void; + private [K_COUNTERS]; - private [K_PARENT]; + private [K_CONSUMING]; - private [K_ELEMENTS]; + private [K_EXECUTION]; - private [K_COMPLETED]; + private [K_STATUS]; private [K_STOPPED]; - private [K_ACTIVATED]; + private [K_MESSAGE_HANDLERS]; - private [K_STATUS]; + private [K_LANES]; - private [K_TRACKER]; + private [K_EXTENSIONS]; - private [K_MESSAGE_HANDLERS]; + private [K_STATE_MESSAGE]; private [K_EXECUTE_MESSAGE]; + } + const K_LANES: unique symbol; + class Timers { + constructor(options: any); + count: number; + options: any; + setTimeout: any; + clearTimeout: any; + get executing(): any[]; + register(owner: any): RegisteredTimers; + _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; + _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; - private [K_ACTIVITY_Q]; + private [K_EXECUTING]; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + + private [K_TIMER_API]; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + const K_EXECUTING: unique symbol; + const K_TIMER_API: unique symbol; + class Scripts { + getScript(): void; + register(): void; } - const K_PARENT: unique symbol; - const K_ELEMENTS: unique symbol; - const K_TRACKER: unique symbol; - const K_ACTIVITY_Q: unique symbol; - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): Api; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; - } - - interface Api extends ElementBrokerMessage { - get id(): string; - get type(): string; - get name(): string; - get executionId(): string; - get environment(): Environment; - get broker(): ElementBroker; - get owner(): T; - cancel(message?: signalMessage, options?: any): void; - discard(): void; - fail(error: Error): void; - signal(message?: signalMessage, options?: any): void; - stop(): void; - resolveExpression(expression: string): any; - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - getPostponed(...args: any[]): any[]; - createMessage(content?: Record): any; - getExecuting(): Api[]; - } - - class Environment { - constructor(options?: EnvironmentOptions); - options: Record; - expressions: IExpressions; - extensions: Record; - scripts: IScripts; - timers: ITimers; - Logger: LoggerFactory; - get settings(): EnvironmentSettings; - get variables(): Record; - get output(): Record; - set services(arg: any); - get services(): any; - getState(): EnvironmentState; - recover(state?: EnvironmentState): Environment; - clone(overrideOptions?: EnvironmentOptions): Environment; - assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): Environment; - registerScript(activity: any): Script; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - getServiceByName(serviceName: string): CallableFunction; - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - addService(name: string, fn: CallableFunction): void; - } - class ContextInstance { - constructor(definitionContext: SerializableContext, environment?: Environment); - get id(): string; - get name(): string; - get type(): string; - /** Unique context instance id */ - get sid(): string; - get definitionContext(): SerializableContext; - get environment(): Environment; - /** Context owner, Process or SubProcess activity */ - get owner(): Process | Activity | undefined; - getActivityById(activityId: string): T; - getSequenceFlowById(sequenceFlowId: string): SequenceFlow; - getInboundSequenceFlows(activityId: string): SequenceFlow[]; - getOutboundSequenceFlows(activityId: string): SequenceFlow[]; - getInboundAssociations(activityId: string): Association[]; - getOutboundAssociations(activityId: string): Association[]; - getActivities(scopeId?: string): ElementBase[]; - getSequenceFlows(scopeId?: string): SequenceFlow[]; - getAssociations(scopeId?: string): Association[]; - clone(newEnvironment?: Environment): ContextInstance; - getProcessById(processId: string): Process; - getNewProcessById(processId: string): Process; - getProcesses(): Process[]; - getExecutableProcesses(): Process[]; - getMessageFlows(sourceId: string): MessageFlow[]; - getDataObjectById(referenceId: string): any; - getDataStoreById(referenceId: string): any; - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; - loadExtensions(activity: ElementBase): IExtension; - } - - class Process extends Element { - constructor(processDef: SerializableElement, context: ContextInstance); - get isExecutable(): boolean; - get counters(): completedCounters; - get lanes(): Lane[] | undefined; - get extensions(): IExtension; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string; - get execution(): ProcessExecution; - get status(): ProcessRunStatus | undefined; - get activityStatus(): ActivityStatus; - init(useAsExecutionId?: string): void; - run(runContent?: Record): void; - getState(): ProcessState; - recover(state?: ProcessState): Process; - shake(startId?: string): void; - signal(message: any): any; - cancelActivity(message: any): any; - sendMessage(message: any): void; - getActivityById(childId: string): T; - getActivities(): Activity[]; - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; - getSequenceFlows(): SequenceFlow[]; - getLaneById(laneId: string): Lane | undefined; - getPostponed(filterFn: filterPostponed): Api[]; - } - - interface ProcessExecution { - get isSubProcess(): boolean; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; - execute(executeMessage: ElementBrokerMessage): void; - getPostponed(filterFn: filterPostponed): Api[]; - getActivities(): Activity[]; - getActivityById(activityId: string): T; - getSequenceFlows(): SequenceFlow[]; - getApi(message?: ElementBrokerMessage): Api; - } - - class Lane extends ElementBase { - constructor(process: Process, laneDefinition: SerializableElement); - /** Process broker */ - get broker(): Broker; - get process(): Process; - } - - class SequenceFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isDefault(): boolean; - get isSequenceFlow(): boolean; - get counters(): { take: number; discard: number; looped: number }; - take(content?: any): boolean; - discard(content?: any): void; - shake(message: any): number; - getCondition(): ISequenceFlowCondition | null; - createMessage(override?: any): object; - /** - * Evaluate flow - * Executes condition if any, default flow is - * @param fromMessage Activity message - * @param callback Callback with evaluation result, if truthy flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - getState(): SequenceFlowState | undefined; - } - - class MessageFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get source(): MessageFlowReference; - get target(): MessageFlowReference; - get counters(): { messages: number }; - activate(): void; - deactivate(): void; - getState(): MessageFlowState | undefined; - } - - class Association extends Element { - constructor(associationDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isAssociation(): boolean; - get counters(): { take: number; discard: number }; - take(content?: any): boolean; - discard(content?: any): boolean; - getState(): AssociationState | undefined; - } - interface ElementBroker extends Broker { - get owner(): T; - } - - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - } - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - type filterPostponed = (elementApi: any) => boolean; - - enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', - } + export {}; +} - /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ - enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', +declare module 'bpmn-elements/gateways' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; + export function EventBasedGateway(activityDef: any, context: any): Activity; + export class EventBasedGatewayBehaviour { + constructor(activity: any, context: any); + id: any; + type: any; + activity: any; + broker: any; + context: any; + execute(executeMessage: any): any; + _onTargetCompleted(executeMessage: any, _: any, message: any, owner: any): void; + _complete(completedContent: any): void; + _stop(): void; + + private [K_TARGETS]; + + private [K_COMPLETED]; + } + export function ExclusiveGateway(activityDef: any, context: any): Activity; + export class ExclusiveGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute({ content }: { + content: any; + }): void; + } + export function InclusiveGateway(activityDef: any, context: any): Activity; + export class InclusiveGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute({ content }: { + content: any; + }): void; + } + export class ParallelGateway { + constructor(activityDef: any, context: any); + id: string | undefined; + } + export class ParallelGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + activity: any; + broker: any; + inbound: Set; + isConverging: boolean; + execute(executeMessage: any): any; + setup(executeMessage: any): any; + peerMonitor: PeerMonitor | undefined; + _onExecuteMessage(routingKey: any, message: any): any; + _onPeerEnterMessage(_: any, message: any): void; + _complete(): any; + _stop(): void; + + private [K_EXECUTE_MESSAGE]; + + private [K_TARGETS]; + } + class PeerMonitor { + constructor(activity: any, peers: any, targets: any); + activity: any; + id: any; + broker: any; + running: Map; + index: number; + discarded: number; + watching: Map; + peers: any; + targets: any; + touched: Set; + inbound: any[]; + get isRunning(): boolean; + execute(executeMessage: any): number; + monitor(peerActivity: any): void; + _onCompleteMessage(_routingKey: any, message: any): boolean; + stop(): void; + } /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory */ - Wait = 'wait', - } - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + environment: Environment; + context: ContextInstance; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): any; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + const K_ACTIVATED: unique symbol; + const K_COMPLETED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXECUTION: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_STATUS: unique symbol; + const K_STOPPED: unique symbol; + const K_TARGETS: unique symbol; + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; } - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; } - interface MessageFlowReference { - /** activity id */ + interface ElementParent { get id(): string; - get processId(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; } - type LoggerFactory = (scope: string) => ILogger; + // --- Element abstract bases --------------------------------------------------- + + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + // --- Activity behaviour & extensions ------------------------------------------ + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + // --- Environment -------------------------------------------------------------- + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + // --- Filter / callback shapes ------------------------------------------------- + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + // --- State snapshots ---------------------------------------------------------- + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + // --- Logging ------------------------------------------------------------------ + + type LoggerFactory = (scope: string) => ILogger; interface ILogger { debug(...args: any[]): void; @@ -6613,6 +6007,8 @@ declare module 'bpmn-elements/tasks' { [x: string]: any; } + // --- Timers ------------------------------------------------------------------- + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; type wrappedClearTimeout = (ref: any) => void; @@ -6645,6 +6041,8 @@ declare module 'bpmn-elements/tasks' { [x: string]: any; } + // --- Scripts ------------------------------------------------------------------ + interface IScripts { register(activity: any): Script | undefined; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; @@ -6654,6 +6052,1656 @@ declare module 'bpmn-elements/tasks' { execute(executionContext: any, callback: CallableFunction): void; } + /** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + class Environment { + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + constructor(options?: EnvironmentOptions); + options: {}; + expressions: IExpressions; + extensions: Record | undefined; + output: any; + scripts: IScripts | Scripts; + timers: ITimers | Timers; + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + Logger: LoggerFactory | typeof DummyLogger; + /** + * Snapshot environment state for recover. + */ + getState(): { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + /** + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. + * */ + recover(state?: EnvironmentState): this; + /** + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. + * + */ + clone(overrideOptions?: EnvironmentOptions): any; + /** + * Merge variables into the environment. Non-objects are ignored. + * */ + assignVariables(newVars: Record): void; + /** + * Merge settings into the environment. Non-objects are ignored. + * */ + assignSettings(newSettings: EnvironmentSettings): this; + /** + * Resolve a registered script by language and identifier. + * */ + getScript(...args: any[]): void | Script; + /** + * Register a script for an activity, delegating to the configured scripts engine. + * */ + registerScript(...args: any[]): void | Script; + /** + * Lookup a registered service by name. + * */ + getServiceByName(serviceName: string): CallableFunction; + /** + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param message Element message merged onto the resolution scope + * + */ + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + /** + * Register a service callable by name. + * */ + addService(name: string, fn: CallableFunction): void; + + private [K_SERVICES]; + + private [K_VARIABLES]; + } + function DummyLogger(): { + debug: () => void; + error: () => void; + warn: () => void; + }; + const K_SERVICES: unique symbol; + const K_VARIABLES: unique symbol; + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + class ContextInstance { + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); + id: string; + name: string; + type: string; + sid: string; + definitionContext: import("moddle-context-serializer").SerializableContext; + environment: Environment; + extensionsMapper: ExtensionsMapper; + refs: Map>; + get owner(): Activity | Process | undefined; + /** + * Get or create the activity instance for the given id. + * */ + getActivityById(activityId: string): any; + /** + * Return the cached activity instance, instantiating it the first time it is referenced. + * */ + upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + /** + * Get or create the sequence flow instance for the given id. + * */ + getSequenceFlowById(sequenceFlowId: string): any; + + getInboundSequenceFlows(activityId: string): any[]; + + getOutboundSequenceFlows(activityId: string): any[]; + + getInboundAssociations(activityId: string): any[]; + + getOutboundAssociations(activityId: string): any[]; + /** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getActivities(scopeId?: string): any[]; + /** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getSequenceFlows(scopeId?: string): any[]; + /** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * */ + upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * @param scopeId Process or sub-process id + */ + getAssociations(scopeId?: string): any[]; + + upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * + */ + clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; + /** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * */ + getProcessById(processId: string): any; + /** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * */ + getNewProcessById(processId: string): any; + /** + * Get every process in the definition. + */ + getProcesses(): any[]; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any[]; + /** + * Get message flows that originate from the given process id. + * @param sourceId Source process id + */ + getMessageFlows(sourceId: string): any[]; + /** + * Get or create a data object instance for the given reference id. + * */ + getDataObjectById(referenceId: string): any; + /** + * Get or create a data store instance for the given reference id. + * */ + getDataStoreById(referenceId: string): any; + /** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param scopeId Process or sub-process id + */ + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + /** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * */ + loadExtensions(activity: ElementBase): Extensions | undefined; + /** + * Resolve the parent process or sub-process activity that owns the given activity. + * */ + getActivityParentById(activityId: string): any; + + private [K_OWNER]; + } + class ExtensionsMapper { + constructor(context: any); + context: any; + get(activity: any): Extensions; + + _getExtensions(): any[]; + } + class Extensions { + constructor(activity: any, context: any, extensions: any); + extensions: any[]; + get count(): number; + activate(message: any): void; + deactivate(message: any): void; + + private [K_ACTIVATED]; + } + const K_OWNER: unique symbol; + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + class Process { + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + isExecutable: any; + environment: Environment; + context: ContextInstance; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + /** + * Allocate an executionId and emit init event without starting the run. + * @param useAsExecutionId Override for the generated execution id + */ + init(useAsExecutionId?: string): void; + /** + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param runContent Optional content merged into the run message + * @throws {Error} when the process is already running + */ + run(runContent?: Record): void; + /** + * Resume after recover by republishing the last run message. + * @throws {Error} when called on a running process + */ + resume(): this; + /** + * Snapshot process state for recover. + */ + getState(): { + id: string | undefined; + type: string; + executionId: any; + environment: { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + status: any; + stopped: any; + counters: any; + broker: { + exchanges: { + bindings?: { + id: string; + options: { + priority: number; + }; + queueName: string; + pattern: string; + }[] | undefined; + deliveryQueue?: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + } | undefined; + name: string; + type: import("smqp").exchangeType; + options: { + [x: string]: any; + durable?: boolean; + autoDelete?: boolean; + }; + }[] | undefined; + queues: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + }[] | undefined; + } | undefined; + execution: any; + }; + /** + * Restore process state captured by getState. + * @throws {Error} when called on a running process + */ + recover(state?: ProcessState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. + * + */ + shake(startId?: string): any; + /** + * Stop the process if running. + */ + stop(): void; + /** + * Resolve a Process Api wrapper, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Send a delegated signal to the running process. + * + */ + signal(message?: signalMessage): any; + /** + * Cancel a running activity inside the process by delegated api message. + * + */ + cancelActivity(message?: signalMessage): any; + + _activateRunConsumers(): void; + + _deactivateRunConsumers(): void; + + _onRunMessage(routingKey: any, message: any): any; + + _onResumeMessage(message: any): any; + + _onExecutionMessage(routingKey: any, message: any): void; + + _publishEvent(state: any, content: any): void; + /** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. + * */ + sendMessage(message: ElementBrokerMessage): void; + + getActivityById(childId: string): any; + /** + * Get every activity in the process scope. + */ + getActivities(): any; + /** + * Get start activities, optionally filtered by referenced event definition. + * + */ + getStartActivities(filterOptions?: startActivityFilterOptions): any[]; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any; + + getLaneById(laneId: string): any; + /** + * List currently postponed activities as Api wrappers. + * + */ + getPostponed(...args: any[]): any; + + _onApiMessage(routingKey: any, message: any): void; + + _onStop(): void; + + _createMessage(override: any): any; + + _debug(msg: any): void; + + private [K_COUNTERS]; + + private [K_CONSUMING]; + + private [K_EXECUTION]; + + private [K_STATUS]; + + private [K_STOPPED]; + + private [K_MESSAGE_HANDLERS]; + + private [K_LANES]; + + private [K_EXTENSIONS]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_LANES: unique symbol; + class Timers { + constructor(options: any); + count: number; + options: any; + setTimeout: any; + clearTimeout: any; + get executing(): any[]; + register(owner: any): RegisteredTimers; + _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; + _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; + + private [K_EXECUTING]; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + + private [K_TIMER_API]; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + const K_EXECUTING: unique symbol; + const K_TIMER_API: unique symbol; + class Scripts { + getScript(): void; + register(): void; + } + + export {}; +} + +declare module 'bpmn-elements/tasks' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; + export function CallActivity(activityDef: any, context: any): Activity; + export class CallActivityBehaviour { + constructor(activity: any); + id: any; + type: any; + calledElement: any; + loopCharacteristics: any; + activity: any; + broker: any; + environment: any; + execute(executeMessage: any): any; + _onDelegatedApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; + _onApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; + _stop(executionId: any): void; + } + export function ReceiveTask(activityDef: any, context: any): Activity; + export class ReceiveTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + reference: any; + loopCharacteristics: any; + activity: any; + broker: any; + execute(executeMessage: any): any; + + private [K_REFERENCE_ELEMENT]; + } + export function ScriptTask(activityDef: any, context: any): Activity; + export class ScriptTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + scriptFormat: any; + loopCharacteristics: any; + activity: any; + environment: any; + execute(executeMessage: any): any; + } + export function ServiceTask(activityDef: any, context: any): Activity; + export class ServiceTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + environment: any; + broker: any; + execute(executeMessage: any): any; + service: any; + getService(message: any): any; + _onApiMessage(executeMessage: any, _: any, message: any): any; + } + export function SignalTask(activityDef: any, context: any): Activity; + export class SignalTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + broker: any; + execute(executeMessage: any): any; + _onDelegatedApiMessage(executeMessage: any, routingKey: any, message: any): any; + _onApiMessage(executeMessage: any, routingKey: any, message: any): any; + _stop(executionId: any): void; + } + export function SubProcess(activityDef: any, context: any): Activity; + export class SubProcessBehaviour { + constructor(activity: any, context: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + context: any; + environment: any; + broker: any; + executionId: any; + execute(executeMessage: any): any; + getState(): any; + recover(state: any): ProcessExecution | undefined; + getPostponed(): any[]; + _upsertExecution(executeMessage: any): any; + _addListeners(executionId: any): void; + _onExecutionCompleted(_: any, message: any): any; + _completeExecution(completeRoutingKey: any, content: any): void; + getApi(apiMessage: any): any; + _getExecutionById(executionId: any): any; + + private [K_EXECUTIONS]; + + private [K_ON_EXECUTION_COMPLETED]; + } + const K_EXECUTIONS: unique symbol; + const K_ON_EXECUTION_COMPLETED: unique symbol; + export function Task(activityDef: any, context: any): Activity; + export class TaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + broker: any; + execute(executeMessage: any): any; + } + export function Transaction(activityDef: any, context: any): Activity; + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; + parent: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + environment: Environment; + context: ContextInstance; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + emitFatal: any; + /** + * Subscribe to inbound flows and start consuming the inbound queue. + */ + activate(): 0 | import("smqp").Consumer | undefined; + /** + * Cancel inbound subscriptions and any pending run/format consumers. + */ + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + */ + getState(): any; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + status: any; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): 0 | import("smqp").Consumer | undefined; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): number; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): any; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): any; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): any; + + _runDiscard(discardContent: any): void; + + _discardRun(): void; + + _onShakeMessage(sourceMessage: any): any; + + _shakeOutbound(sourceMessage: any): any; + + _consumeInbound(): import("smqp").Consumer | undefined; + + _onInbound(routingKey: any, message: any): void; + + _onInboundEvent(routingKey: any, message: any): any; + + _consumeRunQ(): void; + + _pauseRunQ(): void; + + _onRunMessage(routingKey: any, message: any, messageProperties: any): any; + + _continueRunMessage(routingKey: any, message: any): any; + + _onExecutionMessage(routingKey: any, message: any): any; + + _ackRunExecuteMessage(): void; + + _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; + + _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; + + _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; + + _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; + + _onResumeMessage(message: any): any; + + _publishEvent(state: any, content: any, properties: any): void; + + _onStop(message: any): void; + + _consumeApi(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _createMessage(override: any): any; + + _getOutboundSequenceFlowById(flowId: any): any; + + _deactivateRunConsumers(): void; + + private [K_ACTIVITY_DEF]; + + private [K_COUNTERS]; + + private [K_FLOWS]; + + private [K_FLAGS]; + + private [K_EXEC]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EVENT_DEFINITIONS]; + + private [K_EXTENSIONS]; + + private [K_CONSUMING]; + + private [K_CONSUMING_RUN_Q]; + + private [K_ACTIVATED]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_ACTIVITY_DEF: unique symbol; + const K_FLOWS: unique symbol; + const K_FLAGS: unique symbol; + const K_EXEC: unique symbol; + const K_EVENT_DEFINITIONS: unique symbol; + const K_CONSUMING_RUN_Q: unique symbol; + const K_ACTIVATED: unique symbol; + const K_COMPLETED: unique symbol; + const K_CONSUMING: unique symbol; + const K_COUNTERS: unique symbol; + const K_EXECUTE_MESSAGE: unique symbol; + const K_EXECUTION: unique symbol; + const K_EXTENSIONS: unique symbol; + const K_MESSAGE_HANDLERS: unique symbol; + const K_REFERENCE_ELEMENT: unique symbol; + const K_STATE_MESSAGE: unique symbol; + const K_STATUS: unique symbol; + const K_STOPPED: unique symbol; + /** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + class ProcessExecution { + /** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + constructor(parentActivity: Process | Activity, context: ContextInstance); + id: string | undefined; + type: string; + isSubProcess: any; + isTransaction: any; + broker: import("smqp").Broker; + environment: Environment; + context: ContextInstance; + _exchangeName: string; + executionId: string | undefined; + /** + * Activate children and start the process execution. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing + */ + execute(executeMessage: ElementBrokerMessage): any; + /** + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. + */ + resume(): any; + /** + * Snapshot execution state including children, flows, message flows, and associations. + */ + getState(): { + associations?: any[] | undefined; + messageFlows?: any[] | undefined; + flows?: any; + executionId: string | undefined; + stopped: boolean; + completed: boolean; + status: any; + children: any; + }; + /** + * Restore execution state captured by getState. + * */ + recover(state?: ProcessExecutionState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. + * + */ + shake(fromId?: string): any; + /** + * Stop the running process execution via the api. + */ + stop(): void; + /** + * List currently postponed children as Api wrappers. + * + */ + getPostponed(filterFn?: filterPostponed): any[]; + /** + * Queue a discard message that propagates to all running children. + */ + discard(): number | undefined; + /** + * Queue a cancel message that propagates to all running children. + */ + cancel(): number | undefined; + /** + * Get child activities in the process scope. + */ + getActivities(): any[]; + + getActivityById(activityId: string): any; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any[]; + /** + * Get associations in the process scope. + */ + getAssociations(): any[]; + /** + * Resolve a process or child Api for the given message. + * + */ + getApi(message?: ElementBrokerMessage): any; + + _start(): any; + + _activate(): void; + + _deactivate(): void; + + _shakeElements(fromId: any): { + settings: { + skipDiscard: boolean; + }; + sequences: Map; + }; + + _onDelegateEvent(message: any): boolean; + + _onMessageFlowEvent(routingKey: any, message: any): void; + + _onActivityEvent(routingKey: any, message: any): number | void; + + _onChildMessage(routingKey: any, message: any): any; + + _stateChangeMessage(message: any, postponeMessage: any): void; + + _popPostponed(byContent: any): any; + + _onChildCompleted(message: any): any; + + _stopExecution(message: any): any; + + _onDiscard(): any; + + _onCancel(): void; + + _onApiMessage(routingKey: any, message: any): any; + + _delegateApiMessage(routingKey: any, message: any, continueOnConsumed: any): boolean; + + _complete(completionType: any, content: any): any; + + _terminate(message: any): void; + + _getFlowById(flowId: any): any; + + _getAssociationById(associationId: any): any; + + _getMessageFlowById(flowId: any): any; + + _getChildById(childId: any): any; + + _getChildApi(message: any): any; + + _onShakeMessage(message: any): void; + + _debug(logMessage: any): void; + + private [K_PARENT]; + + private [K_ELEMENTS]; + + private [K_COMPLETED]; + + private [K_STOPPED]; + + private [K_ACTIVATED]; + + private [K_STATUS]; + + private [K_TRACKER]; + + private [K_MESSAGE_HANDLERS]; + + private [K_EXECUTE_MESSAGE]; + + private [K_ACTIVITY_Q]; + } + const K_PARENT: unique symbol; + const K_ELEMENTS: unique symbol; + const K_TRACKER: unique symbol; + const K_ACTIVITY_Q: unique symbol; + type signalMessage = { + /** + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc + */ + id?: string; + /** + * Optional execution id + * e.g. excutionId of a parallel multi instance user task + */ + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + // --- Element abstract bases --------------------------------------------------- + + class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + get context(): ContextInstance; + get logger(): ILogger; + } + + // --- Activity behaviour & extensions ------------------------------------------ + + interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + type Extension = (activity: any, context: any) => IExtension; + interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + // --- Environment -------------------------------------------------------------- + + interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + // --- Filter / callback shapes ------------------------------------------------- + + type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + type filterPostponed = (elementApi: any) => boolean; + + // --- State snapshots ---------------------------------------------------------- + + interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + type completedCounters = { completed: number; discarded: number }; + + interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + // --- Logging ------------------------------------------------------------------ + + type LoggerFactory = (scope: string) => ILogger; + + interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + // --- Timers ------------------------------------------------------------------- + + type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + type wrappedClearTimeout = (ref: any) => void; + + interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + // --- Scripts ------------------------------------------------------------------ + + interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + + /** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + class Environment { + /** + * Holds global execution config: variables, injected services, timers, scripts engine, + * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * + */ + constructor(options?: EnvironmentOptions); + options: {}; + expressions: IExpressions; + extensions: Record | undefined; + output: any; + scripts: IScripts | Scripts; + timers: ITimers | Timers; + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + Logger: LoggerFactory | typeof DummyLogger; + /** + * Snapshot environment state for recover. + */ + getState(): { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + /** + * Restore environment state captured by getState. Merges into the existing settings, + * variables, and output rather than replacing them. + * */ + recover(state?: EnvironmentState): this; + /** + * Clone the environment, optionally overriding options. Services are merged when + * `overrideOptions.services` is supplied. + * + */ + clone(overrideOptions?: EnvironmentOptions): any; + /** + * Merge variables into the environment. Non-objects are ignored. + * */ + assignVariables(newVars: Record): void; + /** + * Merge settings into the environment. Non-objects are ignored. + * */ + assignSettings(newSettings: EnvironmentSettings): this; + /** + * Resolve a registered script by language and identifier. + * */ + getScript(...args: any[]): void | Script; + /** + * Register a script for an activity, delegating to the configured scripts engine. + * */ + registerScript(...args: any[]): void | Script; + /** + * Lookup a registered service by name. + * */ + getServiceByName(serviceName: string): CallableFunction; + /** + * Resolve an expression with the environment as scope, optionally extended by an element message. + * @param message Element message merged onto the resolution scope + * + */ + resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + /** + * Register a service callable by name. + * */ + addService(name: string, fn: CallableFunction): void; + + private [K_SERVICES]; + + private [K_VARIABLES]; + } + function DummyLogger(): { + debug: () => void; + error: () => void; + warn: () => void; + }; + const K_SERVICES: unique symbol; + const K_VARIABLES: unique symbol; + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + class ContextInstance { + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); + id: string; + name: string; + type: string; + sid: string; + definitionContext: import("moddle-context-serializer").SerializableContext; + environment: Environment; + extensionsMapper: ExtensionsMapper; + refs: Map>; + get owner(): Activity | Process | undefined; + /** + * Get or create the activity instance for the given id. + * */ + getActivityById(activityId: string): any; + /** + * Return the cached activity instance, instantiating it the first time it is referenced. + * */ + upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + /** + * Get or create the sequence flow instance for the given id. + * */ + getSequenceFlowById(sequenceFlowId: string): any; + + getInboundSequenceFlows(activityId: string): any[]; + + getOutboundSequenceFlows(activityId: string): any[]; + + getInboundAssociations(activityId: string): any[]; + + getOutboundAssociations(activityId: string): any[]; + /** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getActivities(scopeId?: string): any[]; + /** + * Get every sequence flow in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getSequenceFlows(scopeId?: string): any[]; + /** + * Return the cached sequence flow, instantiating it the first time it is referenced. + * */ + upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * @param scopeId Process or sub-process id + */ + getAssociations(scopeId?: string): any[]; + + upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + /** + * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * + */ + clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; + /** + * Get or create the process instance for the given id. Each process gets its own cloned environment. + * */ + getProcessById(processId: string): any; + /** + * Build a fresh, uncached process instance for the given id. Used by call activities. + * */ + getNewProcessById(processId: string): any; + /** + * Get every process in the definition. + */ + getProcesses(): any[]; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any[]; + /** + * Get message flows that originate from the given process id. + * @param sourceId Source process id + */ + getMessageFlows(sourceId: string): any[]; + /** + * Get or create a data object instance for the given reference id. + * */ + getDataObjectById(referenceId: string): any; + /** + * Get or create a data store instance for the given reference id. + * */ + getDataStoreById(referenceId: string): any; + /** + * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + * @param scopeId Process or sub-process id + */ + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + /** + * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. + * Returns undefined when the activity has no extensions to attach. + * */ + loadExtensions(activity: ElementBase): Extensions | undefined; + /** + * Resolve the parent process or sub-process activity that owns the given activity. + * */ + getActivityParentById(activityId: string): any; + + private [K_OWNER]; + } + class ExtensionsMapper { + constructor(context: any); + context: any; + get(activity: any): Extensions; + + _getExtensions(): any[]; + } + class Extensions { + constructor(activity: any, context: any, extensions: any); + extensions: any[]; + get count(): number; + activate(message: any): void; + deactivate(message: any): void; + + private [K_ACTIVATED]; + } + const K_OWNER: unique symbol; + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + class Process { + /** + * Owns one ``. Wraps the structural definition and orchestrates flow traversal, + * joins, and parallel activation through ProcessExecution. + * */ + constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + isExecutable: any; + environment: Environment; + context: ContextInstance; + broker: import("smqp").Broker; + on: any; + once: any; + waitFor: any; + logger: ILogger | { + debug: () => void; + error: () => void; + warn: () => void; + }; + /** + * Allocate an executionId and emit init event without starting the run. + * @param useAsExecutionId Override for the generated execution id + */ + init(useAsExecutionId?: string): void; + /** + * Start running the process by publishing run.enter, run.start, and run.execute. + * @param runContent Optional content merged into the run message + * @throws {Error} when the process is already running + */ + run(runContent?: Record): void; + /** + * Resume after recover by republishing the last run message. + * @throws {Error} when called on a running process + */ + resume(): this; + /** + * Snapshot process state for recover. + */ + getState(): { + id: string | undefined; + type: string; + executionId: any; + environment: { + settings: { + enableDummyService?: boolean; + step?: boolean; + strict?: boolean; + batchSize?: number; + disableTrackState?: boolean; + skipDiscard: boolean; + }; + variables: { + [x: string]: any; + }; + output: any; + }; + status: any; + stopped: any; + counters: any; + broker: { + exchanges: { + bindings?: { + id: string; + options: { + priority: number; + }; + queueName: string; + pattern: string; + }[] | undefined; + deliveryQueue?: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + } | undefined; + name: string; + type: import("smqp").exchangeType; + options: { + [x: string]: any; + durable?: boolean; + autoDelete?: boolean; + }; + }[] | undefined; + queues: { + name: string; + options: import("smqp").QueueOptions; + messages?: import("smqp").MessageEnvelope[]; + }[] | undefined; + } | undefined; + execution: any; + }; + /** + * Restore process state captured by getState. + * @throws {Error} when called on a running process + */ + recover(state?: ProcessState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. + * + */ + shake(startId?: string): any; + /** + * Stop the process if running. + */ + stop(): void; + /** + * Resolve a Process Api wrapper, preferring the running execution if any. + * + */ + getApi(message?: ElementBrokerMessage): any; + /** + * Send a delegated signal to the running process. + * + */ + signal(message?: signalMessage): any; + /** + * Cancel a running activity inside the process by delegated api message. + * + */ + cancelActivity(message?: signalMessage): any; + + _activateRunConsumers(): void; + + _deactivateRunConsumers(): void; + + _onRunMessage(routingKey: any, message: any): any; + + _onResumeMessage(message: any): any; + + _onExecutionMessage(routingKey: any, message: any): void; + + _publishEvent(state: any, content: any): void; + /** + * Deliver a message to a target activity or start activity that references it. + * Starts the process if a target is found and the process is idle. + * */ + sendMessage(message: ElementBrokerMessage): void; + + getActivityById(childId: string): any; + /** + * Get every activity in the process scope. + */ + getActivities(): any; + /** + * Get start activities, optionally filtered by referenced event definition. + * + */ + getStartActivities(filterOptions?: startActivityFilterOptions): any[]; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any; + + getLaneById(laneId: string): any; + /** + * List currently postponed activities as Api wrappers. + * + */ + getPostponed(...args: any[]): any; + + _onApiMessage(routingKey: any, message: any): void; + + _onStop(): void; + + _createMessage(override: any): any; + + _debug(msg: any): void; + + private [K_COUNTERS]; + + private [K_CONSUMING]; + + private [K_EXECUTION]; + + private [K_STATUS]; + + private [K_STOPPED]; + + private [K_MESSAGE_HANDLERS]; + + private [K_LANES]; + + private [K_EXTENSIONS]; + + private [K_STATE_MESSAGE]; + + private [K_EXECUTE_MESSAGE]; + } + const K_LANES: unique symbol; + class Timers { + constructor(options: any); + count: number; + options: any; + setTimeout: any; + clearTimeout: any; + get executing(): any[]; + register(owner: any): RegisteredTimers; + _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; + _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; + + private [K_EXECUTING]; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + + private [K_TIMER_API]; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + const K_EXECUTING: unique symbol; + const K_TIMER_API: unique symbol; + class Scripts { + getScript(): void; + register(): void; + } + export {}; } diff --git a/types/index.d.ts.map b/types/index.d.ts.map index e3314e57..c9c46795 100644 --- a/types/index.d.ts.map +++ b/types/index.d.ts.map @@ -10,6 +10,7 @@ "K_EVENT_DEFINITIONS", "K_CONSUMING_RUN_Q", "Context", + "ContextInstance", "ExtensionsMapper", "Extensions", "K_OWNER", @@ -47,16 +48,11 @@ "MessageFlow", "K_SOURCE_ELEMENT", "SequenceFlow", - "ElementBase", - "Element", - "Api", - "ContextInstance", - "ProcessExecution", - "ElementBroker", "signalMessage", "ElementMessageContent", "ElementBrokerMessage", "ElementParent", + "ElementBase", "ISequenceFlowCondition", "IActivityBehaviour", "Extension", @@ -65,9 +61,7 @@ "EnvironmentSettings", "EnvironmentOptions", "startActivityFilterOptions", - "filterPostponed", - "ProcessRunStatus", - "ActivityStatus", + "runCallback", "ElementState", "EnvironmentState", "completedCounters", @@ -80,8 +74,6 @@ "ProcessState", "DefinitionExecutionState", "DefinitionState", - "runCallback", - "MessageFlowReference", "LoggerFactory", "ILogger", "wrappedSetTimeout", @@ -130,8 +122,11 @@ "ExclusiveGateway", "InclusiveGateway", "ParallelGateway", + "Api", "ScriptCondition", "ExpressionCondition", + "makeErrorFromMessage", + "BpmnError", "BoundaryEventBehaviour", "K_SHOVELS", "K_ATTACHED_TAGS", @@ -155,16 +150,17 @@ "K_EXECUTIONS", "K_ON_EXECUTION_COMPLETED", "TaskBehaviour", + "ProcessExecution", "K_PARENT", "K_ELEMENTS", "K_TRACKER", - "K_ACTIVITY_Q" + "K_ACTIVITY_Q", + "filterPostponed" ], "sources": [ "../src/activity/Activity.js", "../src/Context.js", "../src/definition/Definition.js", - "types.d.ts", "../src/Environment.js", "../src/activity/Escalation.js", "../src/activity/Message.js", @@ -184,9 +180,10 @@ "../src/tasks/SubProcess.js", "../src/tasks/Task.js", "../src/tasks/Transaction.js", + "../src/flows/Association.js", "../src/flows/MessageFlow.js", - "../src/Api.js", - "interfaces.d.ts", + "../src/flows/SequenceFlow.js", + "types.d.ts", "../src/constants.js", "../src/events/BoundaryEvent.js", "../src/events/EndEvent.js", @@ -208,6 +205,7 @@ "../src/gateways/ExclusiveGateway.js", "../src/gateways/InclusiveGateway.js", "../src/gateways/ParallelGateway.js", + "../src/Api.js", "../src/condition.js", "../src/process/ProcessExecution.js" ], @@ -260,8 +258,9 @@ null, null, null, + null, null ], - "mappings": ";;;;;;;;;iBA0BgBA,QAAQA;cAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;;;;;;;;;;;;;;iBCCCC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6UtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCWGC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCqMLC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UCFvBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;iBCLOC,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAVC,OAAOA;;;;;;;;;;;iBH+VVC,IAAIA;cAAJA,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;OI/VnBC,SAASA;;;;;;;;;;;;;;;;;;;;iBJ+SMC,OAAOA;cAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OKvStBC,OAAOA;iBCHWC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;OAF5BC,YAAYA;iBCDMC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;iBCFrBC,MAAMA;;;;;;;iBCENC,2BAA2BA;iBCGnCC,MAAMA;cAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;cCCJC,aAAaA;;;;;;;;;;;;;cAebC,QAAQA;;;iBCbGC,YAAYA;iBCAZC,WAAWA;iBCCXC,UAAUA;iBCDVC,WAAWA;iBCAXC,UAAUA;iBCGVC,UAAUA;iBCJVC,IAAIA;iBCDJC,WAAWA;;;;;iBnBoYdC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAVXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OoBtX1BC,gBAAgBA;;;;;iBpBgWDC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAjQHC,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YqB9DrBC,GAAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QrB4LEC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4FXC,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YsBzUhBC,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YASZC,wBAAwBA;;;;;;;;YAQxBC,eAAeA;;;;;;;;;OASpBC,WAAWA;;YAENC,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;OCvVlBC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OACfC,QAAQA;OACRC,SAASA;iBCHEC,aAAaA;iBCLbC,QAAQA;iBCARC,sBAAsBA;iBCAtBC,sBAAsBA;iBCAtBC,UAAUA;iBCFVC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,cAAcA;OADdC,cAAcA;iBCCIC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,WAAWA;iBCDOC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJtCC,OAAOA;OADPC,eAAeA;UCLLC,OAAOA;OAAPA,OAAOA;;;;iBCICC,iBAAiBA;iBCDjBC,gBAAgBA;iBCAhBC,gBAAgBA;iBCOhBC,eAAeA;cAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UCFvBC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;iBpB1BX1B,aAAaA;iBAIrB2B,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OANhCC,SAASA;OAFTC,eAAeA;OACfC,kBAAkBA;iBCFA7B,QAAQA;iBAIhB8B,iBAAiBA;cAAjBA,iBAAiBA;;;;;;;;;iBCJT7B,sBAAsBA;iBAI9B8B,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;;iBCJvB7B,sBAAsBA;iBAI9B8B,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;iBCJvB7B,UAAUA;iBAIlB8B,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;U/BiBnBzI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BXVmF,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;QvB0FEvD,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;YsBpYPS,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;iBOpVPoB,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,cAAcA;OADdC,cAAcA;iBCCIC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAF3CC,WAAWA;iBCDOC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJtCC,OAAOA;OADPC,eAAeA;OfLRjC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OAEfE,SAASA;QvBwFQzD,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;;;;U4C9XhBuF,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;U/CVnBjI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;YyBTE4C,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;iBtB+CV/C,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAVXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OoBtX1BC,gBAAgBA;;;;;iBpBgWDC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAjQHC,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YqB9DrBC,GAAGA;;;;;;;;;;;;;;;;;;;;QrBkKEnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YsB7VAgC,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCvVlBC,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;;;;;;;U1BeZpG,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;;;;iB2CPCsH,iBAAiBA;iBAIzBc,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;iBCLlBb,gBAAgBA;iBAIxBc,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCJjBb,gBAAgBA;iBAIxBc,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCGjBb,eAAeA;cAAfA,eAAeA;;;;iBAoCvBc,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;;;;;;;;;;;;UAqI/BC,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;U9CzJJ9I,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BXVmF,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OAGf2C,SAASA;QvBuFQlG,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;YsBpYPS,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;iBVnVPvD,YAAYA;iBAIpB+G,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;iBCJb9G,WAAWA;iBASnB+G,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;iBCRZ9G,UAAUA;iBAIlB+G,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;iBCLX9G,WAAWA;iBAInB+G,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;iBCJZ9G,UAAUA;iBAIlB+G,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;iBCDX9G,UAAUA;iBAqBlB+G,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;;;OAxB7BC,YAAYA;OACZC,wBAAwBA;iBCFNhH,IAAIA;iBAIZiH,aAAaA;cAAbA,aAAaA;;;;;;;;iBCLLhH,WAAWA;;;;;;;UtBwBnBxC,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAhBlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BXVmF,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OAEjBE,YAAYA;OACZC,kBAAkBA;OAElBE,mBAAmBA;OAEnBE,eAAeA;OACfC,QAAQA;OACRC,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OsBHhBmD,QAAQA;OADRC,UAAUA;OAEVC,SAASA;OAHTC,YAAYA;Q7C6FY/G,WAAWA;;;;;;;;;;;;QAYXC,OAAOA;;;;;;;;;;YA2CZC,GAAGA;;;;;;;;;;;;;;;;;;;;QAyDPnC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;QA0BXoC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgEf5B,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BH6B,gBAAgBA;;;;;;;;;;;;;;;;;;;;QAoBpB/B,IAAIA;;;;;;;QAOJ0B,YAAYA;;;;;;;;;;;;;;;;;;;;;;QAsBZF,WAAWA;;;;;;;;;;QAUXD,WAAWA;;;;;;;;;;YsBpYPS,aAAaA;;;;OAIlBC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;YA6BbC,sBAAsBA;;;;;;;;;;;YAWtBC,kBAAkBA;;;;;;;;;OASvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;YAIZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;OAcvBC,0BAA0BA;;;;;;;OAO1BC,eAAeA;;OAUTC,gBAAgBA;;;;;;;;;;;;;OAahBC,cAAcA;;;;;;;;;;;;;;;;;;;;YA4CfC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YA4BZI,oBAAoBA;;;;;;OAMzBC,aAAaA;;YAERC,OAAOA;;;;;;;OAOZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;YAePC,QAAQA;;;;;YAKRC,MAAMA", + "mappings": ";;;;;;;;;iBAgCgBA,QAAQA;cAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;;;;;;;;;;;;;;iBCPPC,OAAOA;;;;;UAWPC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCkBGC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCTVC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;iBCLDC,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAVC,OAAOA;;;;;;;;;;;iBCQPC,IAAIA;cAAJA,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARdC,SAASA;;;;;;;;;;;;;;;;;;;;iBC0BCC,OAAOA;cAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;iBCbGC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;OAFpBC,YAAYA;iBCFFC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;iBCDrBC,MAAMA;;;;;;;iBCCNC,2BAA2BA;iBCI3BC,MAAMA;cAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;cCCJC,aAAaA;;;;;;;;;;;;;cAebC,QAAQA;;;iBCbLC,YAAYA;iBCAZC,WAAWA;iBCCXC,UAAUA;iBCDVC,WAAWA;iBCAXC,UAAUA;iBCGVC,UAAUA;iBCJVC,IAAIA;iBCFJC,WAAWA;;;;;iBCWXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OATrBC,gBAAgBA;;;;;iBCONC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCyBRC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;YAiFhBC,sBAAsBA;;;;;;;;;;;;;YAatBC,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;OAS1BC,WAAWA;;;;YAuENC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YASZC,wBAAwBA;;;;;;;;YAQxBC,eAAeA;;;;;;;;;;;OAmBpBC,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;OCzclBC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OACfC,QAAQA;OACRC,SAASA;iBCHNC,aAAaA;iBCLbC,QAAQA;iBCARC,sBAAsBA;iBCAtBC,sBAAsBA;iBCAtBC,UAAUA;iBCFVC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,cAAcA;OADdC,cAAcA;iBCCJC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,WAAWA;iBCDDC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJ9BC,OAAOA;OADPC,eAAeA;UCLLC,OAAOA;OAAPA,OAAOA;;;;iBCIPC,iBAAiBA;iBCDjBC,gBAAgBA;iBCAhBC,gBAAgBA;iBCOhBC,eAAeA;cAAfA,eAAeA;;;;;;;;;;;UCyCfC,GAAGA;OAAHA,GAAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UC5CHC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;iBnCEnBC,oBAAoBA;cAnCvB3F,aAAaA;;;;;;;;;;;;;cAebC,QAAQA;;;cAOR2F,SAASA;;;;;;;;;;;;;;;;;;;;;iBcdN7B,aAAaA;iBAIb8B,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OANhCC,SAASA;OAFTC,eAAeA;OACfC,kBAAkBA;iBCFRhC,QAAQA;iBAIRiC,iBAAiBA;cAAjBA,iBAAiBA;;;;;;;;;iBCJjBhC,sBAAsBA;iBAItBiC,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;;iBCJ/BhC,sBAAsBA;iBAItBiC,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;iBCJ/BhC,UAAUA;iBAIViC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;U/BuBnBpI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BnBV2E,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OACfC,QAAQA;OACRC,SAASA;ODyBFhD,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;UMqBGU,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;iBVGPf,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,cAAcA;OADdC,cAAcA;iBCCJC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,WAAWA;iBCDDC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJ9BC,OAAOA;OADPC,eAAeA;OfLRjC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OACfC,QAAQA;OACRC,SAASA;ODyBFhD,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;UuBlcfyC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;UhDHnB1H,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;UOOPe,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;;;;;;UJJGT,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;UWAGiB,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;iBpBYPzE,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OATrBC,gBAAgBA;;;;;iBCONC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCyBRC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;YAiFhBC,sBAAsBA;;;;;;;;;;;;;YAatBC,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;;;;U4C8CDwG,GAAGA;OAAHA,GAAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OrBnDNvC,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OACfC,QAAQA;OACRC,SAASA;;;;;UzBUNtF,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;;;UD2BGX,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;UOOPe,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;iBCIPC,iBAAiBA;iBAIjBiB,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;iBCL1BhB,gBAAgBA;iBAIhBiB,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCJzBhB,gBAAgBA;iBAIhBiB,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCGzBhB,eAAeA;cAAfA,eAAeA;;;;iBAoCfiB,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;;;;;;;;;;;;UAqI/BC,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;U9CnJJzI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BnBV2E,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OACfC,QAAQA;OACRC,SAASA;OACT4C,SAASA;ODwBF5F,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;UMqBGU,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;iB5BIPjF,YAAYA;iBAIZyG,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;iBCJrBxG,WAAWA;iBASXyG,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;iBCRpBxG,UAAUA;iBAIVyG,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;iBCLnBxG,WAAWA;iBAIXyG,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;iBCJpBxG,UAAUA;iBAIVyG,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;iBCDnBxG,UAAUA;iBAqBVyG,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;;;OAxB7BC,YAAYA;OACZC,wBAAwBA;iBCFd1G,IAAIA;iBAIJ2G,aAAaA;cAAbA,aAAaA;;;;;;;;iBCNb1G,WAAWA;;;;;;;UrB+BXzC,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BnBV2E,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAElBE,mBAAmBA;OAEnBE,eAAeA;OACfC,QAAQA;OACRC,SAASA;;;;;UuBINsD,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAT1BC,QAAQA;OADRC,UAAUA;OAEVC,SAASA;OAHTC,YAAYA;OxBgCE1G,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;OAO1B+F,eAAeA;;;;YAyEV7F,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;UMqBGU,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA", "ignoreList": [] } \ No newline at end of file diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts deleted file mode 100644 index 7a462107..00000000 --- a/types/interfaces.d.ts +++ /dev/null @@ -1,355 +0,0 @@ -import { Broker, BrokerState, Consumer, MessageEnvelope, MessageFields, MessageProperties } from 'smqp'; - -export declare interface ElementBroker extends Broker { - get owner(): T; -} - -export declare type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; -}; - -export declare interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; -} - -export declare interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; -} - -export declare interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; -} - -export declare const enum TimerType { - TimeCycle = 'timeCycle', - TimeDuration = 'timeDuration', - TimeDate = 'timeDate', -} - -export declare type parsedTimer = { - /** Expires at date time */ - expireAt?: Date; - /** Repeat number of times */ - repeat?: number; - /** Delay in milliseconds */ - delay?: number; -}; - -export declare interface ICondition { - /** Condition type */ - get type(): string; - [x: string]: any; - execute(message: ElementBrokerMessage, callback: CallableFunction): void; -} - -export declare interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; -} - -export declare interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; -} - -export declare type Extension = (activity: any, context: any) => IExtension; -export declare interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; -} - -export declare interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; -} - -export declare interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; -} - -export declare interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; -} - -export declare type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; -}; - -export declare type filterPostponed = (elementApi: any) => boolean; - -export declare const enum DefinitionRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - End = 'end', - Discarded = 'discarded', -} - -export declare const enum ProcessRunStatus { - Entered = 'entered', - Start = 'start', - Executing = 'executing', - Errored = 'errored', - End = 'end', - Discarded = 'discarded', -} - -/** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. - */ -export declare const enum ActivityStatus { - /** Idle, not running anything */ - Idle = 'idle', - /** - * At least one activity is executing, - * e.g. a service task making a asynchronous request - */ - Executing = 'executing', - /** - * At least one activity is waiting for a timer to complete, - * usually only TimerEventDefinition's - */ - Timer = 'timer', - /** - * At least one activity is waiting for a signal of some sort, - * e.g. user tasks, intermediate catch events, etc - */ - Wait = 'wait', -} - -/** - * Activity run status - */ -export declare const enum ActivityRunStatus { - /** Run entered, triggered by taken inbound flow */ - Entered = 'entered', - /** Run started */ - Started = 'started', - /** Executing activity behaviour */ - Executing = 'executing', - /** Activity behaviour execution completed successfully */ - Executed = 'executed', - /** Run end, take outbound flows */ - End = 'end', - /** Entering discard run, triggered by discarded inbound flow */ - Discard = 'discard', - /** Run was discarded, discard outbound flows */ - Discarded = 'discarded', - /** Activity behaviour execution failed, discard run */ - Error = 'error', - /** Formatting next run message */ - Formatting = 'formatting', -} - -export declare interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; -} - -export declare interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; -} - -export declare type completedCounters = { completed: number; discarded: number }; - -export declare interface ActivityExecutionState { - completed: boolean; - [x: string]: any; -} - -export declare interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; -} - -export declare interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; -} - -export declare interface MessageFlowState extends ElementState { - counters: { messages: number }; -} - -export declare interface AssociationState extends ElementState { - counters: { take: number; discard: number }; -} - -export declare interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; -} - -export declare interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; -} - -export declare interface DefinitionExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - processes: ProcessState[]; -} - -export declare interface DefinitionState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: DefinitionExecutionState; -} - -export declare type runCallback = (err: Error, definitionApi: any) => void; - -export declare interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; -} - -export declare type LoggerFactory = (scope: string) => ILogger; - -export declare interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; -} - -export declare type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; -export declare type wrappedClearTimeout = (ref: any) => void; - -export declare interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; -} - -export declare interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; -} - -export declare interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; -} - -export declare interface TimersOptions { - /** Defaults to builtin setTimeout */ - setTimeout?: typeof setTimeout; - /** Defaults to builtin clearTimeout */ - clearTimeout?: typeof clearTimeout; - [x: string]: any; -} - -export declare interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; -} - -export declare interface Script { - execute(executionContext: any, callback: CallableFunction): void; -} - -/** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ - -export { Consumer, MessageFields, MessageProperties }; diff --git a/types/types.d.ts b/types/types.d.ts index f2cda12c..b4068946 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1,104 +1,78 @@ -import { Broker } from 'smqp'; +import { Broker, BrokerState, Consumer, MessageEnvelope, MessageFields, MessageProperties } from 'smqp'; import { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + +// Class re-exports — types follow the implementation in src/. export { Activity } from '../src/activity/Activity.js'; -import { Activity } from '../src/activity/Activity.js'; +export { ActivityExecution } from '../src/activity/ActivityExecution.js'; +export { Process } from '../src/process/Process.js'; +export { ProcessExecution } from '../src/process/ProcessExecution.js'; +export { Lane } from '../src/process/Lane.js'; +export { Definition } from '../src/definition/Definition.js'; +export { DefinitionExecution } from '../src/definition/DefinitionExecution.js'; +export { Environment } from '../src/Environment.js'; +export { Context, ContextInstance } from '../src/Context.js'; +export { SequenceFlow } from '../src/flows/SequenceFlow.js'; +export { MessageFlow } from '../src/flows/MessageFlow.js'; +export { Association } from '../src/flows/Association.js'; +export { Timers } from '../src/Timers.js'; +export { Formatter as MessageFormatter } from '../src/MessageFormatter.js'; +export { ActivityError, BpmnError, RunError } from '../src/error/Errors.js'; +export { TimerEventDefinition } from '../src/eventDefinitions/TimerEventDefinition.js'; +export { ConditionalEventDefinition } from '../src/eventDefinitions/ConditionalEventDefinition.js'; -import { - ElementBroker, - ElementBrokerMessage, - ElementMessageContent, - ElementParent, - ElementState, - ActivityState, - ActivityExecutionState, - IActivityBehaviour, - IExtension, - IExpressions, - IScripts, - ITimers, - ILogger, - ICondition, - ISequenceFlowCondition, - ActivityRunStatus, - ActivityStatus, - DefinitionRunStatus, - ProcessRunStatus, - TimerType, - parsedTimer, - EnvironmentSettings, - EnvironmentOptions, - EnvironmentState, - startActivityFilterOptions, - filterPostponed, - runCallback, - completedCounters, - signalMessage, - ProcessExecutionState, - ProcessState, - DefinitionExecutionState, - DefinitionState, - SequenceFlowState, - MessageFlowState, - AssociationState, - MessageFlowReference, - LoggerFactory, - Timer, - RegisteredTimer, - TimersOptions, - Script, - wrappedSetTimeout, - wrappedClearTimeout, -} from './interfaces.js'; - -export * from './interfaces.js'; +// Re-export of supporting smqp types (kept here so JSDoc can address them via `import('types')`). +export { Consumer, MessageFields, MessageProperties }; -export declare class EventDefinition { - constructor(activity: Activity, eventDefinitionElement: SerializableElement, context?: ContextInstance, index?: number); - get id(): string; - get type(): string; - get executionId(): string; - get isThrowing(): boolean; - get activity(): Activity; - get broker(): Broker; - get logger(): ILogger; - get reference(): { - id?: string; - name: string; - referenceType: string; - }; - [x: string]: any; - execute(executeMessage: ElementBrokerMessage): void; -} +import { Activity } from '../src/activity/Activity.js'; +import { Process } from '../src/process/Process.js'; +import { Definition } from '../src/definition/Definition.js'; +import { Environment } from '../src/Environment.js'; +import { ContextInstance } from '../src/Context.js'; +import { ActivityError } from '../src/error/Errors.js'; -export declare class TimerEventDefinition extends EventDefinition { - /** - * Parse timer type - * @param timerType type of timer - * @param timerValue resolved expression timer string - */ - parse(timerType: TimerType, timerValue: string): parsedTimer; +// --- Broker / message contracts ----------------------------------------------- + +export declare interface ElementBroker extends Broker { + get owner(): T; } -export declare class ConditionalEventDefinition extends EventDefinition { - /** - * Evaluate condition - * @param message - * @param callback - */ - evaluate(message: ElementBrokerMessage, callback: CallableFunction): void; +export declare type signalMessage = { /** - * Handle evaluate result or error - * @param err Condition evaluation error - * @param result Result from evaluated condition, completes execution if truthy + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc */ - evaluateCallback(err: Error | null, result?: any): void; + id?: string; /** - * Get condition from behaviour - * @param index Event definition sequence number, used to name registered script + * Optional execution id + * e.g. excutionId of a parallel multi instance user task */ - getCondition(index: number): ICondition | null; + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; +}; + +export declare interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; } +export declare interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; +} + +export declare interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; +} + +// --- Element abstract bases --------------------------------------------------- + export declare abstract class ElementBase { get id(): string; get type(): string; @@ -121,39 +95,372 @@ export declare abstract class Element extends ElementBase { waitFor(eventName: string, options?: any): Promise>; } -export declare interface DefinitionExecution { +export declare abstract class MessageElement { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + resolve(executionMessage: ElementBrokerMessage): { + parent: ElementParent; + name: string; + id: string; + type: string; + messageType: string; + }; +} + +// --- Event definitions -------------------------------------------------------- + +// Common ancestor for the typed event definitions; concrete types live in src/eventDefinitions. +export declare class EventDefinition { + constructor(activity: Activity, eventDefinitionElement: SerializableElement, context?: ContextInstance, index?: number); get id(): string; get type(): string; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get processes(): Process[]; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; + get isThrowing(): boolean; + get activity(): Activity; + get broker(): Broker; + get logger(): ILogger; + get reference(): { + id?: string; + name: string; + referenceType: string; + }; + [x: string]: any; execute(executeMessage: ElementBrokerMessage): void; - getProcesses(): Process[]; - getProcessById(processId: string): Process; - getProcessesById(processId: string): Process[]; - getProcessByExecutionId(processExecutionId: string): Process; - getRunningProcesses(): Process[]; - getExecutableProcesses(): Process[]; - getPostponed(filterFn?: filterPostponed): Api[]; } -export declare interface ActivityExecution { - get completed(): boolean; - get executionId(): string; - get source(): IActivityBehaviour; +export declare const enum TimerType { + TimeCycle = 'timeCycle', + TimeDuration = 'timeDuration', + TimeDate = 'timeDate', +} + +export declare type parsedTimer = { + /** Expires at date time */ + expireAt?: Date; + /** Repeat number of times */ + repeat?: number; + /** Delay in milliseconds */ + delay?: number; +}; + +// --- Conditions --------------------------------------------------------------- + +export declare interface ICondition { + /** Condition type */ + get type(): string; + [x: string]: any; + execute(message: ElementBrokerMessage, callback: CallableFunction): void; +} + +export declare interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; + /** + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken + */ + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; +} + +// --- Activity behaviour & extensions ------------------------------------------ + +export declare interface IActivityBehaviour { + id: string; + type: string; + activity: any; + environment: any; + new (activity: any, context: any): IActivityBehaviour; execute(executeMessage: ElementBrokerMessage): void; } +// Custom activity behaviour factory signature. export declare function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; +export declare type Extension = (activity: any, context: any) => IExtension; +export declare interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; +} + +export declare interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; +} + +// --- Environment -------------------------------------------------------------- + +export declare interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; +} + +export declare interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; +} + +// --- Filter / callback shapes ------------------------------------------------- + +export declare type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; +}; + +export declare type filterPostponed = (elementApi: any) => boolean; + +export declare type runCallback = (err: Error, definitionApi: any) => void; + +// --- Run-status enums --------------------------------------------------------- + +export declare const enum DefinitionRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + End = 'end', + Discarded = 'discarded', +} + +export declare const enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', +} + +/** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ +export declare const enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', +} + +/** + * Activity run status + */ +export declare const enum ActivityRunStatus { + /** Run entered, triggered by taken inbound flow */ + Entered = 'entered', + /** Run started */ + Started = 'started', + /** Executing activity behaviour */ + Executing = 'executing', + /** Activity behaviour execution completed successfully */ + Executed = 'executed', + /** Run end, take outbound flows */ + End = 'end', + /** Entering discard run, triggered by discarded inbound flow */ + Discard = 'discard', + /** Run was discarded, discard outbound flows */ + Discarded = 'discarded', + /** Activity behaviour execution failed, discard run */ + Error = 'error', + /** Formatting next run message */ + Formatting = 'formatting', +} + +// --- State snapshots ---------------------------------------------------------- + +export declare interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; +} + +export declare interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; +} + +export declare type completedCounters = { completed: number; discarded: number }; + +export declare interface ActivityExecutionState { + completed: boolean; + [x: string]: any; +} + +export declare interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; +} + +export declare interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; +} + +export declare interface MessageFlowState extends ElementState { + counters: { messages: number }; +} + +export declare interface AssociationState extends ElementState { + counters: { take: number; discard: number }; +} + +export declare interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; +} + +export declare interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; +} + +export declare interface DefinitionExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + processes: ProcessState[]; +} + +export declare interface DefinitionState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: DefinitionExecutionState; +} + +// --- Flow references ---------------------------------------------------------- + +export declare interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; +} + +// --- Logging ------------------------------------------------------------------ + +export declare type LoggerFactory = (scope: string) => ILogger; + +export declare interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; +} + +// --- Timers ------------------------------------------------------------------- + +export declare type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; +export declare type wrappedClearTimeout = (ref: any) => void; + +export declare interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; +} + +export declare interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; +} + +export declare interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; +} + +export declare interface TimersOptions { + /** Defaults to builtin setTimeout */ + setTimeout?: typeof setTimeout; + /** Defaults to builtin clearTimeout */ + clearTimeout?: typeof clearTimeout; + [x: string]: any; +} + +// --- Scripts ------------------------------------------------------------------ + +export declare interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; +} + +export declare interface Script { + execute(executionContext: any, callback: CallableFunction): void; +} + +// --- Generic api shape; constructed via Activity/Process/Definition/Flow Api factories. + export declare interface Api extends ElementBrokerMessage { get id(): string; get type(): string; @@ -174,6 +481,8 @@ export declare interface Api extends ElementBrokerMessage { getExecuting(): Api[]; } +// --- Scope passed to user scripts/services ----------------------------------- + interface ExecutionScope { /** Calling element id */ id: string; @@ -197,234 +506,9 @@ interface ExecutionScope { ActivityError: ActivityError; } -export declare abstract class MessageElement { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - resolve(executionMessage: ElementBrokerMessage): { - parent: ElementParent; - name: string; - id: string; - type: string; - messageType: string; - }; -} - -export declare class Environment { - constructor(options?: EnvironmentOptions); - options: Record; - expressions: IExpressions; - extensions: Record; - scripts: IScripts; - timers: ITimers; - Logger: LoggerFactory; - get settings(): EnvironmentSettings; - get variables(): Record; - get output(): Record; - set services(arg: any); - get services(): any; - getState(): EnvironmentState; - recover(state?: EnvironmentState): Environment; - clone(overrideOptions?: EnvironmentOptions): Environment; - assignVariables(newVars: Record): void; - assignSettings(newSettings: Record): Environment; - registerScript(activity: any): Script; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - getServiceByName(serviceName: string): CallableFunction; - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - addService(name: string, fn: CallableFunction): void; -} - -export declare function Context(definitionContext: SerializableContext, environment?: Environment): ContextInstance; -export declare class ContextInstance { - constructor(definitionContext: SerializableContext, environment?: Environment); - get id(): string; - get name(): string; - get type(): string; - /** Unique context instance id */ - get sid(): string; - get definitionContext(): SerializableContext; - get environment(): Environment; - /** Context owner, Process or SubProcess activity */ - get owner(): Process | Activity | undefined; - getActivityById(activityId: string): T; - getSequenceFlowById(sequenceFlowId: string): SequenceFlow; - getInboundSequenceFlows(activityId: string): SequenceFlow[]; - getOutboundSequenceFlows(activityId: string): SequenceFlow[]; - getInboundAssociations(activityId: string): Association[]; - getOutboundAssociations(activityId: string): Association[]; - getActivities(scopeId?: string): ElementBase[]; - getSequenceFlows(scopeId?: string): SequenceFlow[]; - getAssociations(scopeId?: string): Association[]; - clone(newEnvironment?: Environment): ContextInstance; - getProcessById(processId: string): Process; - getNewProcessById(processId: string): Process; - getProcesses(): Process[]; - getExecutableProcesses(): Process[]; - getMessageFlows(sourceId: string): MessageFlow[]; - getDataObjectById(referenceId: string): any; - getDataStoreById(referenceId: string): any; - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; - loadExtensions(activity: ElementBase): IExtension; -} - -export declare class Definition extends Element { - constructor(context: ContextInstance, options?: EnvironmentOptions); - get counters(): completedCounters; - get execution(): DefinitionExecution; - get executionId(): string; - get isRunning(): boolean; - get status(): DefinitionRunStatus | undefined; - get stopped(): boolean; - get activityStatus(): ActivityStatus; - run(): Definition; - run(runContent: Record): Definition; - run(runContent: Record, callback: runCallback): Definition; - run(callback: runCallback): Definition; - getState(): DefinitionState; - recover(state?: DefinitionState): Definition; - resume(): void; - resume(callback: (err: Error, definitionApi: Api) => void): void; - shake(startId?: string): object; - getProcesses(): Process[]; - /** get processes marked with isExecutable=true */ - getExecutableProcesses(): Process[]; - getRunningProcesses(): Process[]; - getProcessById(processId: string): Process; - getActivityById(childId: string): Activity; - getElementById(elementId: string): Element; - getPostponed(filterFn?: filterPostponed): Api[]; - /** Send delegated signal message */ - signal(message: any): void; - cancelActivity(message: any): void; - sendMessage(message: any): void; -} - -export declare class Process extends Element { - constructor(processDef: SerializableElement, context: ContextInstance); - get isExecutable(): boolean; - get counters(): completedCounters; - get lanes(): Lane[] | undefined; - get extensions(): IExtension; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string; - get execution(): ProcessExecution; - get status(): ProcessRunStatus | undefined; - get activityStatus(): ActivityStatus; - init(useAsExecutionId?: string): void; - run(runContent?: Record): void; - getState(): ProcessState; - recover(state?: ProcessState): Process; - shake(startId?: string): void; - signal(message: any): any; - cancelActivity(message: any): any; - sendMessage(message: any): void; - getActivityById(childId: string): T; - getActivities(): Activity[]; - getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; - getSequenceFlows(): SequenceFlow[]; - getLaneById(laneId: string): Lane | undefined; - getPostponed(filterFn: filterPostponed): Api[]; -} - -export declare interface ProcessExecution { - get isSubProcess(): boolean; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get executionId(): string; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): ActivityStatus; - execute(executeMessage: ElementBrokerMessage): void; - getPostponed(filterFn: filterPostponed): Api[]; - getActivities(): Activity[]; - getActivityById(activityId: string): T; - getSequenceFlows(): SequenceFlow[]; - getApi(message?: ElementBrokerMessage): Api; -} - -export declare class Lane extends ElementBase { - constructor(process: Process, laneDefinition: SerializableElement); - /** Process broker */ - get broker(): Broker; - get process(): Process; -} - -export declare class SequenceFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isDefault(): boolean; - get isSequenceFlow(): boolean; - get counters(): { take: number; discard: number; looped: number }; - take(content?: any): boolean; - discard(content?: any): void; - shake(message: any): number; - getCondition(): ISequenceFlowCondition | null; - createMessage(override?: any): object; - /** - * Evaluate flow - * Executes condition if any, default flow is - * @param fromMessage Activity message - * @param {evaluateCallback} callback Callback with evaluation result, if truthy flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - getState(): SequenceFlowState | undefined; -} - -export declare class MessageFlow extends Element { - constructor(flowDef: SerializableElement, context: ContextInstance); - get source(): MessageFlowReference; - get target(): MessageFlowReference; - get counters(): { messages: number }; - activate(): void; - deactivate(): void; - getState(): MessageFlowState | undefined; -} - -export declare class Association extends Element { - constructor(associationDef: SerializableElement, context: ContextInstance); - get sourceId(): string; - get targetId(): string; - get isAssociation(): boolean; - get counters(): { take: number; discard: number }; - take(content?: any): boolean; - discard(content?: any): boolean; - getState(): AssociationState | undefined; -} - -export declare class Timers implements ITimers { - options: TimersOptions; - constructor(options?: TimersOptions); - get executing(): Timer[]; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; -} - -export declare class MessageFormatter { - id: string; - broker: Broker; - logger: ILogger; - format(message: MessageElement, callback: CallableFunction): void; -} - -// Activity is generated from JSDoc in src/activity/Activity.js. Re-exporting keeps -// existing `import('types').Activity` JSDoc references resolving. - -export declare class ActivityError extends Error { - type: string; - description: string; - /** Activity that threw error */ - source?: ElementBrokerMessage; - /** Original error */ - inner?: Error; - code?: string; - constructor(description: string, sourceMessage: any, inner?: Error); -} +/** + * Evaluate flow callback + * @callback evaluateCallback + * @param {Error} err Evaluation error + * @param {boolean|object} evaluationResult If thruthy flow should be taken + */ From a59f3546b51c25c6a361c710bcd16e91e64681d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Mon, 11 May 2026 05:50:38 +0200 Subject: [PATCH 13/31] build types from implementation --- .gitignore | 3 + CHANGELOG.md | 1 + dist/Api.js | 28 +- dist/Context.js | 26 +- dist/Environment.js | 49 +- dist/EventBroker.js | 47 +- dist/MessageFormatter.js | 12 +- dist/Timers.js | 3 - dist/activity/Activity.js | 59 +- dist/activity/ActivityExecution.js | 23 +- dist/condition.js | 6 +- dist/definition/Definition.js | 54 +- dist/definition/DefinitionExecution.js | 58 +- .../eventDefinitions/CancelEventDefinition.js | 4 - .../CompensateEventDefinition.js | 15 - .../ConditionalEventDefinition.js | 3 +- dist/eventDefinitions/ErrorEventDefinition.js | 9 - .../EscalationEventDefinition.js | 7 - .../EventDefinitionExecution.js | 25 +- dist/eventDefinitions/LinkEventDefinition.js | 1 - .../MessageEventDefinition.js | 8 - .../eventDefinitions/SignalEventDefinition.js | 8 - dist/eventDefinitions/TimerEventDefinition.js | 34 +- dist/events/BoundaryEvent.js | 32 +- dist/events/EndEvent.js | 1 - dist/events/IntermediateCatchEvent.js | 1 - dist/events/IntermediateThrowEvent.js | 1 - dist/events/StartEvent.js | 2 - dist/flows/Association.js | 11 +- dist/flows/MessageFlow.js | 13 +- dist/flows/SequenceFlow.js | 17 +- dist/gateways/EventBasedGateway.js | 5 - dist/gateways/ParallelGateway.js | 11 +- dist/io/EnvironmentDataObject.js | 5 + dist/io/InputOutputSpecification.js | 1 - dist/io/Properties.js | 2 - dist/process/Lane.js | 6 +- dist/process/Process.js | 61 +- dist/process/ProcessExecution.js | 69 +- dist/tasks/CallActivity.js | 6 + dist/tasks/ReceiveTask.js | 7 - dist/tasks/SubProcess.js | 23 +- package.json | 8 +- scripts/build-types.js | 228 +- src/Api.js | 28 +- src/Context.js | 26 +- src/Environment.js | 50 +- src/EventBroker.js | 46 +- src/MessageFormatter.js | 11 +- src/Timers.js | 3 - src/activity/Activity.js | 49 +- src/activity/ActivityExecution.js | 22 +- src/condition.js | 6 +- src/definition/Definition.js | 45 +- src/definition/DefinitionExecution.js | 48 +- src/eventDefinitions/CancelEventDefinition.js | 4 - .../CompensateEventDefinition.js | 13 - .../ConditionalEventDefinition.js | 3 +- src/eventDefinitions/ErrorEventDefinition.js | 8 - .../EscalationEventDefinition.js | 7 - .../EventDefinitionExecution.js | 23 +- src/eventDefinitions/LinkEventDefinition.js | 1 - .../MessageEventDefinition.js | 8 - src/eventDefinitions/SignalEventDefinition.js | 8 - src/eventDefinitions/TimerEventDefinition.js | 31 +- src/events/BoundaryEvent.js | 30 +- src/events/EndEvent.js | 1 - src/events/IntermediateCatchEvent.js | 1 - src/events/IntermediateThrowEvent.js | 1 - src/events/StartEvent.js | 2 - src/flows/Association.js | 10 +- src/flows/MessageFlow.js | 11 +- src/flows/SequenceFlow.js | 16 +- src/gateways/EventBasedGateway.js | 4 - src/gateways/ParallelGateway.js | 11 +- src/io/EnvironmentDataObject.js | 4 + src/io/InputOutputSpecification.js | 1 - src/io/Properties.js | 1 - src/process/Lane.js | 5 +- src/process/Process.js | 51 +- src/process/ProcessExecution.js | 52 +- src/tasks/CallActivity.js | 6 + src/tasks/ReceiveTask.js | 5 - src/tasks/SubProcess.js | 21 +- test/activity/Activity-test.js | 2 +- test/feature/BoundaryEvent-feature.js | 2 + test/feature/Definition-feature.js | 4 +- test/feature/activity-io-feature.js | 2 +- test/feature/call-activity-feature.js | 3 +- test/feature/io-feature.js | 3 +- tsconfig.json | 4 +- types/augmentations.d.ts | 90 - types/bundle-errors.d.ts | 1 + types/bundle-eventDefinitions.d.ts | 1 + types/bundle-events.d.ts | 1 + types/bundle-flows.d.ts | 1 + types/bundle-gateways.d.ts | 1 + types/bundle-tasks.d.ts | 1 + types/bundle.d.ts | 63 + types/index.d.ts | 9469 +++++------------ types/index.d.ts.map | 266 - types/{types.d.ts => interfaces.d.ts} | 260 +- 102 files changed, 3402 insertions(+), 8438 deletions(-) delete mode 100644 types/augmentations.d.ts create mode 100644 types/bundle-errors.d.ts create mode 100644 types/bundle-eventDefinitions.d.ts create mode 100644 types/bundle-events.d.ts create mode 100644 types/bundle-flows.d.ts create mode 100644 types/bundle-gateways.d.ts create mode 100644 types/bundle-tasks.d.ts create mode 100644 types/bundle.d.ts delete mode 100644 types/index.d.ts.map rename types/{types.d.ts => interfaces.d.ts} (61%) diff --git a/.gitignore b/.gitignore index e8795bb5..8a7db5ca 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ CLAUDE.md *.swp *.swo +# TS +*.d.ts.map + # eslint .eslintcache diff --git a/CHANGELOG.md b/CHANGELOG.md index 607a39cb..2897e6bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - drop default exports across all implementation files in favour of named exports — internal-facing churn only, the package's public exports map (`bpmn-elements`, `bpmn-elements/events`, `…/eventDefinitions`, `…/flows`, `…/gateways`, `…/tasks`) is unchanged - replace hand-rolled class declarations in `types/types.d.ts` with re-exports from the implementation files — the type definitions track the JSDoc-driven source rather than living in parallel - strip the duplicate `export function Foo(...)` declarations that tsc emits alongside `export class Foo` for constructor-function patterns — the bundled `Definition`, `Activity`, `Process`, etc. are now plain class declarations that merge cleanly with the property augmentations +- strip internal class members (`@internal`, `private`, and underscore-prefixed names) from the bundled `.d.ts` — dts-buddy's built-in `stripInternal` only handles `PropertySignature` (interface members), so the build script now walks the bundle AST and removes matching `MethodDeclaration`/`PropertyDeclaration`/accessor nodes ### Types diff --git a/dist/Api.js b/dist/Api.js index 5a5ad2fa..2c80f3b1 100644 --- a/dist/Api.js +++ b/dist/Api.js @@ -13,8 +13,8 @@ var _shared = require("./shared.js"); /** * Build an activity-scoped Api wrapper. Routing keys are published under `activity.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ function ActivityApi(broker, apiMessage, environment) { return new Api('activity', broker, apiMessage, environment); @@ -23,8 +23,8 @@ function ActivityApi(broker, apiMessage, environment) { /** * Build a definition-scoped Api wrapper. Routing keys are published under `definition.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ function DefinitionApi(broker, apiMessage, environment) { return new Api('definition', broker, apiMessage, environment); @@ -33,8 +33,8 @@ function DefinitionApi(broker, apiMessage, environment) { /** * Build a process-scoped Api wrapper. Routing keys are published under `process.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ function ProcessApi(broker, apiMessage, environment) { return new Api('process', broker, apiMessage, environment); @@ -43,8 +43,8 @@ function ProcessApi(broker, apiMessage, environment) { /** * Build a flow-scoped Api wrapper. Routing keys are published under `flow.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ function FlowApi(broker, apiMessage, environment) { return new Api('flow', broker, apiMessage, environment); @@ -54,8 +54,8 @@ function FlowApi(broker, apiMessage, environment) { * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. * @param {string} pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` * @param {any} broker - * @param {import('types').ElementBrokerMessage} sourceMessage Cloned to back the api - * @param {import('types').Environment} [environment] Defaults to `broker.owner.environment` + * @param {import('#types').ElementBrokerMessage} sourceMessage Cloned to back the api + * @param {import('#types').Environment} [environment] Defaults to `broker.owner.environment` * @throws {Error} when sourceMessage is missing */ function Api(pfx, broker, sourceMessage, environment) { @@ -82,7 +82,7 @@ function Api(pfx, broker, sourceMessage, environment) { /** * Send a cancel api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] * @param {any} [options] */ Api.prototype.cancel = function cancel(message, options) { @@ -110,7 +110,7 @@ Api.prototype.fail = function fail(error) { /** * Send a signal api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] * @param {any} [options] */ Api.prototype.signal = function signal(message, options) { @@ -141,7 +141,7 @@ Api.prototype.resolveExpression = function resolveExpression(expression) { /** * Publish a custom api message to the broker. * @param {string} action Routing key suffix, e.g. `signal`, `cancel` - * @param {import('types').signalMessage} [content] Merged into the message content + * @param {import('#types').signalMessage} [content] Merged into the message content * @param {any} [options] */ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) { @@ -157,7 +157,7 @@ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) /** * List currently postponed activities, falling back to a sub-process execution when applicable. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ Api.prototype.getPostponed = function getPostponed(...args) { if (this.owner.getPostponed) return this.owner.getPostponed(...args); diff --git a/dist/Context.js b/dist/Context.js index 83d0c50f..505d6c99 100644 --- a/dist/Context.js +++ b/dist/Context.js @@ -14,7 +14,7 @@ const K_OWNER = Symbol.for('owner'); /** * Build a runtime Context from a parsed BPMN definition. * @param {import('moddle-context-serializer').SerializableContext} definitionContext - * @param {import('types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted + * @param {import('#types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted */ function Context(definitionContext, environment) { environment = environment ? environment.clone() : new _Environment.Environment(); @@ -24,8 +24,8 @@ function Context(definitionContext, environment) { /** * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. * @param {import('moddle-context-serializer').SerializableContext} definitionContext - * @param {import('types').Environment} environment - * @param {import('types').Process | import('types').Activity} [owner] Process or sub-process activity that owns this context + * @param {import('#types').Environment} environment + * @param {import('#types').Process | import('#types').Activity} [owner] Process or sub-process activity that owns this context */ function ContextInstance(definitionContext, environment, owner) { const { @@ -40,13 +40,13 @@ function ContextInstance(definitionContext, environment, owner) { this.sid = sid; this.definitionContext = definitionContext; this.environment = environment; + /** @type {import('#types').IExtensionsMapper} */ this.extensionsMapper = new ExtensionsMapper(this); this.refs = new Map([['activityRefs', new Map()], ['sequenceFlowRefs', new Map()], ['processRefs', new Map()], ['messageFlows', new Set()], ['associationRefs', new Map()], ['dataObjectRefs', new Map()], ['dataStoreRefs', new Map()]]); - /** @private */ this[K_OWNER] = owner; } Object.defineProperty(ContextInstance.prototype, 'owner', { - /** @returns {import('types').Process | import('types').Activity | undefined} Process or sub-process activity that owns this context */ + /** @returns {import('#types').Process | import('#types').Activity | undefined} Process or sub-process activity that owns this context */ get() { return this[K_OWNER]; } @@ -55,6 +55,7 @@ Object.defineProperty(ContextInstance.prototype, 'owner', { /** * Get or create the activity instance for the given id. * @param {string} activityId + * @returns {import('./activity/Activity.js').Activity | null} */ ContextInstance.prototype.getActivityById = function getActivityById(activityId) { const activityInstance = this.refs.get('activityRefs').get(activityId); @@ -67,6 +68,7 @@ ContextInstance.prototype.getActivityById = function getActivityById(activityId) /** * Return the cached activity instance, instantiating it the first time it is referenced. * @param {import('moddle-context-serializer').SerializableElement} activityDef + * @returns {import('./activity/Activity.js').Activity} */ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) { let activityInstance = this.refs.get('activityRefs').get(activityDef.id); @@ -79,6 +81,7 @@ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) /** * Get or create the sequence flow instance for the given id. * @param {string} sequenceFlowId + * @returns {import('./flows/SequenceFlow.js').SequenceFlow | null} */ ContextInstance.prototype.getSequenceFlowById = function getSequenceFlowById(sequenceFlowId) { const flowInstance = this.refs.get('sequenceFlowRefs').get(sequenceFlowId); @@ -166,8 +169,8 @@ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associa /** * Create a new context that shares the parsed definition but optionally swaps environment and owner. - * @param {import('types').Environment} [newEnvironment] - * @param {import('types').Process | import('types').Activity} [newOwner] + * @param {import('#types').Environment} [newEnvironment] + * @param {import('#types').Process | import('#types').Activity} [newOwner] */ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner); @@ -176,6 +179,7 @@ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { /** * Get or create the process instance for the given id. Each process gets its own cloned environment. * @param {string} processId + * @returns {import('./process/Process.js').Process | null} */ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const processRefs = this.refs.get('processRefs'); @@ -275,7 +279,7 @@ ContextInstance.prototype.getDataStoreById = function getDataStoreById(reference /** * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. - * @param {import('types').startActivityFilterOptions} [filterOptions] + * @param {import('#types').startActivityFilterOptions} [filterOptions] * @param {string} [scopeId] Process or sub-process id */ ContextInstance.prototype.getStartActivities = function getStartActivities(filterOptions, scopeId) { @@ -301,7 +305,8 @@ ContextInstance.prototype.getStartActivities = function getStartActivities(filte /** * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. * Returns undefined when the activity has no extensions to attach. - * @param {import('types').ElementBase} activity + * @param {import('#types').ElementBase} activity + * @returns {import('#types').IExtension | undefined} */ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { const io = new _BpmnIO.BpmnIO(activity, this); @@ -341,7 +346,6 @@ function Extensions(activity, context, extensions) { const extension = Extension(activity, context); if (extension) result.push(extension); } - /** @private */ this[_constants.K_ACTIVATED] = false; } Object.defineProperty(Extensions.prototype, 'count', { @@ -351,13 +355,11 @@ Object.defineProperty(Extensions.prototype, 'count', { }); Extensions.prototype.activate = function activate(message) { if (this[_constants.K_ACTIVATED]) return; - /** @private */ this[_constants.K_ACTIVATED] = true; for (const extension of this.extensions) extension.activate(message); }; Extensions.prototype.deactivate = function deactivate(message) { if (!this[_constants.K_ACTIVATED]) return; - /** @private */ this[_constants.K_ACTIVATED] = false; for (const extension of this.extensions) extension.deactivate(message); }; \ No newline at end of file diff --git a/dist/Environment.js b/dist/Environment.js index 2692bdec..1f581be7 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -14,7 +14,7 @@ const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', /** * Holds global execution config: variables, injected services, timers, scripts engine, * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * @param {import('types').EnvironmentOptions} [options] + * @param {import('#types').EnvironmentOptions} [options] */ function Environment(options = {}) { this.options = validateOptions(options); @@ -28,28 +28,26 @@ function Environment(options = {}) { ...options.settings }; this.Logger = options.Logger || DummyLogger; - /** @private */ this[K_SERVICES] = options.services || {}; - /** @private */ this[K_VARIABLES] = options.variables || {}; } -Object.defineProperties(Environment.prototype, { - variables: { - get() { - return this[K_VARIABLES]; - } +Object.defineProperty(Environment.prototype, 'variables', { + /** @returns {Record} */ + get() { + return this[K_VARIABLES]; + } +}); +Object.defineProperty(Environment.prototype, 'services', { + /** @returns {Record} */ + get() { + return this[K_SERVICES]; }, - services: { - get() { - return this[K_SERVICES]; - }, - set(value) { - const services = this[K_SERVICES]; - for (const name in services) { - if (!(name in value)) delete services[name]; - } - Object.assign(services, value); + set(value) { + const services = this[K_SERVICES]; + for (const name in services) { + if (!(name in value)) delete services[name]; } + Object.assign(services, value); } }); @@ -73,7 +71,7 @@ Environment.prototype.getState = function getState() { /** * Restore environment state captured by getState. Merges into the existing settings, * variables, and output rather than replacing them. - * @param {import('types').EnvironmentState} [state] + * @param {import('#types').EnvironmentState} [state] * @returns {this} */ Environment.prototype.recover = function recover(state) { @@ -87,7 +85,7 @@ Environment.prototype.recover = function recover(state) { /** * Clone the environment, optionally overriding options. Services are merged when * `overrideOptions.services` is supplied. - * @param {import('types').EnvironmentOptions} [overrideOptions] + * @param {import('#types').EnvironmentOptions} [overrideOptions] */ Environment.prototype.clone = function clone(overrideOptions) { const services = this[K_SERVICES]; @@ -120,8 +118,6 @@ Environment.prototype.clone = function clone(overrideOptions) { */ Environment.prototype.assignVariables = function assignVariables(newVars) { if (!newVars || typeof newVars !== 'object') return; - - /** @private */ this[K_VARIABLES] = { ...this.variables, ...newVars @@ -130,7 +126,7 @@ Environment.prototype.assignVariables = function assignVariables(newVars) { /** * Merge settings into the environment. Non-objects are ignored. - * @param {import('types').EnvironmentSettings} newSettings + * @param {import('#types').EnvironmentSettings} newSettings * @returns {this} */ Environment.prototype.assignSettings = function assignSettings(newSettings) { @@ -170,7 +166,7 @@ Environment.prototype.getServiceByName = function getServiceByName(serviceName) /** * Resolve an expression with the environment as scope, optionally extended by an element message. * @param {string} expression - * @param {import('types').ElementBrokerMessage} [message] Element message merged onto the resolution scope + * @param {import('#types').ElementBrokerMessage} [message] Element message merged onto the resolution scope * @param {any} [expressionFnContext] */ Environment.prototype.resolveExpression = function resolveExpression(expression, message, expressionFnContext) { @@ -187,7 +183,6 @@ Environment.prototype.resolveExpression = function resolveExpression(expression, * @param {CallableFunction} fn */ Environment.prototype.addService = function addService(name, fn) { - /** @private */ this[K_SERVICES][name] = fn; }; function validateOptions(input) { @@ -214,6 +209,10 @@ function validateOptions(input) { } return options; } + +/** + * @returns {import('#types').ILogger} + */ function DummyLogger() { return { debug, diff --git a/dist/EventBroker.js b/dist/EventBroker.js index 7b8ef0ed..f5599785 100644 --- a/dist/EventBroker.js +++ b/dist/EventBroker.js @@ -10,9 +10,19 @@ exports.MessageFlowBroker = MessageFlowBroker; exports.ProcessBroker = ProcessBroker; var _smqp = require("smqp"); var _Errors = require("./error/Errors.js"); +/** + * @typedef {object} BrokerApi Shape of the bound event helpers exposed by an EventBroker + * (and inherited by every element class that destructures from one). + * @property {(eventName: string, callback: CallableFunction, eventOptions?: { once?: boolean, [x: string]: any }) => import('smqp').Consumer} on + * @property {(eventName: string, callback: CallableFunction, eventOptions?: { [x: string]: any }) => import('smqp').Consumer} once + * @property {(eventName: string, onMessage?: (routingKey: string, message: import('#types').ElementBrokerMessage, owner: any) => boolean) => Promise} waitFor + * @property {(eventName: string, content?: Record, props?: any) => void} emit + * @property {(error: Error, content?: Record) => void} emitFatal + */ + /** * Build the broker for an activity, including run/format/execution/api exchanges and queues. - * @param {import('types').Activity} activity + * @param {import('#types').Activity} activity */ function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); @@ -21,7 +31,7 @@ function ActivityBroker(activity) { /** * Build the broker for a process, with an additional api-q bound to all api routing keys. - * @param {import('types').Process} owner + * @param {import('#types').Process} owner */ function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); @@ -35,8 +45,8 @@ function ProcessBroker(owner) { /** * Build the broker for a definition. Optionally registers a custom return-message handler. - * @param {import('types').Definition} owner - * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] + * @param {import('#types').Definition} owner + * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] */ function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); @@ -44,7 +54,7 @@ function DefinitionBroker(owner, onBrokerReturn) { /** * Build the broker for a message flow with a durable message exchange and message-q. - * @param {import('types').MessageFlow} owner + * @param {import('#types').MessageFlow} owner */ function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { @@ -110,7 +120,7 @@ function ExecutionBroker(brokerOwner, prefix, onBrokerReturn) { * Owns an smqp Broker on behalf of the calling element and exposes prefixed event helpers. * @param {any} brokerOwner Element that owns the broker, accessed as `broker.owner` * @param {{ prefix: string, autoDelete?: boolean, durable?: boolean }} options - * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] Override for unrouted return messages + * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] Override for unrouted return messages */ function EventBroker(brokerOwner, options, onBrokerReturn) { this.options = options; @@ -118,19 +128,23 @@ function EventBroker(brokerOwner, options, onBrokerReturn) { const broker = this.broker = new _smqp.Broker(brokerOwner); broker.assertExchange('event', 'topic', options); broker.on('return', onBrokerReturn ? onBrokerReturn.bind(brokerOwner) : this._onBrokerReturnFn.bind(this)); + + /** @type {BrokerApi['on']} */ this.on = this.on.bind(this); + /** @type {BrokerApi['once']} */ this.once = this.once.bind(this); + /** @type {BrokerApi['waitFor']} */ this.waitFor = this.waitFor.bind(this); + /** @type {BrokerApi['emit']} */ this.emit = this.emit.bind(this); + /** @type {BrokerApi['emitFatal']} */ this.emitFatal = this.emitFatal.bind(this); } /** * Subscribe to a prefixed event. Errors are unwrapped via `makeErrorFromMessage`, * other events resolve to the owner's Api wrapper. - * @param {string} eventName Bare name (e.g. `enter`) or a full routing key - * @param {CallableFunction} callback - * @param {{ once?: boolean, [x: string]: any }} [eventOptions] + * @type {BrokerApi['on']} */ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { once: false @@ -149,9 +163,7 @@ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { /** * Subscribe to the next occurrence of an event. - * @param {string} eventName - * @param {CallableFunction} callback - * @param {any} [eventOptions] + * @type {BrokerApi['once']} */ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { return this.on(eventName, callback, { @@ -162,9 +174,7 @@ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { /** * Promise-style wait for an event. Rejects on a mandatory `*.error` message. - * @param {string} eventName - * @param {(routingKey: string, message: import('types').ElementBrokerMessage, owner: any) => boolean | undefined} [onMessage] - * Filter; the promise only resolves when it returns truthy + * @type {BrokerApi['waitFor']} */ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { const key = this._getEventRoutingKey(eventName); @@ -194,9 +204,7 @@ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { /** * Publish a prefixed event message. - * @param {string} eventName - * @param {Record} [content] - * @param {any} [props] + * @type {BrokerApi['emit']} */ EventBroker.prototype.emit = function emit(eventName, content, props) { this.broker.publish('event', `${this.eventPrefix}.${eventName}`, { @@ -209,8 +217,7 @@ EventBroker.prototype.emit = function emit(eventName, content, props) { /** * Emit a mandatory error event. Surfaces via `on('error', ...)` or causes a return message to throw. - * @param {Error} error - * @param {Record} [content] + * @type {BrokerApi['emitFatal']} */ EventBroker.prototype.emitFatal = function emitFatal(error, content) { this.emit('error', { diff --git a/dist/MessageFormatter.js b/dist/MessageFormatter.js index 0776413a..81b62b19 100644 --- a/dist/MessageFormatter.js +++ b/dist/MessageFormatter.js @@ -16,7 +16,7 @@ const EXEC_ROUTING_KEY = 'run._formatting.exec'; * Enriches an element run message via async format start/end messages on the `format` exchange * before the run message is continued. Handlers publish enrichment by responding to a start * message with a matching end (or error) routing key. - * @param {import('types').ElementBase} element + * @param {import('#types').ElementBase} element */ function Formatter(element) { const { @@ -27,15 +27,14 @@ function Formatter(element) { this.id = id; this.broker = broker; this.logger = logger; - /** @private */ this[K_ON_MESSAGE] = this._onMessage.bind(this); } /** * Format the given run message. Callback fires with `(err, content, formatted)` once * formatting completes; `formatted` is true when content was actually enriched. - * @param {import('types').ElementBrokerMessage} message - * @param {(err: Error | null, content?: import('types').ElementMessageContent, formatted?: boolean) => void} callback + * @param {import('#types').ElementBrokerMessage} message + * @param {(err: Error | null, content?: import('#types').ElementMessageContent, formatted?: boolean) => void} callback */ Formatter.prototype.format = function format(message, callback) { const correlationId = this._runId = (0, _shared.getUniqueId)(message.fields.routingKey); @@ -45,8 +44,6 @@ Formatter.prototype.format = function format(message, callback) { correlationId, persistent: false }); - - /** @private */ this[_constants.K_EXECUTION] = { correlationId, formatKey: message.fields.routingKey, @@ -77,7 +74,6 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { if (!asyncFormatting) { return this._complete(message); } - /** @private */ this[_constants.K_EXECUTION].executeMessage = message; } else { message.ack(); @@ -110,7 +106,6 @@ Formatter.prototype._complete = function complete(message, isError) { formatted, executeMessage } = this[_constants.K_EXECUTION]; - /** @private */ this[_constants.K_EXECUTION] = null; if (executeMessage) executeMessage.ack(); this.broker.cancel(message.fields.consumerTag); @@ -143,7 +138,6 @@ Formatter.prototype._enrich = function enrich(withContent) { default: { content[key] = withContent[key]; - /** @private */ this[_constants.K_EXECUTION].formatted = true; } } diff --git a/dist/Timers.js b/dist/Timers.js index aaab99a6..de4a9669 100644 --- a/dist/Timers.js +++ b/dist/Timers.js @@ -14,7 +14,6 @@ function Timers(options) { clearTimeout, ...options }; - /** @private */ this[K_EXECUTING] = new Set(); this.setTimeout = this.setTimeout.bind(this); this.clearTimeout = this.clearTimeout.bind(this); @@ -54,7 +53,6 @@ Timers.prototype._getReference = function getReference(owner, callback, delay, a return new Timer(owner, `timer_${this.count++}`, callback, delay, args); }; function RegisteredTimers(timersApi, owner) { - /** @private */ this[K_TIMER_API] = timersApi; this.owner = owner; this.setTimeout = this.setTimeout.bind(this); @@ -65,7 +63,6 @@ RegisteredTimers.prototype.setTimeout = function registeredSetTimeout(callback, return timersApi._setTimeout(this.owner, callback, delay, ...args); }; RegisteredTimers.prototype.clearTimeout = function registeredClearTimeout(ref) { - /** @private */ this[K_TIMER_API].clearTimeout(ref); }; function Timer(owner, timerId, callback, delay, args) { diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 1a30c8a8..9f42972d 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -23,9 +23,9 @@ const K_FORMATTER = Symbol.for('formatter'); /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param {import('types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution + * @param {import('#types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution * @param {import('moddle-context-serializer').SerializableElement} activityDef Parsed BPMN element definition - * @param {import('types').ContextInstance} context Per-execution registry and factory + * @param {import('#types').ContextInstance} context Per-execution registry and factory */ function Activity(Behaviour, activityDef, context) { const { @@ -38,8 +38,6 @@ function Activity(Behaviour, activityDef, context) { attachedTo: attachedToRef, eventDefinitions } = behaviour; - - /** @private */ this[K_ACTIVITY_DEF] = activityDef; this.id = id; this.type = type; @@ -49,11 +47,13 @@ function Activity(Behaviour, activityDef, context) { eventDefinitions }; this.Behaviour = Behaviour; + /** @type {import('moddle-context-serializer').Parent} */ this.parent = activityDef.parent ? (0, _messageHelper.cloneParent)(activityDef.parent) : {}; this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; - /** @private */ + /** @type {import('#types').ActivityRunStatus} */ + this.status = undefined; this[_constants.K_COUNTERS] = { taken: 0, discarded: 0 @@ -91,8 +91,6 @@ function Activity(Behaviour, activityDef, context) { sourceId }) => sourceId)); const isParallelJoin = activityDef.isParallelGateway && inboundSourceIds.size > 1; - - /** @private */ this[K_FLOWS] = { inboundSequenceFlows, inboundAssociations, @@ -100,8 +98,6 @@ function Activity(Behaviour, activityDef, context) { outboundSequenceFlows, outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows) }; - - /** @private */ this[K_FLAGS] = { isEnd: !outboundSequenceFlows.length, isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, @@ -116,24 +112,16 @@ function Activity(Behaviour, activityDef, context) { isCatching: activityDef.isCatching, lane: activityDef.lane?.id }; - /** @private */ this[K_EXEC] = new Map(); - - /** @private */ this[_constants.K_MESSAGE_HANDLERS] = { onInbound: this._onInbound.bind(this), onRunMessage: this._onRunMessage.bind(this), onApiMessage: this._onApiMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this) }; - - /** @private */ this[K_EVENT_DEFINITIONS] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); - /** @private */ this[_constants.K_EXTENSIONS] = context.loadExtensions(this); - /** @private */ this[_constants.K_CONSUMING] = false; - /** @private */ this[K_CONSUMING_RUN_Q] = undefined; } Object.defineProperties(Activity.prototype, { @@ -273,10 +261,10 @@ Object.defineProperties(Activity.prototype, { /** * Subscribe to inbound flows and start consuming the inbound queue. + * @returns {void} */ Activity.prototype.activate = function activate() { if (this[_constants.K_ACTIVATED]) return; - /** @private */ this[_constants.K_ACTIVATED] = true; return this.addInboundListeners() && this._consumeInbound(); }; @@ -285,7 +273,6 @@ Activity.prototype.activate = function activate() { * Cancel inbound subscriptions and any pending run/format consumers. */ Activity.prototype.deactivate = function deactivate() { - /** @private */ this[_constants.K_ACTIVATED] = false; const broker = this.broker; this.removeInboundListeners(); @@ -329,8 +316,6 @@ Activity.prototype.run = function run(runContent) { const broker = this.broker; broker.publish('run', 'run.enter', content); broker.publish('run', 'run.start', (0, _messageHelper.cloneContent)(content)); - - /** @private */ this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; @@ -338,6 +323,7 @@ Activity.prototype.run = function run(runContent) { /** * Snapshot activity state for recover. * Returns undefined when nothing is running and `disableTrackState` is set. + * @returns {import('#types').ActivityState} */ Activity.prototype.getState = function getState() { const status = this.status; @@ -364,7 +350,7 @@ Activity.prototype.getState = function getState() { /** * Restore activity state captured by getState. Cannot be called while running. - * @param {import('types').ActivityState} [state] + * @param {import('#types').ActivityState} [state] * @returns {this} this when state was applied * @throws {Error} when activity is currently running */ @@ -375,8 +361,6 @@ Activity.prototype.recover = function recover(state) { this.status = state.status; const exec = this[K_EXEC]; exec.set('executionId', state.executionId); - - /** @private */ this[_constants.K_COUNTERS] = { ...this[_constants.K_COUNTERS], ...state.counters @@ -403,8 +387,6 @@ Activity.prototype.resume = function resume() { this.broker.publish('run', 'run.resume', content, { persistent: false }); - - /** @private */ this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; @@ -421,7 +403,6 @@ Activity.prototype.discard = function discard(discardContent) { const broker = this.broker; broker.getQueue('run-q').purge(); broker.publish('run', 'run.discard', (0, _messageHelper.cloneContent)(this[_constants.K_STATE_MESSAGE].content)); - /** @private */ this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; @@ -480,6 +461,7 @@ Activity.prototype.stop = function stop() { */ Activity.prototype.next = function next() { if (!this.environment.settings.step) return; + /** @type {import('#types').ElementBrokerMessage} */ const stateMessage = this[_constants.K_STATE_MESSAGE]; if (!stateMessage) return; if (this.status === 'executing') return false; @@ -500,9 +482,10 @@ Activity.prototype.shake = function shake() { /** * Evaluate outbound sequence flows for the given source message. - * @param {import('types').ElementBrokerMessage} fromMessage Source run message + * @param {import('#types').ElementBrokerMessage} fromMessage Source run message * @param {boolean} discardRestAtTake When true, take only the first matching flow and discard the rest * @param {(err: Error, evaluationResult: any) => void} callback + * @returns {void} */ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) { return this[K_FLOWS].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); @@ -510,7 +493,8 @@ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, dis /** * Resolve an Api wrapper for the activity, preferring the running execution if any. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ Activity.prototype.getApi = function getApi(message) { const execution = this[K_EXEC].get('execution'); @@ -538,8 +522,6 @@ Activity.prototype._runDiscard = function runDiscard(discardContent) { executionId }); this.broker.publish('run', 'run.discard', content); - - /** @private */ this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; @@ -571,7 +553,6 @@ Activity.prototype._discardRun = function discardRun() { broker.publish('run', discardRoutingKey, (0, _messageHelper.cloneContent)(stateMessage.content), { correlationId: stateMessage.properties.correlationId }); - /** @private */ this[_constants.K_CONSUMING] = true; this._consumeRunQ(); }; @@ -695,7 +676,6 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message /** @internal */ Activity.prototype._consumeRunQ = function consumeRunQ() { - /** @private */ this[K_CONSUMING_RUN_Q] = true; this.broker.getQueue('run-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onRunMessage, { exclusive: true, @@ -706,8 +686,6 @@ Activity.prototype._consumeRunQ = function consumeRunQ() { /** @internal */ Activity.prototype._pauseRunQ = function pauseRunQ() { if (!this[K_CONSUMING_RUN_Q]) return; - - /** @private */ this[K_CONSUMING_RUN_Q] = false; this.broker.cancel('_activity-run'); }; @@ -744,7 +722,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, const correlationId = message.properties.correlationId; const id = this.id; const step = this.environment.settings.step; - /** @private */ this[_constants.K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': @@ -752,7 +729,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, this.logger.debug(`<${id}> enter`, isRedelivered ? 'redelivered' : ''); this.status = 'entered'; if (!isRedelivered) { - /** @private */ this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate((0, _messageHelper.cloneMessage)(message)); this._publishEvent('enter', content, { @@ -765,7 +741,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, { this.logger.debug(`<${id}> discard`, isRedelivered ? 'redelivered' : ''); this.status = 'discard'; - /** @private */ this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate((0, _messageHelper.cloneMessage)(message)); if (!isRedelivered) { @@ -795,7 +770,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, const execution = this[K_EXEC].get('execution'); if (!isRedelivered && execution) { if (execution.completed) return message.ack(); - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = message; return execution.passthrough(message); } @@ -803,7 +777,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, case 'run.execute': { this.status = 'executing'; - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = message; if (isRedelivered && this.extensions) this.extensions.activate((0, _messageHelper.cloneMessage)(message)); const exec = this[K_EXEC]; @@ -822,8 +795,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, { this.logger.debug(`<${id}> end`, isRedelivered ? 'redelivered' : ''); if (isRedelivered) break; - - /** @private */ this[_constants.K_COUNTERS].taken++; this.status = 'end'; return this._doRunLeave(message, false, () => { @@ -846,7 +817,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, case 'run.discarded': { this.logger.debug(`<${content.executionId} (${id})> discarded`); - /** @private */ this[_constants.K_COUNTERS].discarded++; this.status = 'discarded'; content.outbound = undefined; @@ -1098,8 +1068,6 @@ Activity.prototype._publishEvent = function publishEvent(state, content, propert Activity.prototype._onStop = function onStop(message) { const running = this[_constants.K_CONSUMING]; this.stopped = true; - - /** @private */ this[_constants.K_CONSUMING] = false; const broker = this.broker; this._pauseRunQ(); @@ -1184,6 +1152,5 @@ Activity.prototype._deactivateRunConsumers = function _deactivateRunConsumers() broker.cancel('_activity-api'); this._pauseRunQ(); broker.cancel('_activity-execution'); - /** @private */ this[_constants.K_CONSUMING] = false; }; \ No newline at end of file diff --git a/dist/activity/ActivityExecution.js b/dist/activity/ActivityExecution.js index 7fd1b6a3..41635bde 100644 --- a/dist/activity/ActivityExecution.js +++ b/dist/activity/ActivityExecution.js @@ -13,25 +13,20 @@ const K_POSTPONED = Symbol.for('postponed'); /** * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour * and drives the execute message flow over the activity broker. - * @param {import('types').Activity} activity - * @param {import('types').ContextInstance} context + * @param {import('./Activity.js').Activity} activity + * @param {import('../Context.js').ContextInstance} context */ function ActivityExecution(activity, context) { this.activity = activity; this.context = context; this.id = activity.id; this.broker = activity.broker; - /** @private */ this[K_POSTPONED] = new Set(); - /** @private */ this[_constants.K_COMPLETED] = false; - /** @private */ this[K_EXECUTE_Q] = this.broker.assertQueue('execute-q', { durable: true, autoDelete: false }); - - /** @private */ this[_constants.K_MESSAGE_HANDLERS] = { onParentApiMessage: this._onParentApiMessage.bind(this), onExecuteMessage: this._onExecuteMessage.bind(this) @@ -46,7 +41,7 @@ Object.defineProperty(ActivityExecution.prototype, 'completed', { /** * Begin executing the activity behaviour. Resumes if the message is redelivered. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage * @throws {Error} when message or executionId is missing */ ActivityExecution.prototype.execute = function execute(executeMessage) { @@ -60,7 +55,6 @@ ActivityExecution.prototype.execute = function execute(executeMessage) { isRootScope: true }); if (executeMessage.fields.redelivered) { - /** @private */ this[K_POSTPONED].clear(); this._debug('resume execution'); if (!this.source) this.source = new this.activity.Behaviour(this.activity, this.context); @@ -89,7 +83,6 @@ ActivityExecution.prototype.activate = function activate() { onExecuteMessage, onParentApiMessage } = this[_constants.K_MESSAGE_HANDLERS]; - /** @private */ this[K_EXECUTE_Q].assertConsumer(onExecuteMessage, { exclusive: true, prefetch: batchSize * 2, @@ -126,7 +119,8 @@ ActivityExecution.prototype.discard = function discard() { /** * Resolve an Api wrapper, preferring a behaviour-specific Api when the source exposes one. - * @param {import('types').ElementBrokerMessage} [apiMessage] + * @param {import('#types').ElementBrokerMessage} [apiMessage] + * @returns {import('#types').IApi} */ ActivityExecution.prototype.getApi = function getApi(apiMessage) { const self = this; @@ -149,7 +143,7 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { /** * Pass an execute message straight to the behaviour, executing first if no source is set up yet. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage */ ActivityExecution.prototype.passthrough = function passthrough(executeMessage) { if (!this.source) return this.execute(executeMessage); @@ -186,11 +180,10 @@ ActivityExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. - * @param {import('types').ActivityExecutionState} [state] + * @param {import('#types').ActivityExecutionState} [state] * @returns {this} */ ActivityExecution.prototype.recover = function recover(state) { - /** @private */ this[K_POSTPONED].clear(); if (!state) return this; if ('completed' in state) this[_constants.K_COMPLETED] = state.completed; @@ -324,7 +317,6 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete return; } this._debug('completed execution', executionId); - /** @private */ this[_constants.K_COMPLETED] = true; message.ack(true); this.deactivate(); @@ -369,7 +361,6 @@ ActivityExecution.prototype._onExecutionDiscarded = function onExecutionDiscarde /** @internal */ ActivityExecution.prototype._publishExecutionCompleted = function publishExecutionCompleted(completionType, completeContent, correlationId) { - /** @private */ this[_constants.K_COMPLETED] = true; this.broker.publish('execution', `execution.${completionType}`, { ...completeContent, diff --git a/dist/condition.js b/dist/condition.js index 8be0857e..fa60ce9c 100644 --- a/dist/condition.js +++ b/dist/condition.js @@ -8,7 +8,7 @@ exports.ScriptCondition = ScriptCondition; var _ExecutionScope = require("./activity/ExecutionScope.js"); /** * Script condition - * @param {import('types').ElementBase} owner + * @param {import('#types').ElementBase} owner * @param {any} script * @param {string} language */ @@ -37,7 +37,7 @@ ScriptCondition.prototype.execute = function execute(message, callback) { /** * Expression condition - * @param {import('types').ElementBase} owner + * @param {import('#types').ElementBase} owner * @param {string} expression */ function ExpressionCondition(owner, expression) { @@ -48,7 +48,7 @@ function ExpressionCondition(owner, expression) { /** * Execute - * @param {any} message + * @param {import('#types').ElementBrokerMessage} message * @param {CallableFunction} callback */ ExpressionCondition.prototype.execute = function execute(message, callback) { diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index af1654d8..627a3a02 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -14,8 +14,8 @@ var _constants = require("../constants.js"); /** * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and * mediates inter-process messaging. - * @param {import('types').ContextInstance} context - * @param {import('types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged + * @param {import('../Context.js').ContextInstance} context + * @param {import('#types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged */ function Definition(context, options) { if (!(this instanceof Definition)) return new Definition(context, options); @@ -36,19 +36,13 @@ function Definition(context, options) { environment = this.environment = context.environment; this.context = context; } - - /** @private */ this[_constants.K_COUNTERS] = { completed: 0, discarded: 0 }; - - /** @private */ this[_constants.K_STOPPED] = false; - /** @private */ this[_constants.K_EXECUTION] = new Map(); const onBrokerReturn = this._onBrokerReturnFn.bind(this); - /** @private */ this[_constants.K_MESSAGE_HANDLERS] = { onBrokerReturn, onApiMessage: this._onApiMessage.bind(this), @@ -70,6 +64,8 @@ function Definition(context, options) { this.waitFor = waitFor; this.emit = emit; this.emitFatal = emitFatal; + + /** @type {import('#types').ILogger} */ this.logger = environment.Logger(type.toLowerCase()); } Object.defineProperties(Definition.prototype, { @@ -117,8 +113,8 @@ Object.defineProperties(Definition.prototype, { /** * Start running the definition. Accepts run options, a callback, or both. * The callback fires once on leave, stop, or error. - * @param {Record | import('types').runCallback} [optionsOrCallback] - * @param {import('types').runCallback} [optionalCallback] + * @param {Record | import('#types').runCallback} [optionsOrCallback] + * @param {import('#types').runCallback} [optionalCallback] * @returns {this} * @throws {Error} when already running and no callback is supplied */ @@ -150,7 +146,7 @@ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { /** * Resume after recover by republishing the last run message. The callback fires once on * leave, stop, or error. - * @param {import('types').runCallback} [callback] + * @param {import('#types').runCallback} [callback] * @returns {this} */ Definition.prototype.resume = function resume(callback) { @@ -159,8 +155,6 @@ Definition.prototype.resume = function resume(callback) { if (callback) return callback(err); throw err; } - - /** @private */ this[_constants.K_STOPPED] = false; if (!this.status) return this; if (callback) { @@ -191,22 +185,18 @@ Definition.prototype.getState = function getState() { /** * Restore definition state captured by getState. - * @param {import('types').DefinitionState} [state] + * @param {import('#types').DefinitionState} [state] * @returns {this} * @throws {Error} when called on a running definition */ Definition.prototype.recover = function recover(state) { if (this.isRunning) throw new Error('cannot recover running definition'); if (!state) return this; - - /** @private */ this[_constants.K_STOPPED] = !!state.stopped; - /** @private */ this[_constants.K_STATUS] = state.status; const exec = this[_constants.K_EXECUTION]; exec.set('executionId', state.executionId); if (state.counters) { - /** @private */ this[_constants.K_COUNTERS] = { ...this[_constants.K_COUNTERS], ...state.counters @@ -318,7 +308,7 @@ Definition.prototype.getElementById = function getElementById(elementId) { /** * List currently postponed activities as Api wrappers. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ Definition.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; @@ -328,7 +318,8 @@ Definition.prototype.getPostponed = function getPostponed(...args) { /** * Resolve a Definition Api wrapper, preferring the running execution if any. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} * @throws {Error} when the definition is not running and no message is given */ Definition.prototype.getApi = function getApi(message) { @@ -341,7 +332,7 @@ Definition.prototype.getApi = function getApi(message) { /** * Send a delegated signal to the running definition. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Definition.prototype.signal = function signal(message) { return this.getApi().signal(message, { @@ -351,7 +342,7 @@ Definition.prototype.signal = function signal(message) { /** * Cancel a running activity inside the definition by delegated api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Definition.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { @@ -395,7 +386,6 @@ Definition.prototype.stop = function stop() { /** @internal */ Definition.prototype._activateRunConsumers = function activateRunConsumers() { - /** @private */ this[_constants.K_CONSUMING] = true; const broker = this.broker; const { @@ -418,7 +408,6 @@ Definition.prototype._deactivateRunConsumers = function deactivateRunConsumers() broker.cancel('_definition-api'); broker.cancel('_definition-run'); broker.cancel('_definition-execution'); - /** @private */ this[_constants.K_CONSUMING] = false; }; @@ -443,14 +432,11 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) return this._onResumeMessage(message); } const exec = this[_constants.K_EXECUTION]; - /** @private */ this[_constants.K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this.logger.debug(`<${this.executionId} (${this.id})> enter`); - - /** @private */ this[_constants.K_STATUS] = 'entered'; if (fields.redelivered) break; exec.delete('execution'); @@ -460,21 +446,18 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) case 'run.start': { this.logger.debug(`<${this.executionId} (${this.id})> start`); - /** @private */ this[_constants.K_STATUS] = 'start'; this._publishEvent('start', content); break; } case 'run.execute': { - /** @private */ this[_constants.K_STATUS] = 'executing'; const executeMessage = (0, _messageHelper.cloneMessage)(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = message; this.broker.getQueue('execution-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, @@ -492,11 +475,8 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) case 'run.end': { if (this[_constants.K_STATUS] === 'end') break; - - /** @private */ this[_constants.K_COUNTERS].completed++; this.logger.debug(`<${this.executionId} (${this.id})> completed`); - /** @private */ this[_constants.K_STATUS] = 'end'; this.broker.publish('run', 'run.leave', content); this._publishEvent('end', content); @@ -515,11 +495,7 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) case 'run.discarded': { if (this[_constants.K_STATUS] === 'discarded') break; - - /** @private */ this[_constants.K_COUNTERS].discarded++; - - /** @private */ this[_constants.K_STATUS] = 'discarded'; this.broker.publish('run', 'run.leave', content); break; @@ -527,7 +503,6 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) case 'run.leave': { message.ack(); - /** @private */ this[_constants.K_STATUS] = undefined; this._deactivateRunConsumers(); this._publishEvent('leave', this._createMessage()); @@ -579,7 +554,6 @@ Definition.prototype._onExecutionMessage = function onExecutionMessage(routingKe } } const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; @@ -605,7 +579,6 @@ Definition.prototype._publishEvent = function publishEvent(action, content, msgO /** @internal */ Definition.prototype._onStop = function onStop() { - /** @private */ this[_constants.K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop', this._createMessage()); @@ -622,7 +595,6 @@ Definition.prototype._onBrokerReturnFn = function onBrokerReturn(message) { /** @internal */ Definition.prototype._reset = function reset() { - /** @private */ this[_constants.K_EXECUTION].delete('executionId'); this._deactivateRunConsumers(); this.broker.purgeQueue('run-q'); diff --git a/dist/definition/DefinitionExecution.js b/dist/definition/DefinitionExecution.js index 42acb97d..5f814fe5 100644 --- a/dist/definition/DefinitionExecution.js +++ b/dist/definition/DefinitionExecution.js @@ -15,13 +15,11 @@ const K_PROCESSES = Symbol.for('processes'); /** * Drives the execution of a Definition. Activates executable processes, routes inter-process * delegate messages and call activity hand-offs, and rolls completion up to the Definition. - * @param {import('types').Definition} definition - * @param {import('types').ContextInstance} context + * @param {import('./Definition.js').Definition} definition + * @param {import('../Context.js').ContextInstance} context */ function DefinitionExecution(definition, context) { const broker = definition.broker; - - /** @private */ this[K_PARENT] = definition; this.id = definition.id; this.type = definition.type; @@ -31,7 +29,7 @@ function DefinitionExecution(definition, context) { const processes = context.getProcesses(); /** @type {Set} */ const ids = new Set(); - /** @type {Set} */ + /** @type {Set} */ const executable = new Set(); for (const bp of processes) { bp.environment.assignVariables(environment.variables); @@ -39,16 +37,14 @@ function DefinitionExecution(definition, context) { ids.add(bp.id); if (bp.isExecutable) executable.add(bp); } - - /** @private */ this[K_PROCESSES] = { /** @type {import('../process/Process.js').Process[]} */ processes, ids, executable, - /** @type {Set} */ + /** @type {Set} */ running: new Set(), - /** @type {Set} */ + /** @type {Set} */ postponed: new Set() }; broker.assertExchange('execution', 'topic', { @@ -56,18 +52,11 @@ function DefinitionExecution(definition, context) { durable: true }); this.executionId = undefined; - /** @private */ this[_constants.K_COMPLETED] = false; - /** @private */ this[_constants.K_STOPPED] = false; - /** @private */ this[_constants.K_ACTIVATED] = false; - /** @private */ this[_constants.K_STATUS] = 'init'; - /** @private */ this[K_PROCESSES_Q] = undefined; - - /** @private */ this[_constants.K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onCallActivity: this._onCallActivity.bind(this), @@ -137,7 +126,7 @@ Object.defineProperties(DefinitionExecution.prototype, { /** * Activate executable processes and start the definition execution. Resumes if the message * is redelivered. When `content.processId` is set, only that process is started. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage * @throws {Error} when message or executionId is missing */ DefinitionExecution.prototype.execute = function execute(executeMessage) { @@ -145,17 +134,11 @@ DefinitionExecution.prototype.execute = function execute(executeMessage) { const content = executeMessage.content; const executionId = this.executionId = content.executionId; if (!executionId) throw new Error('Definition execution requires execution id'); - - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage, { executionId, state: 'start' }); - - /** @private */ this[_constants.K_STOPPED] = false; - - /** @private */ this[K_PROCESSES_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false @@ -195,7 +178,6 @@ DefinitionExecution.prototype.resume = function resume() { } = this[K_PROCESSES]; this._activate(running); postponed.clear(); - /** @private */ this[K_PROCESSES_Q].consume(this[_constants.K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}` @@ -206,18 +188,14 @@ DefinitionExecution.prototype.resume = function resume() { /** * Restore execution state captured by getState. Reinstates running processes from the snapshot. - * @param {import('types').DefinitionExecutionState} [state] + * @param {import('#types').DefinitionExecutionState} [state] * @returns {this} */ DefinitionExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - - /** @private */ this[_constants.K_STOPPED] = state.stopped; - /** @private */ this[_constants.K_COMPLETED] = state.completed; - /** @private */ this[_constants.K_STATUS] = state.status; this._debug(`recover ${this[_constants.K_STATUS]} definition execution`); const running = this[K_PROCESSES].running; @@ -318,7 +296,8 @@ DefinitionExecution.prototype.getState = function getState() { /** * Resolve a Definition Api or, when the message belongs to a child process, its process Api. - * @param {import('types').ElementBrokerMessage} [apiMessage] + * @param {import('#types').ElementBrokerMessage} [apiMessage] + * @returns {import('#types').IApi} */ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { if (!apiMessage) apiMessage = this[_constants.K_EXECUTE_MESSAGE] || { @@ -344,7 +323,7 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { /** * List currently postponed activities across every running process. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { let result = []; @@ -369,13 +348,10 @@ DefinitionExecution.prototype._start = function start() { error: new Error('No executable process') }); } - - /** @private */ this[_constants.K_STATUS] = 'start'; for (const bp of executable) bp.init(); for (const bp of executable) bp.run(); postponed.clear(); - /** @private */ this[K_PROCESSES_Q].assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}` @@ -389,7 +365,6 @@ DefinitionExecution.prototype._activate = function activate(processList) { consumerTag: '_definition-api-consumer' }); for (const bp of processList) this._activateProcess(bp); - /** @private */ this[_constants.K_ACTIVATED] = true; }; @@ -448,8 +423,6 @@ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, mandatory: false }); if (!isDirectChild) return; - - /** @private */ this[K_PROCESSES_Q].queueMessage(message.fields, (0, _messageHelper.cloneContent)(content), message.properties); }; @@ -458,7 +431,6 @@ DefinitionExecution.prototype._deactivate = function deactivate() { this.broker.cancel('_definition-api-consumer'); this.broker.cancel(`_definition-activity-${this.executionId}`); for (const bp of this[K_PROCESSES].running) this._deactivateProcess(bp); - /** @private */ this[_constants.K_ACTIVATED] = false; }; @@ -494,7 +466,6 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout this._stateChangeMessage(message, true); switch (routingKey) { case 'process.enter': - /** @private */ this[_constants.K_STATUS] = 'executing'; break; case 'process.discarded': @@ -593,12 +564,9 @@ DefinitionExecution.prototype._onProcessCompleted = function onProcessCompleted( DefinitionExecution.prototype._onStopped = function onStopped(message) { const running = this[K_PROCESSES].running; this._debug(`stop definition execution (stop process executions ${running.size})`); - /** @private */ this[K_PROCESSES_Q].close(); for (const bp of new Set(running)) bp.stop(); this._deactivate(); - - /** @private */ this[_constants.K_STOPPED] = true; return this.broker.publish('execution', `execution.stopped.${this.executionId}`, (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { ...message.content @@ -626,7 +594,6 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, } if (this.executionId !== message.content.executionId) return; if (messageType === 'stop') { - /** @private */ this[K_PROCESSES_Q].queueMessage({ routingKey: 'execution.stop' }, (0, _messageHelper.cloneContent)(message.content), { @@ -686,7 +653,6 @@ DefinitionExecution.prototype._onMessageOutbound = function onMessageOutbound(ro if (found) return; targetProcess = targetProcess || this.context.getNewProcessById(target.processId); this._activateProcess(targetProcess); - /** @private */ this[K_PROCESSES].running.add(targetProcess); targetProcess.init(); targetProcess.run(); @@ -721,7 +687,6 @@ DefinitionExecution.prototype._onCallActivity = function onCallActivity(routingK if (!targetProcess) return; this._debug(`call from <${fromParent.id}.${fromId}> to <${calledElement}>`); this._activateProcess(targetProcess); - /** @private */ this[K_PROCESSES].running.add(targetProcess); targetProcess.init(bpExecutionId); targetProcess.run({ @@ -795,9 +760,7 @@ DefinitionExecution.prototype._complete = function complete(completionType, cont const stateMessage = this[_constants.K_EXECUTE_MESSAGE]; this._debug(`definition execution ${completionType} in ${Date.now() - stateMessage.properties.timestamp}ms`); if (!content) content = this._createMessage(); - /** @private */ this[_constants.K_COMPLETED] = true; - /** @private */ this[_constants.K_STATUS] = completionType; this.broker.deleteQueue(this[K_PROCESSES_Q].name); return this.broker.publish('execution', `execution.${completionType}.${this.executionId}`, { @@ -849,6 +812,5 @@ DefinitionExecution.prototype._getProcessApiByExecutionId = function getProcessA /** @internal */ DefinitionExecution.prototype._debug = function debug(logMessage) { - /** @private */ this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; \ No newline at end of file diff --git a/dist/eventDefinitions/CancelEventDefinition.js b/dist/eventDefinitions/CancelEventDefinition.js index c608e687..94569b66 100644 --- a/dist/eventDefinitions/CancelEventDefinition.js +++ b/dist/eventDefinitions/CancelEventDefinition.js @@ -34,9 +34,7 @@ CancelEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { @@ -91,7 +89,6 @@ CancelEventDefinition.prototype._onCatchMessage = function onCatchMessage(_, mes return this._complete(content.message); }; CancelEventDefinition.prototype._complete = function complete(output) { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); this._debug('completed'); @@ -105,7 +102,6 @@ CancelEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey switch (message.properties.type) { case 'discard': { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); const content = (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content); diff --git a/dist/eventDefinitions/CompensateEventDefinition.js b/dist/eventDefinitions/CompensateEventDefinition.js index 7254c959..fb36ef84 100644 --- a/dist/eventDefinitions/CompensateEventDefinition.js +++ b/dist/eventDefinitions/CompensateEventDefinition.js @@ -26,17 +26,13 @@ function CompensateEventDefinition(activity, eventDefinition, context) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); if (!isThrowing) { - /** @private */ this[_constants.K_COMPLETED] = false; - /** @private */ this[K_ASSOCIATIONS] = context.getOutboundAssociations(id); const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-q`; - /** @private */ this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - /** @private */ this[K_COMPENSATE_Q] = broker.assertQueue('compensate-q', { autoDelete: false, durable: true @@ -56,13 +52,10 @@ CompensateEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; CompensateEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[_constants.K_COMPLETED] = false; if (executeMessage.fields.routingKey === 'execute.compensating') { this._debug('resumed at compensating'); - /** @private */ this[_constants.K_COMPLETED] = true; return this._compensate(); } @@ -79,8 +72,6 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute noAck: true, consumerTag: '_oncollect-messages' }); - - /** @private */ this[_constants.K_MESSAGE_Q].consume(this._onCompensateApiMessage.bind(this), { noAck: true, consumerTag: `_oncompensate-${executionId}` @@ -125,7 +116,6 @@ CompensateEventDefinition.prototype._onCollect = function onCollect(routingKey, } }; CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompensateApiMessage(routingKey, message) { - /** @private */ this[_constants.K_COMPLETED] = true; const output = message.content.message; const broker = this.broker; @@ -139,8 +129,6 @@ CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompens executionId: executeContent.parent.executionId }); catchContent.parent = (0, _messageHelper.shiftParent)(catchContent.parent); - - /** @private */ this[K_COMPENSATE_Q].queueMessage({ routingKey: 'execute.compensated' }, (0, _messageHelper.cloneContent)(executeContent)); @@ -171,10 +159,8 @@ CompensateEventDefinition.prototype._onCollected = function onCollected(routingK for (const association of this[K_ASSOCIATIONS]) association.take((0, _messageHelper.cloneMessage)(message)); }; CompensateEventDefinition.prototype._onDiscardApiMessage = function onDiscardApiMessage(routingKey, message) { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); - /** @private */ this[K_COMPENSATE_Q].purge(); for (const association of this[K_ASSOCIATIONS]) association.discard((0, _messageHelper.cloneMessage)(message)); return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); @@ -202,7 +188,6 @@ CompensateEventDefinition.prototype._stopCollect = function stopCollect() { broker.cancel(`_api-${executionId}`); broker.cancel(`_oncompensate-${executionId}`); broker.cancel('_oncollect-messages'); - /** @private */ this[_constants.K_MESSAGE_Q].purge(); }; CompensateEventDefinition.prototype._stop = function stop() { diff --git a/dist/eventDefinitions/ConditionalEventDefinition.js b/dist/eventDefinitions/ConditionalEventDefinition.js index dacccb72..72f25c3c 100644 --- a/dist/eventDefinitions/ConditionalEventDefinition.js +++ b/dist/eventDefinitions/ConditionalEventDefinition.js @@ -33,7 +33,6 @@ Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { } }); ConditionalEventDefinition.prototype.execute = function execute(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; if (!this.condition) return this._setup(executeMessage); this.evaluate(executeMessage, (err, result) => { @@ -76,7 +75,7 @@ ConditionalEventDefinition.prototype._setup = function setup(executeMessage) { /** * Evaluate condition - * @param {import('types').ElementBrokerMessage} message + * @param {import('#types').ElementBrokerMessage} message * @param {CallableFunction} callback */ ConditionalEventDefinition.prototype.evaluate = function evaluate(message, callback) { diff --git a/dist/eventDefinitions/ErrorEventDefinition.js b/dist/eventDefinitions/ErrorEventDefinition.js index 03108f09..c4f11d3e 100644 --- a/dist/eventDefinitions/ErrorEventDefinition.js +++ b/dist/eventDefinitions/ErrorEventDefinition.js @@ -32,11 +32,9 @@ function ErrorEventDefinition(activity, eventDefinition) { this.logger = environment.Logger(type.toLowerCase()); const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing) { - /** @private */ this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - /** @private */ this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true @@ -56,9 +54,7 @@ ErrorEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { @@ -67,8 +63,6 @@ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessa } = executeContent; const parentExecutionId = parent?.executionId; const info = this[_constants.K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage); - - /** @private */ this[_constants.K_MESSAGE_Q].consume(this._onThrowApiMessage.bind(this), { noAck: true, consumerTag: `_onthrow-${executionId}` @@ -148,7 +142,6 @@ ErrorEventDefinition.prototype._onThrowApiMessage = function onThrowApiMessage(r return this._catchError(routingKey, message, error); }; ErrorEventDefinition.prototype._catchError = function catchError(routingKey, message, error) { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); this._debug(`caught ${this[_constants.K_REFERENCE_INFO].description}`); @@ -179,7 +172,6 @@ ErrorEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, switch (messageType) { case 'discard': { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); @@ -197,7 +189,6 @@ ErrorEventDefinition.prototype._stop = function stop() { broker.cancel(`_onthrow-${executionId}`); broker.cancel(`_onerror-${executionId}`); broker.cancel(`_api-${executionId}`); - /** @private */ this[_constants.K_MESSAGE_Q].purge(); }; ErrorEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { diff --git a/dist/eventDefinitions/EscalationEventDefinition.js b/dist/eventDefinitions/EscalationEventDefinition.js index f1a31b07..80fe03e1 100644 --- a/dist/eventDefinitions/EscalationEventDefinition.js +++ b/dist/eventDefinitions/EscalationEventDefinition.js @@ -33,11 +33,9 @@ function EscalationEventDefinition(activity, eventDefinition) { this.logger = environment.Logger(type.toLowerCase()); const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing) { - /** @private */ this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - /** @private */ this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true @@ -57,9 +55,7 @@ EscalationEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; EscalationEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { @@ -68,7 +64,6 @@ EscalationEventDefinition.prototype.executeCatch = function executeCatch(execute } = executeContent; const info = this[K_REFERENCE] = this._getReferenceInfo(executeMessage); const broker = this.broker; - /** @private */ this[_constants.K_MESSAGE_Q].consume(this._onCatchMessage.bind(this), { noAck: true, consumerTag: `_onescalate-${executionId}` @@ -114,7 +109,6 @@ EscalationEventDefinition.prototype._onCatchMessage = function onCatchMessage(ro const info = this[K_REFERENCE]; if ((0, _getPropertyValue.getPropertyValue)(message, 'content.message.id') !== info.message.id) return; const output = message.content.message; - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); this._debug(`caught ${info.description}`); @@ -147,7 +141,6 @@ EscalationEventDefinition.prototype._onApiMessage = function onApiMessage(routin } case 'discard': { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content)); diff --git a/dist/eventDefinitions/EventDefinitionExecution.js b/dist/eventDefinitions/EventDefinitionExecution.js index ffb78d5c..cf7cc962 100644 --- a/dist/eventDefinitions/EventDefinitionExecution.js +++ b/dist/eventDefinitions/EventDefinitionExecution.js @@ -12,23 +12,18 @@ function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKe this.broker = activity.broker; this.eventDefinitions = eventDefinitions; this.completedRoutingKey = completedRoutingKey; - /** @private */ this[_constants.K_COMPLETED] = false; - /** @private */ this[_constants.K_STOPPED] = false; - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = null; } -Object.defineProperties(EventDefinitionExecution.prototype, { - completed: { - get() { - return this[_constants.K_COMPLETED]; - } - }, - stopped: { - get() { - return this[_constants.K_STOPPED]; - } +Object.defineProperty(EventDefinitionExecution.prototype, 'completed', { + get() { + return this[_constants.K_COMPLETED]; + } +}); +Object.defineProperty(EventDefinitionExecution.prototype, 'stopped', { + get() { + return this[_constants.K_STOPPED]; } }); EventDefinitionExecution.prototype.execute = function execute(executeMessage) { @@ -36,8 +31,6 @@ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { if (content.isDefinitionScope) return this._executeDefinition(executeMessage); if (!content.isRootScope) return; const broker = this.broker; - - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const executionId = content.executionId; broker.subscribeTmp('execution', 'execute.#', this._onExecuteMessage.bind(this), { @@ -112,7 +105,6 @@ EventDefinitionExecution.prototype._complete = function complete(message) { index, parent } = message.content; - /** @private */ this[_constants.K_COMPLETED] = true; this._debug(executionId, `event definition ${type} completed, index ${index}`); const completeContent = (0, _messageHelper.cloneContent)(message.content, { @@ -136,7 +128,6 @@ EventDefinitionExecution.prototype._executeDefinition = function executeDefiniti ed.execute(message); }; EventDefinitionExecution.prototype._stop = function stop() { - /** @private */ this[_constants.K_STOPPED] = true; this.broker.cancel('_eventdefinition-execution-execute-tag'); this.broker.cancel('_eventdefinition-execution-api-tag'); diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index d1e46160..c7427b5b 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -73,7 +73,6 @@ LinkEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; const { diff --git a/dist/eventDefinitions/MessageEventDefinition.js b/dist/eventDefinitions/MessageEventDefinition.js index a40e8397..4301253a 100644 --- a/dist/eventDefinitions/MessageEventDefinition.js +++ b/dist/eventDefinitions/MessageEventDefinition.js @@ -32,11 +32,9 @@ function MessageEventDefinition(activity, eventDefinition) { this.logger = environment.Logger(type.toLowerCase()); const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing) { - /** @private */ this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - /** @private */ this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true @@ -55,9 +53,7 @@ MessageEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { @@ -69,7 +65,6 @@ MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMes this._debug(`expect ${info.description}`); const broker = this.broker; const onCatchMessage = this._onCatchMessage.bind(this); - /** @private */ this[_constants.K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-message-${executionId}` @@ -156,7 +151,6 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe } case 'discard': { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content), { @@ -170,7 +164,6 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe } }; MessageEventDefinition.prototype._complete = function complete(verb, output, options) { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); this._debug(`${verb} ${this[_constants.K_REFERENCE_INFO].description}`); @@ -198,7 +191,6 @@ MessageEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-${executionId}`); broker.cancel(`_api-parent-${executionId}`); broker.cancel(`_api-delegated-${executionId}`); - /** @private */ this[_constants.K_MESSAGE_Q].purge(); }; MessageEventDefinition.prototype._getReferenceInfo = function getReferenceInfo(message) { diff --git a/dist/eventDefinitions/SignalEventDefinition.js b/dist/eventDefinitions/SignalEventDefinition.js index 84e77aab..7d239ab6 100644 --- a/dist/eventDefinitions/SignalEventDefinition.js +++ b/dist/eventDefinitions/SignalEventDefinition.js @@ -33,11 +33,9 @@ function SignalEventDefinition(activity, eventDefinition) { this.logger = environment.Logger(type.toLowerCase()); const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); if (!isThrowing && isStart) { - /** @private */ this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; - /** @private */ this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true @@ -56,9 +54,7 @@ SignalEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[_constants.K_COMPLETED] = false; const executeContent = executeMessage.content; const { @@ -70,7 +66,6 @@ SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMess const broker = this.broker; const onCatchMessage = this._onCatchMessage.bind(this); if (this.activity.isStart) { - /** @private */ this[_constants.K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-signal-${executionId}` @@ -127,7 +122,6 @@ SignalEventDefinition.prototype.executeThrow = function executeThrow(executeMess SignalEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { const info = this[_constants.K_REFERENCE_INFO]; if ((0, _getPropertyValue.getPropertyValue)(message, 'content.message.id') !== info.message.id) return; - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); const { @@ -158,7 +152,6 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey } case 'discard': { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content), { @@ -173,7 +166,6 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey } }; SignalEventDefinition.prototype._complete = function complete(output, options) { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); this._debug(`signaled with ${this[_constants.K_REFERENCE_INFO].description}`); diff --git a/dist/eventDefinitions/TimerEventDefinition.js b/dist/eventDefinitions/TimerEventDefinition.js index 61938ce3..e9f64471 100644 --- a/dist/eventDefinitions/TimerEventDefinition.js +++ b/dist/eventDefinitions/TimerEventDefinition.js @@ -26,27 +26,22 @@ function TimerEventDefinition(activity, eventDefinition) { if (timeDate) this.timeDate = timeDate; this.broker = activity.broker; this.logger = environment.Logger(type.toLowerCase()); - - /** @private */ this[_constants.K_STOPPED] = false; - /** @private */ this[K_TIMER] = null; } -Object.defineProperties(TimerEventDefinition.prototype, { - executionId: { - get() { - return this[K_TIMER_CONTENT]?.executionId; - } - }, - stopped: { - get() { - return this[_constants.K_STOPPED]; - } - }, - timer: { - get() { - return this[K_TIMER]; - } +Object.defineProperty(TimerEventDefinition.prototype, 'executionId', { + get() { + return this[K_TIMER_CONTENT]?.executionId; + } +}); +Object.defineProperty(TimerEventDefinition.prototype, 'stopped', { + get() { + return this[_constants.K_STOPPED]; + } +}); +Object.defineProperty(TimerEventDefinition.prototype, 'timer', { + get() { + return this[K_TIMER]; } }); TimerEventDefinition.prototype.execute = function execute(executeMessage) { @@ -59,7 +54,6 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { return; } if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); - /** @private */ this[_constants.K_STOPPED] = false; const content = executeMessage.content; const executionId = content.executionId; @@ -95,7 +89,6 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { if (timerContent.timeout <= 0) return this._completed(); const timers = this.environment.timers.register(timerContent); const delay = timerContent.timeout; - /** @private */ this[K_TIMER] = timers.setTimeout(this._completed.bind(this), delay, { id: content.id, type: this.type, @@ -195,7 +188,6 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, } }; TimerEventDefinition.prototype._stop = function stop() { - /** @private */ this[_constants.K_STOPPED] = true; const timer = this[K_TIMER]; if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); diff --git a/dist/events/BoundaryEvent.js b/dist/events/BoundaryEvent.js index bb4cef13..4050c861 100644 --- a/dist/events/BoundaryEvent.js +++ b/dist/events/BoundaryEvent.js @@ -23,24 +23,19 @@ function BoundaryEventBehaviour(activity) { this.activity = activity; this.environment = activity.environment; this.broker = activity.broker; - /** @private */ this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions, 'execute.bound.completed'); - /** @private */ this[K_SHOVELS] = new Set(); - /** @private */ this[K_ATTACHED_TAGS] = new Set(); } -Object.defineProperties(BoundaryEventBehaviour.prototype, { - executionId: { - get() { - return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; - } - }, - cancelActivity: { - get() { - const behaviour = this.activity.behaviour || {}; - return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true; - } +Object.defineProperty(BoundaryEventBehaviour.prototype, 'executionId', { + get() { + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; + } +}); +Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', { + get() { + const behaviour = this.activity.behaviour || {}; + return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true; } }); BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { @@ -50,7 +45,6 @@ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { } = executeMessage.content; const eventDefinitionExecution = this[_constants.K_EXECUTION]; if (isRootScope && executeMessage.content.id === this.id) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const broker = this.broker; if (executeMessage.fields.routingKey === 'execute.bound.completed') { @@ -63,7 +57,6 @@ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { consumerTag, priority: 300 }); - /** @private */ this[K_ATTACHED_TAGS].add(consumerTag); broker.subscribeOnce('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { consumerTag: `_api-${executionId}` @@ -111,8 +104,6 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, { cancelActivity: false })); } - - /** @private */ this[K_COMPLETE_CONTENT] = content; const { inbound, @@ -123,7 +114,6 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, { this.activity.logger.debug(`<${executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`); if (content.isRecovered && !attachedTo.isRunning) { const attachedExecuteTag = `_on-attached-execute-${executionId}`; - /** @private */ this[K_ATTACHED_TAGS].add(attachedExecuteTag); attachedTo.broker.subscribeOnce('execution', '#', () => { attachedTo.getApi({ @@ -158,7 +148,6 @@ BoundaryEventBehaviour.prototype._onExpectMessage = function onExpectMessage(_, } = content; const attachedTo = this.attachedTo; const errorConsumerTag = `_bound-error-listener-${executionId}`; - /** @private */ this[K_ATTACHED_TAGS].add(errorConsumerTag); attachedTo.broker.subscribeTmp('event', pattern, (__, message) => { if (message.content.id !== attachedTo.id) return; @@ -191,7 +180,6 @@ BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_, sourcePattern } = content; const shovelName = `_detached-${(0, _shared.brokerSafeId)(id)}_${detachId}`; - /** @private */ this[K_SHOVELS].add(shovelName); const broker = this.broker; attachedTo.broker.createShovel(shovelName, { @@ -240,10 +228,8 @@ BoundaryEventBehaviour.prototype._stop = function stop(detach) { broker = this.broker, executionId = this.executionId; for (const tag of this[K_ATTACHED_TAGS]) attachedTo.broker.cancel(tag); - /** @private */ this[K_ATTACHED_TAGS].clear(); for (const shovelName of this[K_SHOVELS]) attachedTo.broker.closeShovel(shovelName); - /** @private */ this[K_SHOVELS].clear(); broker.cancel('_execution-tag'); broker.cancel(`_execution-completed-${executionId}`); diff --git a/dist/events/EndEvent.js b/dist/events/EndEvent.js index ba2b3fa7..54cf944e 100644 --- a/dist/events/EndEvent.js +++ b/dist/events/EndEvent.js @@ -19,7 +19,6 @@ function EndEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - /** @private */ this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } EndEventBehaviour.prototype.execute = function execute(executeMessage) { diff --git a/dist/events/IntermediateCatchEvent.js b/dist/events/IntermediateCatchEvent.js index 7b3c0cea..fb742a79 100644 --- a/dist/events/IntermediateCatchEvent.js +++ b/dist/events/IntermediateCatchEvent.js @@ -19,7 +19,6 @@ function IntermediateCatchEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - /** @private */ this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } IntermediateCatchEventBehaviour.prototype.execute = function execute(executeMessage) { diff --git a/dist/events/IntermediateThrowEvent.js b/dist/events/IntermediateThrowEvent.js index 9df78066..553d0a51 100644 --- a/dist/events/IntermediateThrowEvent.js +++ b/dist/events/IntermediateThrowEvent.js @@ -19,7 +19,6 @@ function IntermediateThrowEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - /** @private */ this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } IntermediateThrowEventBehaviour.prototype.execute = function execute(executeMessage) { diff --git a/dist/events/StartEvent.js b/dist/events/StartEvent.js index 5f5370c3..393b6154 100644 --- a/dist/events/StartEvent.js +++ b/dist/events/StartEvent.js @@ -17,7 +17,6 @@ function StartEventBehaviour(activity) { this.type = activity.type; this.activity = activity; this.broker = activity.broker; - /** @private */ this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } Object.defineProperty(StartEventBehaviour.prototype, 'executionId', { @@ -36,7 +35,6 @@ StartEventBehaviour.prototype.execute = function execute(executeMessage) { return broker.publish('execution', 'execute.completed', content); } const executionId = content.executionId; - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; broker.subscribeTmp('api', `activity.#.${executionId}`, (...args) => this._onApiMessage(...args), { noAck: true, diff --git a/dist/flows/Association.js b/dist/flows/Association.js index 12776994..d5b46c4c 100644 --- a/dist/flows/Association.js +++ b/dist/flows/Association.js @@ -13,7 +13,7 @@ var _constants = require("../constants.js"); * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. * @param {import('moddle-context-serializer').SerializableElement} associationDef - * @param {import('types').ContextInstance} context + * @param {import('#types').ContextInstance} context */ function Association(associationDef, { environment @@ -37,8 +37,6 @@ function Association(associationDef, { this.isAssociation = true; this.environment = environment; const logger = this.logger = environment.Logger(type.toLowerCase()); - - /** @private */ this[_constants.K_COUNTERS] = { take: 0, discard: 0 @@ -93,7 +91,7 @@ Association.prototype.discard = function discard(content) { /** * Snapshot association state. Returns undefined when broker has no state and * `disableTrackState` is set. - * @returns {import('types').AssociationState | undefined} + * @returns {import('#types').AssociationState | undefined} */ Association.prototype.getState = function getState() { const brokerState = this.broker.getState(true); @@ -108,7 +106,7 @@ Association.prototype.getState = function getState() { /** * Restore association state captured by getState. - * @param {import('types').AssociationState} state + * @param {import('#types').AssociationState} state */ Association.prototype.recover = function recover(state) { Object.assign(this[_constants.K_COUNTERS], state.counters); @@ -117,7 +115,8 @@ Association.prototype.recover = function recover(state) { /** * Resolve an association-scoped Api wrapper. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ Association.prototype.getApi = function getApi(message) { return new _Api.Api('association', this.broker, message || { diff --git a/dist/flows/MessageFlow.js b/dist/flows/MessageFlow.js index 845a6c57..913ae87e 100644 --- a/dist/flows/MessageFlow.js +++ b/dist/flows/MessageFlow.js @@ -16,7 +16,7 @@ const K_SOURCE_ELEMENT = Symbol.for('sourceElement'); * source's `end` event and publishes `message.outbound` whenever the source completes, * carrying any message payload through to the target. * @param {import('moddle-context-serializer').SerializableElement} flowDef - * @param {import('types').ContextInstance} context + * @param {import('#types').ContextInstance} context */ function MessageFlow(flowDef, context) { const { @@ -37,8 +37,6 @@ function MessageFlow(flowDef, context) { this.behaviour = behaviour; this.environment = context.environment; this.context = context; - - /** @private */ this[_constants.K_COUNTERS] = { messages: 0 }; @@ -54,8 +52,6 @@ function MessageFlow(flowDef, context) { this.once = once; this.emit = emit; this.waitFor = waitFor; - - /** @private */ this[K_SOURCE_ELEMENT] = context.getActivityById(source.id) || context.getProcessById(source.processId); this.logger = context.environment.Logger(type.toLowerCase()); } @@ -71,7 +67,7 @@ Object.defineProperty(MessageFlow.prototype, 'counters', { /** * Snapshot message-flow state. Returns undefined when broker has no state and * `disableTrackState` is set. - * @returns {import('types').MessageFlowState | undefined} + * @returns {import('#types').MessageFlowState | undefined} */ MessageFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); @@ -86,7 +82,7 @@ MessageFlow.prototype.getState = function getState() { /** * Restore message-flow state captured by getState. - * @param {import('types').MessageFlowState} state + * @param {import('#types').MessageFlowState} state */ MessageFlow.prototype.recover = function recover(state) { Object.assign(this[_constants.K_COUNTERS], state.counters); @@ -95,7 +91,8 @@ MessageFlow.prototype.recover = function recover(state) { /** * Resolve a message-scoped Api wrapper. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ MessageFlow.prototype.getApi = function getApi(message) { return new _Api.Api('message', this.broker, message || { diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index 2236e2c2..8e4fd6b4 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -14,7 +14,7 @@ var _constants = require("../constants.js"); * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. * @param {import('moddle-context-serializer').SerializableElement} flowDef - * @param {import('types').ContextInstance} context + * @param {import('#types').ContextInstance} context */ function SequenceFlow(flowDef, { environment @@ -40,8 +40,6 @@ function SequenceFlow(flowDef, { this.isSequenceFlow = true; this.environment = environment; const logger = this.logger = environment.Logger(type.toLowerCase()); - - /** @private */ this[_constants.K_COUNTERS] = { looped: 0, take: 0, @@ -109,7 +107,7 @@ SequenceFlow.prototype.discard = function discard(content = {}) { /** * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` * is set. - * @returns {import('types').SequenceFlowState | undefined} + * @returns {import('#types').SequenceFlowState | undefined} */ SequenceFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); @@ -124,7 +122,7 @@ SequenceFlow.prototype.getState = function getState() { /** * Restore flow state captured by getState. - * @param {import('types').SequenceFlowState} state + * @param {import('#types').SequenceFlowState} state */ SequenceFlow.prototype.recover = function recover(state) { Object.assign(this[_constants.K_COUNTERS], state.counters); @@ -133,7 +131,8 @@ SequenceFlow.prototype.recover = function recover(state) { /** * Resolve a Flow Api wrapper. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ SequenceFlow.prototype.getApi = function getApi(message) { return (0, _Api.FlowApi)(this.broker, message || { @@ -151,7 +150,7 @@ SequenceFlow.prototype.stop = function stop() { /** * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop * when the target was already visited, otherwise flow.shake. - * @param {import('types').ElementBrokerMessage} message + * @param {import('#types').ElementBrokerMessage} message */ SequenceFlow.prototype.shake = function shake(message) { const content = (0, _messageHelper.cloneContent)(message.content); @@ -186,7 +185,7 @@ SequenceFlow.prototype.shake = function shake(message) { /** * Resolve the flow's condition (script or expression). Returns null when no condition is set. * Emits a fatal error when the script language is missing or unsupported. - * @returns {import('types').ISequenceFlowCondition | null} + * @returns {import('#types').ISequenceFlowCondition | null} */ SequenceFlow.prototype.getCondition = function getCondition() { const conditionExpression = this.behaviour.conditionExpression; @@ -225,7 +224,7 @@ SequenceFlow.prototype.createMessage = function createMessage(override) { /** * Evaluate the flow's condition for the source activity message. Default flows are always taken. - * @param {import('types').ElementBrokerMessage} fromMessage Source activity message + * @param {import('#types').ElementBrokerMessage} fromMessage Source activity message * @param {(err: Error | null, result?: boolean | object) => void} callback Callback with truthy result if flow should be taken */ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { diff --git a/dist/gateways/EventBasedGateway.js b/dist/gateways/EventBasedGateway.js index aaaf2e83..c8b5bfa8 100644 --- a/dist/gateways/EventBasedGateway.js +++ b/dist/gateways/EventBasedGateway.js @@ -17,7 +17,6 @@ function EventBasedGatewayBehaviour(activity, context) { this.activity = activity; this.broker = activity.broker; this.context = context; - /** @private */ this[_constants.K_TARGETS] = new Set(activity.outbound.map(flow => context.getActivityById(flow.targetId))); } EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) { @@ -28,7 +27,6 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) outboundTaken } = executeContent; const targets = this[_constants.K_TARGETS]; - /** @private */ this[_constants.K_COMPLETED] = false; if (!targets.size) return this._complete(executeContent); for (const flow of this.activity.outbound) { @@ -49,8 +47,6 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) broker.subscribeOnce('api', `activity.stop.${executionId}`, () => this._stop(), { consumerTag: '_api-stop-execution' }); - - /** @private */ this[_constants.K_COMPLETED] = false; if (!executeMessage.fields.redelivered) { return broker.publish('execution', 'execute.outbound.take', (0, _messageHelper.cloneContent)(executeContent, { @@ -81,7 +77,6 @@ EventBasedGatewayBehaviour.prototype._onTargetCompleted = function onTargetCompl this._complete(completedContent); }; EventBasedGatewayBehaviour.prototype._complete = function complete(completedContent) { - /** @private */ this[_constants.K_COMPLETED] = true; this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(completedContent)); }; diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 12964415..69791d21 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -58,14 +58,11 @@ function ParallelGatewayBehaviour(activity) { this.isConverging = new Set(activity.inbound.map(({ sourceId }) => sourceId)).size > 1; - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = undefined; } -Object.defineProperties(ParallelGatewayBehaviour.prototype, { - executionId: { - get() { - return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; - } +Object.defineProperty(ParallelGatewayBehaviour.prototype, 'executionId', { + get() { + return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { @@ -73,7 +70,6 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { const isRedelivered = executeMessage.fields.redelivered; const executeContent = executeMessage.content; if (executeContent.isRootScope) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; switch (routingKey) { case 'execute.start': @@ -91,7 +87,6 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { }; ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { const peerIds = new Set([...this.activity[K_PEERS].values()].map(v => [...v]).flat()); - /** @private */ this[_constants.K_TARGETS] = new Map([...peerIds].map(pid => [pid, this.activity.getActivityById(pid)])); this.peerMonitor = new PeerMonitor(this.activity, this.activity[K_INBOUND_SOURCE_IDS], this[_constants.K_TARGETS]); const message = this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage); diff --git a/dist/io/EnvironmentDataObject.js b/dist/io/EnvironmentDataObject.js index 07ca4c6e..e70576f4 100644 --- a/dist/io/EnvironmentDataObject.js +++ b/dist/io/EnvironmentDataObject.js @@ -34,6 +34,11 @@ EnvironmentDataObject.prototype.write = function write(broker, exchange, routing const content = this._createContent(value); return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; + +/** + * @private + * Create content + */ EnvironmentDataObject.prototype._createContent = function createContent(value) { return { id: this.id, diff --git a/dist/io/InputOutputSpecification.js b/dist/io/InputOutputSpecification.js index 590d5899..f11f58d3 100644 --- a/dist/io/InputOutputSpecification.js +++ b/dist/io/InputOutputSpecification.js @@ -28,7 +28,6 @@ IoSpecification.prototype.activate = function activate(message) { if (message?.fields.redelivered && message.fields.routingKey === 'run.end') { this._onFormatComplete(message); } - /** @private */ this[_constants.K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); diff --git a/dist/io/Properties.js b/dist/io/Properties.js index f1809848..dafc8326 100644 --- a/dist/io/Properties.js +++ b/dist/io/Properties.js @@ -79,8 +79,6 @@ Properties.prototype.activate = function activate(message) { if (message.fields.redelivered && message.content.properties) { this._onActivityEvent('activity.extension.resume', message); } - - /** @private */ this[_constants.K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); diff --git a/dist/process/Lane.js b/dist/process/Lane.js index 1cbcf5ad..6fc8fb25 100644 --- a/dist/process/Lane.js +++ b/dist/process/Lane.js @@ -9,7 +9,7 @@ const K_PROCESS = Symbol.for('process'); /** * Process lane. Wraps a `` definition and points back to its owning process; * activities reference their lane through `Activity.lane`. - * @param {import('types').Process} process + * @param {import('#types').Process} process * @param {import('moddle-context-serializer').SerializableElement} laneDefinition */ function Lane(process, laneDefinition) { @@ -22,8 +22,6 @@ function Lane(process, laneDefinition) { type, behaviour } = laneDefinition; - - /** @private */ this[K_PROCESS] = process; this.id = id; this.type = type; @@ -41,7 +39,7 @@ function Lane(process, laneDefinition) { this.logger = environment.Logger(type.toLowerCase()); } Object.defineProperty(Lane.prototype, 'process', { - /** @returns {import('types').Process} */ + /** @returns {import('#types').Process} */ get() { return this[K_PROCESS]; } diff --git a/dist/process/Process.js b/dist/process/Process.js index 71adf318..d1197f13 100644 --- a/dist/process/Process.js +++ b/dist/process/Process.js @@ -16,8 +16,8 @@ const K_LANES = Symbol.for('lanes'); /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. - * @param {import('moddle-context-serializer').SerializableElement} processDef - * @param {import('types').ContextInstance} context + * @param {import('moddle-context-serializer').MappedProcess} processDef + * @param {import('#types').ContextInstance} context */ function Process(processDef, context) { const { @@ -32,24 +32,16 @@ function Process(processDef, context) { this.name = name; this.parent = parent ? (0, _messageHelper.cloneParent)(parent) : {}; this.behaviour = behaviour; - const { - isExecutable - } = behaviour; - this.isExecutable = isExecutable; + this.isExecutable = behaviour.isExecutable; const environment = this.environment = context.environment; this.context = context; - /** @private */ this[_constants.K_COUNTERS] = { completed: 0, discarded: 0 }; - /** @private */ this[_constants.K_CONSUMING] = false; - /** @private */ this[_constants.K_EXECUTION] = new Map(); - /** @private */ this[_constants.K_STATUS] = undefined; - /** @private */ this[_constants.K_STOPPED] = false; const { broker, @@ -61,8 +53,6 @@ function Process(processDef, context) { this.on = on; this.once = once; this.waitFor = waitFor; - - /** @private */ this[_constants.K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onRunMessage: this._onRunMessage.bind(this), @@ -70,10 +60,8 @@ function Process(processDef, context) { }; this.logger = environment.Logger(type.toLowerCase()); if (behaviour.lanes) { - /** @private */ this[K_LANES] = behaviour.lanes.map(lane => new lane.Behaviour(this, lane)); } - /** @private */ this[_constants.K_EXTENSIONS] = context.loadExtensions(this); } Object.defineProperties(Process.prototype, { @@ -134,7 +122,6 @@ Object.defineProperties(Process.prototype, { */ Process.prototype.init = function init(useAsExecutionId) { const initExecutionId = useAsExecutionId || (0, _shared.getUniqueId)(this.id); - /** @private */ this[_constants.K_EXECUTION].set('initExecutionId', initExecutionId); this._debug(`initialized with executionId <${initExecutionId}>`); this._publishEvent('init', this._createMessage({ @@ -172,8 +159,6 @@ Process.prototype.run = function run(runContent) { Process.prototype.resume = function resume() { if (this.isRunning) throw new Error(`cannot resume running process <${this.id}>`); if (!this.status) return this; - - /** @private */ this[_constants.K_STOPPED] = false; const content = this._createMessage(); this.broker.publish('run', 'run.resume', content, { @@ -202,21 +187,17 @@ Process.prototype.getState = function getState() { /** * Restore process state captured by getState. - * @param {import('types').ProcessState} [state] + * @param {import('#types').ProcessState} [state] * @returns {this} * @throws {Error} when called on a running process */ Process.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running process <${this.id}>`); if (!state) return this; - - /** @private */ this[_constants.K_STOPPED] = !!state.stopped; - /** @private */ this[_constants.K_STATUS] = state.status; const exec = this[_constants.K_EXECUTION]; exec.set('executionId', state.executionId); - /** @private */ this[_constants.K_COUNTERS] = { ...this[_constants.K_COUNTERS], ...state.counters @@ -248,7 +229,8 @@ Process.prototype.stop = function stop() { /** * Resolve a Process Api wrapper, preferring the running execution if any. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ Process.prototype.getApi = function getApi(message) { const execution = this.execution; @@ -258,7 +240,7 @@ Process.prototype.getApi = function getApi(message) { /** * Send a delegated signal to the running process. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Process.prototype.signal = function signal(message) { return this.getApi().signal(message, { @@ -268,7 +250,7 @@ Process.prototype.signal = function signal(message) { /** * Cancel a running activity inside the process by delegated api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Process.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { @@ -278,7 +260,6 @@ Process.prototype.cancelActivity = function cancelActivity(message) { /** @internal */ Process.prototype._activateRunConsumers = function activateRunConsumers() { - /** @private */ this[_constants.K_CONSUMING] = true; const broker = this.broker; const { @@ -302,7 +283,6 @@ Process.prototype._deactivateRunConsumers = function deactivateRunConsumers() { broker.cancel('_process-api'); broker.cancel('_process-run'); broker.cancel('_process-execution'); - /** @private */ this[_constants.K_CONSUMING] = false; }; @@ -315,19 +295,13 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { if (routingKey === 'run.resume') { return this._onResumeMessage(message); } - - /** @private */ this[_constants.K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this._debug('enter'); - - /** @private */ this[_constants.K_STATUS] = 'entered'; if (fields.redelivered) break; - - /** @private */ this[_constants.K_EXECUTION].delete('execution'); this._publishEvent('enter', content); break; @@ -335,7 +309,6 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { case 'run.start': { this._debug('start'); - /** @private */ this[_constants.K_STATUS] = 'start'; this._publishEvent('start', content); break; @@ -343,14 +316,12 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { case 'run.execute': { const exec = this[_constants.K_EXECUTION]; - /** @private */ this[_constants.K_STATUS] = 'executing'; const executeMessage = (0, _messageHelper.cloneMessage)(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = message; this.broker.getQueue('execution-q').assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, @@ -362,7 +333,6 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } case 'run.error': { - /** @private */ this[_constants.K_STATUS] = 'errored'; this._publishEvent('error', (0, _messageHelper.cloneContent)(content, { error: fields.redelivered ? (0, _Errors.makeErrorFromMessage)(message) : content.error @@ -371,12 +341,9 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } case 'run.end': { - /** @private */ this[_constants.K_STATUS] = 'end'; if (fields.redelivered) break; this._debug('completed'); - - /** @private */ this[_constants.K_COUNTERS].completed++; this.broker.publish('run', 'run.leave', content); this._publishEvent('end', content); @@ -384,11 +351,8 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } case 'run.discarded': { - /** @private */ this[_constants.K_STATUS] = 'discarded'; if (fields.redelivered) break; - - /** @private */ this[_constants.K_COUNTERS].discarded++; this.broker.publish('run', 'run.leave', content); this._publishEvent('discarded', content); @@ -396,7 +360,6 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } case 'run.leave': { - /** @private */ this[_constants.K_STATUS] = undefined; message.ack(); this._deactivateRunConsumers(); @@ -455,7 +418,6 @@ Process.prototype._onExecutionMessage = function onExecutionMessage(routingKey, } } const executeMessage = this[_constants.K_EXECUTE_MESSAGE]; - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; @@ -475,7 +437,7 @@ Process.prototype._publishEvent = function publishEvent(state, content) { /** * Deliver a message to a target activity or start activity that references it. * Starts the process if a target is found and the process is idle. - * @param {import('types').ElementBrokerMessage} message + * @param {import('#types').ElementBrokerMessage} message */ Process.prototype.sendMessage = function sendMessage(message) { const messageContent = message?.content; @@ -516,7 +478,7 @@ Process.prototype.getActivities = function getActivities() { /** * Get start activities, optionally filtered by referenced event definition. - * @param {import('types').startActivityFilterOptions} [filterOptions] + * @param {import('#types').startActivityFilterOptions} [filterOptions] */ Process.prototype.getStartActivities = function getStartActivities(filterOptions) { return this.context.getStartActivities(filterOptions, this.id); @@ -542,7 +504,7 @@ Process.prototype.getLaneById = function getLaneById(laneId) { /** * List currently postponed activities as Api wrappers. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ Process.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; @@ -565,7 +527,6 @@ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { /** @internal */ Process.prototype._onStop = function onStop() { - /** @private */ this[_constants.K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop'); diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index d500462d..2283a589 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -17,8 +17,8 @@ const K_TRACKER = Symbol.for('activity tracker'); /** * Drives the execution of a single process or sub-process: activates children, routes activity * events, and rolls completion up to the owning Process or sub-process Activity. - * @param {import('types').Process | import('types').Activity} parentActivity - * @param {import('types').ContextInstance} context + * @param {import('#types').Process | import('#types').Activity} parentActivity + * @param {import('#types').ContextInstance} context */ function ProcessExecution(parentActivity, context) { const { @@ -28,8 +28,6 @@ function ProcessExecution(parentActivity, context) { isSubProcess, isTransaction } = parentActivity; - - /** @private */ this[K_PARENT] = parentActivity; this.id = id; this.type = type; @@ -38,8 +36,6 @@ function ProcessExecution(parentActivity, context) { this.broker = broker; this.environment = context.environment; this.context = context; - - /** @private */ this[K_ELEMENTS] = { postponed: new Set(), children: context.getActivities(id), @@ -57,20 +53,12 @@ function ProcessExecution(parentActivity, context) { autoDelete: false, durable: true }); - - /** @private */ this[_constants.K_COMPLETED] = false; - /** @private */ this[_constants.K_STOPPED] = false; - /** @private */ this[_constants.K_ACTIVATED] = false; - /** @private */ this[_constants.K_STATUS] = 'init'; - /** @private */ this[K_TRACKER] = new _Tracker.ActivityTracker(id); this.executionId = undefined; - - /** @private */ this[_constants.K_MESSAGE_HANDLERS] = { onActivityEvent: this._onActivityEvent.bind(this), onApiMessage: this._onApiMessage.bind(this), @@ -113,24 +101,19 @@ Object.defineProperties(ProcessExecution.prototype, { /** * Activate children and start the process execution. Resumes if the message is redelivered. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage * @throws {Error} when message or executionId is missing */ ProcessExecution.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new Error('Process execution requires message'); if (!executeMessage.content || !executeMessage.content.executionId) throw new Error('Process execution requires execution id'); const executionId = this.executionId = executeMessage.content.executionId; - - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage, { executionId, state: 'start' }); - - /** @private */ this[_constants.K_STOPPED] = false; this.environment.assignVariables(executeMessage); - /** @private */ this[K_ACTIVITY_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false @@ -165,8 +148,6 @@ ProcessExecution.prototype.resume = function resume() { } postponed.clear(); detachedActivities.clear(); - - /** @private */ this[K_ACTIVITY_Q].consume(this[_constants.K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}` @@ -193,6 +174,7 @@ ProcessExecution.prototype.resume = function resume() { /** * Snapshot execution state including children, flows, message flows, and associations. + * @returns {import('#types').ProcessExecutionState} */ ProcessExecution.prototype.getState = function getState() { const { @@ -231,18 +213,14 @@ ProcessExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. - * @param {import('types').ProcessExecutionState} [state] + * @param {import('#types').ProcessExecutionState} [state] * @returns {this} */ ProcessExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - - /** @private */ this[_constants.K_STOPPED] = state.stopped; - /** @private */ this[_constants.K_COMPLETED] = state.completed; - /** @private */ this[_constants.K_STATUS] = state.status; this._debug(`recover process execution at ${this.status}`); if (state.messageFlows) { @@ -293,7 +271,7 @@ ProcessExecution.prototype.stop = function stop() { /** * List currently postponed children as Api wrappers. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { const result = []; @@ -310,7 +288,6 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { * Queue a discard message that propagates to all running children. */ ProcessExecution.prototype.discard = function discard() { - /** @private */ this[_constants.K_STATUS] = 'discard'; return this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.discard' @@ -368,7 +345,8 @@ ProcessExecution.prototype.getAssociations = function getAssociations() { /** * Resolve a process or child Api for the given message. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ ProcessExecution.prototype.getApi = function getApi(message) { if (!message) return (0, _Api.ProcessApi)(this.broker, this[_constants.K_EXECUTE_MESSAGE]); @@ -395,8 +373,6 @@ ProcessExecution.prototype._start = function start() { if (!this[K_ELEMENTS].children.length) { return this._complete('completed'); } - - /** @private */ this[_constants.K_STATUS] = 'start'; const executeContent = { ...this[_constants.K_EXECUTE_MESSAGE].content, @@ -415,7 +391,6 @@ ProcessExecution.prototype._start = function start() { this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); } for (const a of startActivities) a.init(); - /** @private */ this[_constants.K_STATUS] = 'executing'; for (const a of startActivities) a.run(); if (!startActivities.size) { @@ -425,7 +400,6 @@ ProcessExecution.prototype._start = function start() { } postponed.clear(); detachedActivities.clear(); - /** @private */ this[K_ACTIVITY_Q].assertConsumer(this[_constants.K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}` @@ -461,8 +435,7 @@ ProcessExecution.prototype._activate = function activate() { triggeredByEvent, convergingGateways, children - } = /** @private */ - this[K_ELEMENTS]; + } = this[K_ELEMENTS]; for (const flow of outboundMessageFlows) { flow.activate(); flow.broker.subscribeTmp('event', '#', onMessageFlowEvent, { @@ -506,8 +479,6 @@ ProcessExecution.prototype._activate = function activate() { startSequences.set(activity.id, new Set()); } } - - /** @private */ this[_constants.K_ACTIVATED] = true; }; @@ -538,8 +509,6 @@ ProcessExecution.prototype._deactivate = function deactivate() { flow.deactivate(); flow.broker.cancel('_process-message-consumer'); } - - /** @private */ this[_constants.K_ACTIVATED] = false; }; @@ -678,8 +647,6 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe }); } if (delegate) delegate = this._onDelegateEvent(message); - - /** @private */ this[K_TRACKER].track(routingKey, message); this.broker.publish('event', routingKey, content, { ...properties, @@ -699,8 +666,6 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe case 'activity.stop': return; } - - /** @private */ this[K_ACTIVITY_Q].queueMessage(message.fields, (0, _messageHelper.cloneContent)(content), { persistent: true, ...message.properties @@ -752,7 +717,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, switch (routingKey) { case 'activity.detach': { - /** @private */ this[K_ELEMENTS].detachedActivities.add((0, _messageHelper.cloneMessage)(message)); break; } @@ -782,7 +746,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, } } if (eventCaughtBy) { - /** @private */ this[K_ACTIVITY_Q].queueMessage({ routingKey: 'activity.error.caught' }, (0, _messageHelper.cloneContent)(content), { @@ -898,7 +861,6 @@ ProcessExecution.prototype._stopExecution = function stopExecution(message) { for (const api of this.getPostponed()) api.stop(); } this._deactivate(); - /** @private */ this[_constants.K_STOPPED] = true; return this.broker.publish(this._exchangeName, `execution.stopped.${this.executionId}`, { ...this[_constants.K_EXECUTE_MESSAGE].content, @@ -923,8 +885,6 @@ ProcessExecution.prototype._onDiscard = function onDiscard() { for (const flow of this.getAssociations()) flow.stop(); for (const msg of running) this._getChildApi(msg).discard(); } - - /** @private */ this[K_ACTIVITY_Q].purge(); return this._complete('discard'); }; @@ -936,7 +896,6 @@ ProcessExecution.prototype._onCancel = function onCancel() { const isTransaction = this.isTransaction; if (isTransaction) { this._debug(`cancel transaction execution (cancel child executions ${running.size})`); - /** @private */ this[_constants.K_STATUS] = 'cancel'; this.broker.publish('event', 'transaction.cancel', (0, _messageHelper.cloneMessage)(this[_constants.K_EXECUTE_MESSAGE], { state: 'cancel' @@ -973,7 +932,6 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes case 'discard': return this.discard(message); case 'stop': - /** @private */ this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.stop' }, (0, _messageHelper.cloneContent)(message.content), { @@ -1009,7 +967,6 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou /** @internal */ ProcessExecution.prototype._complete = function complete(completionType, content) { this._deactivate(); - /** @private */ this[_constants.K_COMPLETED] = true; const status = this.status; switch (this.status) { @@ -1022,13 +979,11 @@ ProcessExecution.prototype._complete = function complete(completionType, content break; default: this._debug(`process execution ${completionType}`); - /** @private */ this[_constants.K_STATUS] = completionType; } const broker = this.broker; - /** @private */ this[K_ACTIVITY_Q].delete(); - return broker.publish(this._exchangeName, `execution.${completionType}.${this.executionId}`, (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { + broker.publish(this._exchangeName, `execution.${completionType}.${this.executionId}`, (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { output: { ...this.environment.output }, @@ -1042,7 +997,6 @@ ProcessExecution.prototype._complete = function complete(completionType, content /** @internal */ ProcessExecution.prototype._terminate = function terminate(message) { - /** @private */ this[_constants.K_STATUS] = 'terminated'; this._debug('terminating process execution'); const postponed = this[K_ELEMENTS].postponed; @@ -1061,8 +1015,6 @@ ProcessExecution.prototype._terminate = function terminate(message) { this._getChildApi(msg).stop(); msg.ack(); } - - /** @private */ this[K_ACTIVITY_Q].purge(); }; @@ -1114,6 +1066,5 @@ ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { /** @internal */ ProcessExecution.prototype._debug = function debugMessage(logMessage) { - /** @private */ this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; \ No newline at end of file diff --git a/dist/tasks/CallActivity.js b/dist/tasks/CallActivity.js index 46bf2edc..d8361b89 100644 --- a/dist/tasks/CallActivity.js +++ b/dist/tasks/CallActivity.js @@ -8,6 +8,12 @@ exports.CallActivityBehaviour = CallActivityBehaviour; var _Activity = require("../activity/Activity.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Create call activity + * @param {import('moddle-context-serializer').MappedActivity} activityDef + * @param {import('../Context.js').ContextInstance} context + * @returns Call activity + */ function CallActivity(activityDef, context) { return new _Activity.Activity(CallActivityBehaviour, activityDef, context); } diff --git a/dist/tasks/ReceiveTask.js b/dist/tasks/ReceiveTask.js index 1db6e5d3..6d9c997d 100644 --- a/dist/tasks/ReceiveTask.js +++ b/dist/tasks/ReceiveTask.js @@ -35,8 +35,6 @@ function ReceiveTaskBehaviour(activity) { this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.broker = activity.broker; - - /** @private */ this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); } ReceiveTaskBehaviour.prototype.execute = function execute(executeMessage) { @@ -55,12 +53,9 @@ function ReceiveTaskExecution(parent) { this.broker = broker; this.loopCharacteristics = loopCharacteristics; this.referenceElement = parent[_constants.K_REFERENCE_ELEMENT]; - - /** @private */ this[_constants.K_COMPLETED] = false; } ReceiveTaskExecution.prototype.execute = function execute(executeMessage) { - /** @private */ this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; const { @@ -150,7 +145,6 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, } case 'discard': { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content), { @@ -164,7 +158,6 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, } }; ReceiveTaskExecution.prototype._complete = function complete(output, options) { - /** @private */ this[_constants.K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { diff --git a/dist/tasks/SubProcess.js b/dist/tasks/SubProcess.js index 3a8a762f..aebaa143 100644 --- a/dist/tasks/SubProcess.js +++ b/dist/tasks/SubProcess.js @@ -53,22 +53,17 @@ function SubProcessBehaviour(activity, context) { this.environment = activity.environment; this.broker = activity.broker; this.executionId = undefined; - - /** @private */ this[K_EXECUTIONS] = new Set(); - /** @private */ this[K_ON_EXECUTION_COMPLETED] = this._onExecutionCompleted.bind(this); } -Object.defineProperties(SubProcessBehaviour.prototype, { - execution: { - get() { - return [...this[K_EXECUTIONS]][0]; - } - }, - executions: { - get() { - return [...this[K_EXECUTIONS]]; - } +Object.defineProperty(SubProcessBehaviour.prototype, 'execution', { + get() { + return [...this[K_EXECUTIONS]][0]; + } +}); +Object.defineProperty(SubProcessBehaviour.prototype, 'executions', { + get() { + return [...this[K_EXECUTIONS]]; } }); SubProcessBehaviour.prototype.execute = function execute(executeMessage) { @@ -138,7 +133,6 @@ SubProcessBehaviour.prototype._upsertExecution = function upsertExecution(execut const subEnvironment = this.environment.clone(); const subContext = this.context.clone(subEnvironment, this.activity); execution = new _ProcessExecution.ProcessExecution(this.activity, subContext); - /** @private */ this[K_EXECUTIONS].add(execution); this._addListeners(executionId); return execution; @@ -180,7 +174,6 @@ SubProcessBehaviour.prototype._onExecutionCompleted = function onExecutionComple SubProcessBehaviour.prototype._completeExecution = function completeExecution(completeRoutingKey, content) { if (this.loopCharacteristics) { const execution = this._getExecutionById(content.executionId); - /** @private */ this[K_EXECUTIONS].delete(execution); } this.broker.publish('execution', completeRoutingKey, (0, _messageHelper.cloneContent)(content)); diff --git a/package.json b/package.json index f3e73473..55a867b9 100644 --- a/package.json +++ b/package.json @@ -49,12 +49,12 @@ "test": "mocha -R @bonniernews/hot-bev -p -t 3000", "posttest": "npm run lint && npm run dist", "lint": "eslint . --cache && prettier . --check --cache", - "prepack": "npm run dist && npm run types", + "prepack": "npm run dist", "test:md": "texample ./docs/Examples.md,./docs/StartEvent.md,./docs/Extension.md,./docs/ConditionalEventDefinition.md", "cov:html": "c8 -r html -r text mocha -R @bonniernews/hot-bev -p -t 3000", "test:lcov": "c8 -r lcov mocha && npm run lint", - "dist": "babel src -d dist/", - "types": "node scripts/build-types.js" + "dist": "babel src -d dist/ && npm run build:types", + "build:types": "node scripts/build-types.js" }, "repository": { "type": "git", @@ -103,7 +103,7 @@ "@types/bpmn-moddle": "^10.0.0", "@types/node": "^20.19.40", "bpmn-moddle": "^9.0.1", - "c8": "^10.1.1", + "c8": "^11.0.0", "camunda-bpmn-moddle": "^7.0.1", "chai": "^6.2.1", "chronokinesis": "^8.0.0", diff --git a/scripts/build-types.js b/scripts/build-types.js index fd379068..8d7fae32 100644 --- a/scripts/build-types.js +++ b/scripts/build-types.js @@ -1,20 +1,25 @@ -import { readFileSync, writeFileSync } from 'node:fs'; +import { readFileSync, rmSync, writeFileSync } from 'node:fs'; +import ts from 'typescript'; +import MagicString from 'magic-string'; import { createBundle } from 'dts-buddy'; const output = 'types/index.d.ts'; -const augmentations = 'types/augmentations.d.ts'; +// Point dts-buddy at hand-written bundle entries that re-export the runtime +// classes from `src/*.js` once each plus the shared interfaces from +// `types/interfaces.d.ts`. This gives a single source of truth per name +// (no `_1` aliases) and avoids cross-sub-module duplication. createBundle({ project: 'tsconfig.json', output, modules: { - 'bpmn-elements': 'src/index.js', - 'bpmn-elements/errors': 'src/error/Errors.js', - 'bpmn-elements/events': 'src/events/index.js', - 'bpmn-elements/eventDefinitions': 'src/eventDefinitions/index.js', - 'bpmn-elements/flows': 'src/flows/index.js', - 'bpmn-elements/gateways': 'src/gateways/index.js', - 'bpmn-elements/tasks': 'src/tasks/index.js', + 'bpmn-elements': 'types/bundle.d.ts', + 'bpmn-elements/errors': 'types/bundle-errors.d.ts', + 'bpmn-elements/events': 'types/bundle-events.d.ts', + 'bpmn-elements/eventDefinitions': 'types/bundle-eventDefinitions.d.ts', + 'bpmn-elements/flows': 'types/bundle-flows.d.ts', + 'bpmn-elements/gateways': 'types/bundle-gateways.d.ts', + 'bpmn-elements/tasks': 'types/bundle-tasks.d.ts', }, }) .then(() => { @@ -23,18 +28,207 @@ createBundle({ // tsc emits both `export function Foo(...): Foo;` AND `export class Foo { ... }` // for constructor functions in JS. The function declaration overshadows the class // for type-level constructor checks (`Foo extends new (...args) => any`), so strip it. - bundle = bundle.replace( - /^(\s*)(?:export )?function (\w+)\([^)]*\)[^;]*;\n(\s*)((?:export )?class \2\b)/gm, - '$1$3$4' - ); + bundle = bundle.replace(/^(\s*)(?:export )?function (\w+)\([^)]*\)[^;]*;\n(\s*)((?:export )?class \2\b)/gm, '$1$3$4'); - // Object.defineProperties getters can't be inferred from constructor functions, - // so the augmentation file declares them as interface members that merge with - // the dts-buddy-emitted classes. - bundle += '\n' + readFileSync(augmentations, 'utf8'); + // dts-buddy's stripInternal only catches `PropertySignature` (interface members), + // not class members. Walk class declarations and remove members marked `@internal` + // or `private` so they don't leak into the public bundle. + bundle = stripClassMembers(bundle); + + // dts-buddy emits a self-contained type tree per module, so types exported from + // the root (`bpmn-elements`) get re-declared inside every sub-module that references + // them. Strip those redeclarations and `import type` from the root instead. + bundle = hoistSharedTypes(bundle); + + // The declaration map dts-buddy emits is stale after our rewrites — drop it + // and remove the sourceMappingURL comment. + bundle = bundle.replace(/\n*\/\/# sourceMappingURL=.*$/m, '\n'); + rmSync(`${output}.map`, { force: true }); writeFileSync(output, bundle); }) .catch((err) => { throw err; }); + +/** + * @param {string} source + * @returns {string} + */ +function stripClassMembers(source) { + const ast = ts.createSourceFile('bundle.d.ts', source, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS); + const magic = new MagicString(source); + + const referencedSymbols = new Set(); + + /** @param {ts.Node} node */ + function visit(node) { + if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) { + for (const member of node.members) { + if (isInternalMember(member) || hasPrivateModifier(member) || hasUnderscoreName(member) || hasComputedSymbolName(member)) { + magic.remove(member.getFullStart(), member.getEnd()); + } else { + // surviving members may reference symbol constants; record them so the + // orphan-declaration sweep below doesn't drop those. + recordSymbolReferences(member, referencedSymbols); + } + } + } + ts.forEachChild(node, visit); + } + ts.forEachChild(ast, visit); + + // Symbol-keyed slots are inherently private storage; any `const K_FOO: unique symbol;` + // left without references is dead weight in the public bundle. + /** @param {ts.Node} node */ + function dropOrphanSymbols(node) { + if (ts.isVariableStatement(node)) { + const decls = node.declarationList.declarations; + if (decls.length === 1) { + const decl = decls[0]; + if ( + ts.isIdentifier(decl.name) && + decl.type && + (decl.type.kind === ts.SyntaxKind.UniqueKeyword) === false && + ts.isTypeOperatorNode(decl.type) && + decl.type.operator === ts.SyntaxKind.UniqueKeyword + ) { + if (!referencedSymbols.has(decl.name.text)) { + magic.remove(node.getFullStart(), node.getEnd()); + } + } + } + } + ts.forEachChild(node, dropOrphanSymbols); + } + ts.forEachChild(ast, dropOrphanSymbols); + + return magic.toString(); +} + +/** @param {ts.Node} node */ +function isInternalMember(node) { + const jsdoc = ts.getJSDocTags(node); + return jsdoc.some((tag) => tag.tagName.escapedText === 'internal'); +} + +/** @param {ts.Node} node */ +function hasPrivateModifier(node) { + const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined; + return !!modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword); +} + +/** @param {ts.ClassElement} node */ +function hasUnderscoreName(node) { + const name = node.name; + if (!name || !ts.isIdentifier(name)) return false; + return name.text.startsWith('_'); +} + +/** @param {ts.ClassElement} node */ +function hasComputedSymbolName(node) { + const name = node.name; + return !!name && ts.isComputedPropertyName(name) && ts.isIdentifier(name.expression); +} + +/** + * @param {ts.Node} root + * @param {Set} out + */ +function recordSymbolReferences(root, out) { + /** @param {ts.Node} node */ + function visit(node) { + if (ts.isIdentifier(node) && /^K_[A-Z0-9_]+$/.test(node.text)) { + out.add(node.text); + } + ts.forEachChild(node, visit); + } + visit(root); +} + +/** + * @param {string} source + * @returns {string} + */ +function hoistSharedTypes(source) { + const ast = ts.createSourceFile('bundle.d.ts', source, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS); + const magic = new MagicString(source); + + /** @type {ts.ModuleDeclaration[]} */ + const modules = []; + for (const stmt of ast.statements) { + if (ts.isModuleDeclaration(stmt) && ts.isStringLiteral(stmt.name) && stmt.name.text.startsWith('bpmn-elements')) { + modules.push(stmt); + } + } + + const root = modules.find((m) => /** @type {ts.StringLiteral} */ (m.name).text === 'bpmn-elements'); + if (!root || !root.body || !ts.isModuleBlock(root.body)) return source; + + // Collect names exported from the root module — these are the candidates for hoisting. + const rootExports = new Set(); + for (const stmt of root.body.statements) { + if (!hasExportModifier(stmt)) continue; + const name = getDeclName(stmt); + if (name) rootExports.add(name); + } + + for (const mod of modules) { + if (mod === root) continue; + if (!mod.body || !ts.isModuleBlock(mod.body)) continue; + + const stripped = new Set(); + let insertBefore = null; + + for (const stmt of mod.body.statements) { + if (insertBefore === null && !ts.isImportDeclaration(stmt)) insertBefore = stmt; + + // private redeclarations have no `export` modifier; sub-module's own exports stay. + if (hasExportModifier(stmt)) continue; + + const name = getDeclName(stmt); + if (name && rootExports.has(name)) { + magic.remove(stmt.getFullStart(), stmt.getEnd()); + stripped.add(name); + } + } + + if (stripped.size === 0) continue; + + const imports = [...stripped].sort(); + const importStmt = `\timport type { ${imports.join(', ')} } from 'bpmn-elements';\n`; + + if (insertBefore) { + magic.appendLeft(insertBefore.getFullStart(), `\n${importStmt}`); + } + } + + return magic.toString(); +} + +/** @param {ts.Node} node */ +function hasExportModifier(node) { + const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined; + return !!modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword); +} + +/** + * @param {ts.Node} node + * @returns {string | null} + */ +function getDeclName(node) { + if ( + ts.isClassDeclaration(node) || + ts.isFunctionDeclaration(node) || + ts.isInterfaceDeclaration(node) || + ts.isTypeAliasDeclaration(node) || + ts.isEnumDeclaration(node) + ) { + return node.name?.text ?? null; + } + if (ts.isVariableStatement(node)) { + const decls = node.declarationList.declarations; + if (decls.length === 1 && ts.isIdentifier(decls[0].name)) return decls[0].name.text; + } + return null; +} diff --git a/src/Api.js b/src/Api.js index ca9abda9..8338a71d 100644 --- a/src/Api.js +++ b/src/Api.js @@ -4,8 +4,8 @@ import { getUniqueId } from './shared.js'; /** * Build an activity-scoped Api wrapper. Routing keys are published under `activity.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ export function ActivityApi(broker, apiMessage, environment) { return new Api('activity', broker, apiMessage, environment); @@ -14,8 +14,8 @@ export function ActivityApi(broker, apiMessage, environment) { /** * Build a definition-scoped Api wrapper. Routing keys are published under `definition.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ export function DefinitionApi(broker, apiMessage, environment) { return new Api('definition', broker, apiMessage, environment); @@ -24,8 +24,8 @@ export function DefinitionApi(broker, apiMessage, environment) { /** * Build a process-scoped Api wrapper. Routing keys are published under `process.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ export function ProcessApi(broker, apiMessage, environment) { return new Api('process', broker, apiMessage, environment); @@ -34,8 +34,8 @@ export function ProcessApi(broker, apiMessage, environment) { /** * Build a flow-scoped Api wrapper. Routing keys are published under `flow.*`. * @param {any} broker - * @param {import('types').ElementBrokerMessage} apiMessage - * @param {import('types').Environment} [environment] + * @param {import('#types').ElementBrokerMessage} apiMessage + * @param {import('#types').Environment} [environment] */ export function FlowApi(broker, apiMessage, environment) { return new Api('flow', broker, apiMessage, environment); @@ -45,8 +45,8 @@ export function FlowApi(broker, apiMessage, environment) { * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. * @param {string} pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` * @param {any} broker - * @param {import('types').ElementBrokerMessage} sourceMessage Cloned to back the api - * @param {import('types').Environment} [environment] Defaults to `broker.owner.environment` + * @param {import('#types').ElementBrokerMessage} sourceMessage Cloned to back the api + * @param {import('#types').Environment} [environment] Defaults to `broker.owner.environment` * @throws {Error} when sourceMessage is missing */ export function Api(pfx, broker, sourceMessage, environment) { @@ -70,7 +70,7 @@ export function Api(pfx, broker, sourceMessage, environment) { /** * Send a cancel api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] * @param {any} [options] */ Api.prototype.cancel = function cancel(message, options) { @@ -94,7 +94,7 @@ Api.prototype.fail = function fail(error) { /** * Send a signal api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] * @param {any} [options] */ Api.prototype.signal = function signal(message, options) { @@ -127,7 +127,7 @@ Api.prototype.resolveExpression = function resolveExpression(expression) { /** * Publish a custom api message to the broker. * @param {string} action Routing key suffix, e.g. `signal`, `cancel` - * @param {import('types').signalMessage} [content] Merged into the message content + * @param {import('#types').signalMessage} [content] Merged into the message content * @param {any} [options] */ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) { @@ -139,7 +139,7 @@ Api.prototype.sendApiMessage = function sendApiMessage(action, content, options) /** * List currently postponed activities, falling back to a sub-process execution when applicable. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ Api.prototype.getPostponed = function getPostponed(...args) { if (this.owner.getPostponed) return this.owner.getPostponed(...args); diff --git a/src/Context.js b/src/Context.js index b5fdd982..835dcc72 100644 --- a/src/Context.js +++ b/src/Context.js @@ -8,7 +8,7 @@ const K_OWNER = Symbol.for('owner'); /** * Build a runtime Context from a parsed BPMN definition. * @param {import('moddle-context-serializer').SerializableContext} definitionContext - * @param {import('types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted + * @param {import('#types').Environment} [environment] Existing environment to clone; a fresh one is created when omitted */ export function Context(definitionContext, environment) { environment = environment ? environment.clone() : new Environment(); @@ -18,8 +18,8 @@ export function Context(definitionContext, environment) { /** * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. * @param {import('moddle-context-serializer').SerializableContext} definitionContext - * @param {import('types').Environment} environment - * @param {import('types').Process | import('types').Activity} [owner] Process or sub-process activity that owns this context + * @param {import('#types').Environment} environment + * @param {import('#types').Process | import('#types').Activity} [owner] Process or sub-process activity that owns this context */ export function ContextInstance(definitionContext, environment, owner) { const { id = 'Def', name, type = 'context' } = definitionContext; @@ -30,6 +30,7 @@ export function ContextInstance(definitionContext, environment, owner) { this.sid = sid; this.definitionContext = definitionContext; this.environment = environment; + /** @type {import('#types').IExtensionsMapper} */ this.extensionsMapper = new ExtensionsMapper(this); this.refs = new Map([ ['activityRefs', new Map()], @@ -40,12 +41,11 @@ export function ContextInstance(definitionContext, environment, owner) { ['dataObjectRefs', new Map()], ['dataStoreRefs', new Map()], ]); - /** @private */ this[K_OWNER] = owner; } Object.defineProperty(ContextInstance.prototype, 'owner', { - /** @returns {import('types').Process | import('types').Activity | undefined} Process or sub-process activity that owns this context */ + /** @returns {import('#types').Process | import('#types').Activity | undefined} Process or sub-process activity that owns this context */ get() { return this[K_OWNER]; }, @@ -54,6 +54,7 @@ Object.defineProperty(ContextInstance.prototype, 'owner', { /** * Get or create the activity instance for the given id. * @param {string} activityId + * @returns {import('./activity/Activity.js').Activity | null} */ ContextInstance.prototype.getActivityById = function getActivityById(activityId) { const activityInstance = this.refs.get('activityRefs').get(activityId); @@ -66,6 +67,7 @@ ContextInstance.prototype.getActivityById = function getActivityById(activityId) /** * Return the cached activity instance, instantiating it the first time it is referenced. * @param {import('moddle-context-serializer').SerializableElement} activityDef + * @returns {import('./activity/Activity.js').Activity} */ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) { let activityInstance = this.refs.get('activityRefs').get(activityDef.id); @@ -80,6 +82,7 @@ ContextInstance.prototype.upsertActivity = function upsertActivity(activityDef) /** * Get or create the sequence flow instance for the given id. * @param {string} sequenceFlowId + * @returns {import('./flows/SequenceFlow.js').SequenceFlow | null} */ ContextInstance.prototype.getSequenceFlowById = function getSequenceFlowById(sequenceFlowId) { const flowInstance = this.refs.get('sequenceFlowRefs').get(sequenceFlowId); @@ -173,8 +176,8 @@ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associa /** * Create a new context that shares the parsed definition but optionally swaps environment and owner. - * @param {import('types').Environment} [newEnvironment] - * @param {import('types').Process | import('types').Activity} [newOwner] + * @param {import('#types').Environment} [newEnvironment] + * @param {import('#types').Process | import('#types').Activity} [newOwner] */ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner); @@ -183,6 +186,7 @@ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { /** * Get or create the process instance for the given id. Each process gets its own cloned environment. * @param {string} processId + * @returns {import('./process/Process.js').Process | null} */ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const processRefs = this.refs.get('processRefs'); @@ -293,7 +297,7 @@ ContextInstance.prototype.getDataStoreById = function getDataStoreById(reference /** * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. - * @param {import('types').startActivityFilterOptions} [filterOptions] + * @param {import('#types').startActivityFilterOptions} [filterOptions] * @param {string} [scopeId] Process or sub-process id */ ContextInstance.prototype.getStartActivities = function getStartActivities(filterOptions, scopeId) { @@ -321,7 +325,8 @@ ContextInstance.prototype.getStartActivities = function getStartActivities(filte /** * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. * Returns undefined when the activity has no extensions to attach. - * @param {import('types').ElementBase} activity + * @param {import('#types').ElementBase} activity + * @returns {import('#types').IExtension | undefined} */ ContextInstance.prototype.loadExtensions = function loadExtensions(activity) { const io = new BpmnIO(activity, this); @@ -364,7 +369,6 @@ function Extensions(activity, context, extensions) { const extension = Extension(activity, context); if (extension) result.push(extension); } - /** @private */ this[K_ACTIVATED] = false; } @@ -376,14 +380,12 @@ Object.defineProperty(Extensions.prototype, 'count', { Extensions.prototype.activate = function activate(message) { if (this[K_ACTIVATED]) return; - /** @private */ this[K_ACTIVATED] = true; for (const extension of this.extensions) extension.activate(message); }; Extensions.prototype.deactivate = function deactivate(message) { if (!this[K_ACTIVATED]) return; - /** @private */ this[K_ACTIVATED] = false; for (const extension of this.extensions) extension.deactivate(message); }; diff --git a/src/Environment.js b/src/Environment.js index 06adfcf8..fac3b7ee 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -10,7 +10,7 @@ const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', /** * Holds global execution config: variables, injected services, timers, scripts engine, * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * @param {import('types').EnvironmentOptions} [options] + * @param {import('#types').EnvironmentOptions} [options] */ export function Environment(options = {}) { this.options = validateOptions(options); @@ -22,29 +22,28 @@ export function Environment(options = {}) { this.timers = options.timers || new Timers(); this.settings = { skipDiscard: true, ...options.settings }; this.Logger = options.Logger || DummyLogger; - /** @private */ this[K_SERVICES] = options.services || {}; - /** @private */ this[K_VARIABLES] = options.variables || {}; } -Object.defineProperties(Environment.prototype, { - variables: { - get() { - return this[K_VARIABLES]; - }, +Object.defineProperty(Environment.prototype, 'variables', { + /** @returns {Record} */ + get() { + return this[K_VARIABLES]; }, - services: { - get() { - return this[K_SERVICES]; - }, - set(value) { - const services = this[K_SERVICES]; - for (const name in services) { - if (!(name in value)) delete services[name]; - } - Object.assign(services, value); - }, +}); + +Object.defineProperty(Environment.prototype, 'services', { + /** @returns {Record} */ + get() { + return this[K_SERVICES]; + }, + set(value) { + const services = this[K_SERVICES]; + for (const name in services) { + if (!(name in value)) delete services[name]; + } + Object.assign(services, value); }, }); @@ -62,7 +61,7 @@ Environment.prototype.getState = function getState() { /** * Restore environment state captured by getState. Merges into the existing settings, * variables, and output rather than replacing them. - * @param {import('types').EnvironmentState} [state] + * @param {import('#types').EnvironmentState} [state] * @returns {this} */ Environment.prototype.recover = function recover(state) { @@ -78,7 +77,7 @@ Environment.prototype.recover = function recover(state) { /** * Clone the environment, optionally overriding options. Services are merged when * `overrideOptions.services` is supplied. - * @param {import('types').EnvironmentOptions} [overrideOptions] + * @param {import('#types').EnvironmentOptions} [overrideOptions] */ Environment.prototype.clone = function clone(overrideOptions) { const services = this[K_SERVICES]; @@ -107,7 +106,6 @@ Environment.prototype.clone = function clone(overrideOptions) { Environment.prototype.assignVariables = function assignVariables(newVars) { if (!newVars || typeof newVars !== 'object') return; - /** @private */ this[K_VARIABLES] = { ...this.variables, ...newVars, @@ -116,7 +114,7 @@ Environment.prototype.assignVariables = function assignVariables(newVars) { /** * Merge settings into the environment. Non-objects are ignored. - * @param {import('types').EnvironmentSettings} newSettings + * @param {import('#types').EnvironmentSettings} newSettings * @returns {this} */ Environment.prototype.assignSettings = function assignSettings(newSettings) { @@ -158,7 +156,7 @@ Environment.prototype.getServiceByName = function getServiceByName(serviceName) /** * Resolve an expression with the environment as scope, optionally extended by an element message. * @param {string} expression - * @param {import('types').ElementBrokerMessage} [message] Element message merged onto the resolution scope + * @param {import('#types').ElementBrokerMessage} [message] Element message merged onto the resolution scope * @param {any} [expressionFnContext] */ Environment.prototype.resolveExpression = function resolveExpression(expression, message, expressionFnContext) { @@ -176,7 +174,6 @@ Environment.prototype.resolveExpression = function resolveExpression(expression, * @param {CallableFunction} fn */ Environment.prototype.addService = function addService(name, fn) { - /** @private */ this[K_SERVICES][name] = fn; }; @@ -209,6 +206,9 @@ function validateOptions(input) { return options; } +/** + * @returns {import('#types').ILogger} + */ function DummyLogger() { return { debug, diff --git a/src/EventBroker.js b/src/EventBroker.js index 927d55f5..a7654559 100644 --- a/src/EventBroker.js +++ b/src/EventBroker.js @@ -1,9 +1,19 @@ import { Broker } from 'smqp'; import { makeErrorFromMessage } from './error/Errors.js'; +/** + * @typedef {object} BrokerApi Shape of the bound event helpers exposed by an EventBroker + * (and inherited by every element class that destructures from one). + * @property {(eventName: string, callback: CallableFunction, eventOptions?: { once?: boolean, [x: string]: any }) => import('smqp').Consumer} on + * @property {(eventName: string, callback: CallableFunction, eventOptions?: { [x: string]: any }) => import('smqp').Consumer} once + * @property {(eventName: string, onMessage?: (routingKey: string, message: import('#types').ElementBrokerMessage, owner: any) => boolean) => Promise} waitFor + * @property {(eventName: string, content?: Record, props?: any) => void} emit + * @property {(error: Error, content?: Record) => void} emitFatal + */ + /** * Build the broker for an activity, including run/format/execution/api exchanges and queues. - * @param {import('types').Activity} activity + * @param {import('#types').Activity} activity */ export function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); @@ -12,7 +22,7 @@ export function ActivityBroker(activity) { /** * Build the broker for a process, with an additional api-q bound to all api routing keys. - * @param {import('types').Process} owner + * @param {import('#types').Process} owner */ export function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); @@ -23,8 +33,8 @@ export function ProcessBroker(owner) { /** * Build the broker for a definition. Optionally registers a custom return-message handler. - * @param {import('types').Definition} owner - * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] + * @param {import('#types').Definition} owner + * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] */ export function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); @@ -32,7 +42,7 @@ export function DefinitionBroker(owner, onBrokerReturn) { /** * Build the broker for a message flow with a durable message exchange and message-q. - * @param {import('types').MessageFlow} owner + * @param {import('#types').MessageFlow} owner */ export function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { prefix: 'messageflow', autoDelete: false, durable: false }); @@ -70,7 +80,7 @@ function ExecutionBroker(brokerOwner, prefix, onBrokerReturn) { * Owns an smqp Broker on behalf of the calling element and exposes prefixed event helpers. * @param {any} brokerOwner Element that owns the broker, accessed as `broker.owner` * @param {{ prefix: string, autoDelete?: boolean, durable?: boolean }} options - * @param {(message: import('types').ElementBrokerMessage) => void} [onBrokerReturn] Override for unrouted return messages + * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] Override for unrouted return messages */ export function EventBroker(brokerOwner, options, onBrokerReturn) { this.options = options; @@ -80,19 +90,22 @@ export function EventBroker(brokerOwner, options, onBrokerReturn) { broker.assertExchange('event', 'topic', options); broker.on('return', onBrokerReturn ? onBrokerReturn.bind(brokerOwner) : this._onBrokerReturnFn.bind(this)); + /** @type {BrokerApi['on']} */ this.on = this.on.bind(this); + /** @type {BrokerApi['once']} */ this.once = this.once.bind(this); + /** @type {BrokerApi['waitFor']} */ this.waitFor = this.waitFor.bind(this); + /** @type {BrokerApi['emit']} */ this.emit = this.emit.bind(this); + /** @type {BrokerApi['emitFatal']} */ this.emitFatal = this.emitFatal.bind(this); } /** * Subscribe to a prefixed event. Errors are unwrapped via `makeErrorFromMessage`, * other events resolve to the owner's Api wrapper. - * @param {string} eventName Bare name (e.g. `enter`) or a full routing key - * @param {CallableFunction} callback - * @param {{ once?: boolean, [x: string]: any }} [eventOptions] + * @type {BrokerApi['on']} */ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { once: false }) { const key = this._getEventRoutingKey(eventName); @@ -108,9 +121,7 @@ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { onc /** * Subscribe to the next occurrence of an event. - * @param {string} eventName - * @param {CallableFunction} callback - * @param {any} [eventOptions] + * @type {BrokerApi['once']} */ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { return this.on(eventName, callback, { ...eventOptions, once: true }); @@ -118,9 +129,7 @@ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { /** * Promise-style wait for an event. Rejects on a mandatory `*.error` message. - * @param {string} eventName - * @param {(routingKey: string, message: import('types').ElementBrokerMessage, owner: any) => boolean | undefined} [onMessage] - * Filter; the promise only resolves when it returns truthy + * @type {BrokerApi['waitFor']} */ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { const key = this._getEventRoutingKey(eventName); @@ -153,9 +162,7 @@ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { /** * Publish a prefixed event message. - * @param {string} eventName - * @param {Record} [content] - * @param {any} [props] + * @type {BrokerApi['emit']} */ EventBroker.prototype.emit = function emit(eventName, content, props) { this.broker.publish('event', `${this.eventPrefix}.${eventName}`, { ...content }, { type: eventName, ...props }); @@ -163,8 +170,7 @@ EventBroker.prototype.emit = function emit(eventName, content, props) { /** * Emit a mandatory error event. Surfaces via `on('error', ...)` or causes a return message to throw. - * @param {Error} error - * @param {Record} [content] + * @type {BrokerApi['emitFatal']} */ EventBroker.prototype.emitFatal = function emitFatal(error, content) { this.emit('error', { ...content, error }, { mandatory: true }); diff --git a/src/MessageFormatter.js b/src/MessageFormatter.js index 890e87c6..71c988b1 100644 --- a/src/MessageFormatter.js +++ b/src/MessageFormatter.js @@ -12,22 +12,21 @@ const EXEC_ROUTING_KEY = 'run._formatting.exec'; * Enriches an element run message via async format start/end messages on the `format` exchange * before the run message is continued. Handlers publish enrichment by responding to a start * message with a matching end (or error) routing key. - * @param {import('types').ElementBase} element + * @param {import('#types').ElementBase} element */ export function Formatter(element) { const { id, broker, logger } = element; this.id = id; this.broker = broker; this.logger = logger; - /** @private */ this[K_ON_MESSAGE] = this._onMessage.bind(this); } /** * Format the given run message. Callback fires with `(err, content, formatted)` once * formatting completes; `formatted` is true when content was actually enriched. - * @param {import('types').ElementBrokerMessage} message - * @param {(err: Error | null, content?: import('types').ElementMessageContent, formatted?: boolean) => void} callback + * @param {import('#types').ElementBrokerMessage} message + * @param {(err: Error | null, content?: import('#types').ElementMessageContent, formatted?: boolean) => void} callback */ Formatter.prototype.format = function format(message, callback) { const correlationId = (this._runId = getUniqueId(message.fields.routingKey)); @@ -36,7 +35,6 @@ Formatter.prototype.format = function format(message, callback) { broker.publish('format', EXEC_ROUTING_KEY, {}, { correlationId, persistent: false }); - /** @private */ this[K_EXECUTION] = { correlationId, formatKey: message.fields.routingKey, @@ -64,7 +62,6 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { if (!asyncFormatting) { return this._complete(message); } - /** @private */ this[K_EXECUTION].executeMessage = message; } else { message.ack(); @@ -97,7 +94,6 @@ Formatter.prototype._onMessage = function onMessage(routingKey, message) { /** @internal */ Formatter.prototype._complete = function complete(message, isError) { const { runMessage, formatKey, callback, formatted, executeMessage } = this[K_EXECUTION]; - /** @private */ this[K_EXECUTION] = null; if (executeMessage) executeMessage.ack(); @@ -132,7 +128,6 @@ Formatter.prototype._enrich = function enrich(withContent) { break; default: { content[key] = withContent[key]; - /** @private */ this[K_EXECUTION].formatted = true; } } diff --git a/src/Timers.js b/src/Timers.js index 20be0244..81ec0cc5 100644 --- a/src/Timers.js +++ b/src/Timers.js @@ -10,7 +10,6 @@ export function Timers(options) { clearTimeout, ...options, }; - /** @private */ this[K_EXECUTING] = new Set(); this.setTimeout = this.setTimeout.bind(this); this.clearTimeout = this.clearTimeout.bind(this); @@ -58,7 +57,6 @@ Timers.prototype._getReference = function getReference(owner, callback, delay, a }; function RegisteredTimers(timersApi, owner) { - /** @private */ this[K_TIMER_API] = timersApi; this.owner = owner; this.setTimeout = this.setTimeout.bind(this); @@ -71,7 +69,6 @@ RegisteredTimers.prototype.setTimeout = function registeredSetTimeout(callback, }; RegisteredTimers.prototype.clearTimeout = function registeredClearTimeout(ref) { - /** @private */ this[K_TIMER_API].clearTimeout(ref); }; diff --git a/src/activity/Activity.js b/src/activity/Activity.js index 44de1a5b..de3af80b 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -26,26 +26,28 @@ const K_FORMATTER = Symbol.for('formatter'); /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param {import('types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution + * @param {import('#types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution * @param {import('moddle-context-serializer').SerializableElement} activityDef Parsed BPMN element definition - * @param {import('types').ContextInstance} context Per-execution registry and factory + * @param {import('#types').ContextInstance} context Per-execution registry and factory */ export function Activity(Behaviour, activityDef, context) { const { id, type = 'activity', name, behaviour = {} } = activityDef; const { attachedTo: attachedToRef, eventDefinitions } = behaviour; - /** @private */ this[K_ACTIVITY_DEF] = activityDef; this.id = id; this.type = type; this.name = name; this.behaviour = { ...behaviour, eventDefinitions }; this.Behaviour = Behaviour; + /** @type {import('moddle-context-serializer').Parent} */ this.parent = activityDef.parent ? cloneParent(activityDef.parent) : {}; this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; - /** @private */ + /** @type {import('#types').ActivityRunStatus} */ + this.status = undefined; + this[K_COUNTERS] = { taken: 0, discarded: 0, @@ -81,7 +83,6 @@ export function Activity(Behaviour, activityDef, context) { const inboundSourceIds = new Set(inboundSequenceFlows.map(({ sourceId }) => sourceId)); const isParallelJoin = activityDef.isParallelGateway && inboundSourceIds.size > 1; - /** @private */ this[K_FLOWS] = { inboundSequenceFlows, inboundAssociations, @@ -90,7 +91,6 @@ export function Activity(Behaviour, activityDef, context) { outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows), }; - /** @private */ this[K_FLAGS] = { isEnd: !outboundSequenceFlows.length, isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, @@ -105,10 +105,8 @@ export function Activity(Behaviour, activityDef, context) { isCatching: activityDef.isCatching, lane: activityDef.lane?.id, }; - /** @private */ this[K_EXEC] = new Map(); - /** @private */ this[K_MESSAGE_HANDLERS] = { onInbound: this._onInbound.bind(this), onRunMessage: this._onRunMessage.bind(this), @@ -116,13 +114,9 @@ export function Activity(Behaviour, activityDef, context) { onExecutionMessage: this._onExecutionMessage.bind(this), }; - /** @private */ this[K_EVENT_DEFINITIONS] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); - /** @private */ this[K_EXTENSIONS] = context.loadExtensions(this); - /** @private */ this[K_CONSUMING] = false; - /** @private */ this[K_CONSUMING_RUN_Q] = undefined; } @@ -157,7 +151,6 @@ Object.defineProperties(Activity.prototype, { get() { let formatter = this[K_FORMATTER]; if (formatter) return formatter; - formatter = this[K_FORMATTER] = new Formatter(this); return formatter; }, @@ -262,10 +255,10 @@ Object.defineProperties(Activity.prototype, { /** * Subscribe to inbound flows and start consuming the inbound queue. + * @returns {void} */ Activity.prototype.activate = function activate() { if (this[K_ACTIVATED]) return; - /** @private */ this[K_ACTIVATED] = true; return this.addInboundListeners() && this._consumeInbound(); }; @@ -274,7 +267,6 @@ Activity.prototype.activate = function activate() { * Cancel inbound subscriptions and any pending run/format consumers. */ Activity.prototype.deactivate = function deactivate() { - /** @private */ this[K_ACTIVATED] = false; const broker = this.broker; this.removeInboundListeners(); @@ -317,7 +309,6 @@ Activity.prototype.run = function run(runContent) { broker.publish('run', 'run.enter', content); broker.publish('run', 'run.start', cloneContent(content)); - /** @private */ this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -325,6 +316,7 @@ Activity.prototype.run = function run(runContent) { /** * Snapshot activity state for recover. * Returns undefined when nothing is running and `disableTrackState` is set. + * @returns {import('#types').ActivityState} */ Activity.prototype.getState = function getState() { const status = this.status; @@ -348,7 +340,7 @@ Activity.prototype.getState = function getState() { /** * Restore activity state captured by getState. Cannot be called while running. - * @param {import('types').ActivityState} [state] + * @param {import('#types').ActivityState} [state] * @returns {this} this when state was applied * @throws {Error} when activity is currently running */ @@ -361,7 +353,6 @@ Activity.prototype.recover = function recover(state) { const exec = this[K_EXEC]; exec.set('executionId', state.executionId); - /** @private */ this[K_COUNTERS] = { ...this[K_COUNTERS], ...state.counters }; if (state.execution) { @@ -390,7 +381,6 @@ Activity.prototype.resume = function resume() { const content = this._createMessage(); this.broker.publish('run', 'run.resume', content, { persistent: false }); - /** @private */ this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -408,7 +398,6 @@ Activity.prototype.discard = function discard(discardContent) { const broker = this.broker; broker.getQueue('run-q').purge(); broker.publish('run', 'run.discard', cloneContent(this[K_STATE_MESSAGE].content)); - /** @private */ this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -458,6 +447,7 @@ Activity.prototype.stop = function stop() { */ Activity.prototype.next = function next() { if (!this.environment.settings.step) return; + /** @type {import('#types').ElementBrokerMessage} */ const stateMessage = this[K_STATE_MESSAGE]; if (!stateMessage) return; if (this.status === 'executing') return false; @@ -476,9 +466,10 @@ Activity.prototype.shake = function shake() { /** * Evaluate outbound sequence flows for the given source message. - * @param {import('types').ElementBrokerMessage} fromMessage Source run message + * @param {import('#types').ElementBrokerMessage} fromMessage Source run message * @param {boolean} discardRestAtTake When true, take only the first matching flow and discard the rest * @param {(err: Error, evaluationResult: any) => void} callback + * @returns {void} */ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) { return this[K_FLOWS].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback); @@ -486,7 +477,8 @@ Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, dis /** * Resolve an Api wrapper for the activity, preferring the running execution if any. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ Activity.prototype.getApi = function getApi(message) { const execution = this[K_EXEC].get('execution'); @@ -514,7 +506,6 @@ Activity.prototype._runDiscard = function runDiscard(discardContent) { const content = this._createMessage({ ...discardContent, executionId }); this.broker.publish('run', 'run.discard', content); - /** @private */ this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -549,7 +540,6 @@ Activity.prototype._discardRun = function discardRun() { broker.getQueue('run-q').purge(); broker.publish('run', discardRoutingKey, cloneContent(stateMessage.content), { correlationId: stateMessage.properties.correlationId }); - /** @private */ this[K_CONSUMING] = true; this._consumeRunQ(); }; @@ -660,7 +650,6 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message /** @internal */ Activity.prototype._consumeRunQ = function consumeRunQ() { - /** @private */ this[K_CONSUMING_RUN_Q] = true; this.broker.getQueue('run-q').assertConsumer(this[K_MESSAGE_HANDLERS].onRunMessage, { exclusive: true, consumerTag: '_activity-run' }); }; @@ -669,7 +658,6 @@ Activity.prototype._consumeRunQ = function consumeRunQ() { Activity.prototype._pauseRunQ = function pauseRunQ() { if (!this[K_CONSUMING_RUN_Q]) return; - /** @private */ this[K_CONSUMING_RUN_Q] = false; this.broker.cancel('_activity-run'); }; @@ -708,7 +696,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, const id = this.id; const step = this.environment.settings.step; - /** @private */ this[K_STATE_MESSAGE] = message; switch (routingKey) { @@ -717,7 +704,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, this.status = 'entered'; if (!isRedelivered) { - /** @private */ this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate(cloneMessage(message)); this._publishEvent('enter', content, { correlationId }); @@ -728,7 +714,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, this.logger.debug(`<${id}> discard`, isRedelivered ? 'redelivered' : ''); this.status = 'discard'; - /** @private */ this[K_EXEC].delete('execution'); if (this.extensions) this.extensions.activate(cloneMessage(message)); @@ -752,14 +737,12 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, const execution = this[K_EXEC].get('execution'); if (!isRedelivered && execution) { if (execution.completed) return message.ack(); - /** @private */ this[K_EXECUTE_MESSAGE] = message; return execution.passthrough(message); } } case 'run.execute': { this.status = 'executing'; - /** @private */ this[K_EXECUTE_MESSAGE] = message; if (isRedelivered && this.extensions) this.extensions.activate(cloneMessage(message)); @@ -780,7 +763,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, this.logger.debug(`<${id}> end`, isRedelivered ? 'redelivered' : ''); if (isRedelivered) break; - /** @private */ this[K_COUNTERS].taken++; this.status = 'end'; @@ -803,7 +785,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, } case 'run.discarded': { this.logger.debug(`<${content.executionId} (${id})> discarded`); - /** @private */ this[K_COUNTERS].discarded++; this.status = 'discarded'; @@ -1046,7 +1027,6 @@ Activity.prototype._onStop = function onStop(message) { this.stopped = true; - /** @private */ this[K_CONSUMING] = false; const broker = this.broker; this._pauseRunQ(); @@ -1121,6 +1101,5 @@ Activity.prototype._deactivateRunConsumers = function _deactivateRunConsumers() broker.cancel('_activity-api'); this._pauseRunQ(); broker.cancel('_activity-execution'); - /** @private */ this[K_CONSUMING] = false; }; diff --git a/src/activity/ActivityExecution.js b/src/activity/ActivityExecution.js index bce7e8a7..8af971bc 100644 --- a/src/activity/ActivityExecution.js +++ b/src/activity/ActivityExecution.js @@ -8,22 +8,18 @@ const K_POSTPONED = Symbol.for('postponed'); /** * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour * and drives the execute message flow over the activity broker. - * @param {import('types').Activity} activity - * @param {import('types').ContextInstance} context + * @param {import('./Activity.js').Activity} activity + * @param {import('../Context.js').ContextInstance} context */ export function ActivityExecution(activity, context) { this.activity = activity; this.context = context; this.id = activity.id; this.broker = activity.broker; - /** @private */ this[K_POSTPONED] = new Set(); - /** @private */ this[K_COMPLETED] = false; - /** @private */ this[K_EXECUTE_Q] = this.broker.assertQueue('execute-q', { durable: true, autoDelete: false }); - /** @private */ this[K_MESSAGE_HANDLERS] = { onParentApiMessage: this._onParentApiMessage.bind(this), onExecuteMessage: this._onExecuteMessage.bind(this), @@ -39,7 +35,7 @@ Object.defineProperty(ActivityExecution.prototype, 'completed', { /** * Begin executing the activity behaviour. Resumes if the message is redelivered. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage * @throws {Error} when message or executionId is missing */ ActivityExecution.prototype.execute = function execute(executeMessage) { @@ -55,7 +51,6 @@ ActivityExecution.prototype.execute = function execute(executeMessage) { })); if (executeMessage.fields.redelivered) { - /** @private */ this[K_POSTPONED].clear(); this._debug('resume execution'); @@ -82,7 +77,6 @@ ActivityExecution.prototype.activate = function activate() { broker.bindQueue('execute-q', 'execution', 'execute.#', { priority: 100 }); const { onExecuteMessage, onParentApiMessage } = this[K_MESSAGE_HANDLERS]; - /** @private */ this[K_EXECUTE_Q].assertConsumer(onExecuteMessage, { exclusive: true, prefetch: batchSize * 2, @@ -121,7 +115,8 @@ ActivityExecution.prototype.discard = function discard() { /** * Resolve an Api wrapper, preferring a behaviour-specific Api when the source exposes one. - * @param {import('types').ElementBrokerMessage} [apiMessage] + * @param {import('#types').ElementBrokerMessage} [apiMessage] + * @returns {import('#types').IApi} */ ActivityExecution.prototype.getApi = function getApi(apiMessage) { const self = this; @@ -148,7 +143,7 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { /** * Pass an execute message straight to the behaviour, executing first if no source is set up yet. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage */ ActivityExecution.prototype.passthrough = function passthrough(executeMessage) { if (!this.source) return this.execute(executeMessage); @@ -181,11 +176,10 @@ ActivityExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. - * @param {import('types').ActivityExecutionState} [state] + * @param {import('#types').ActivityExecutionState} [state] * @returns {this} */ ActivityExecution.prototype.recover = function recover(state) { - /** @private */ this[K_POSTPONED].clear(); if (!state) return this; @@ -311,7 +305,6 @@ ActivityExecution.prototype._onExecutionCompleted = function onExecutionComplete } this._debug('completed execution', executionId); - /** @private */ this[K_COMPLETED] = true; message.ack(true); @@ -361,7 +354,6 @@ ActivityExecution.prototype._publishExecutionCompleted = function publishExecuti completeContent, correlationId ) { - /** @private */ this[K_COMPLETED] = true; this.broker.publish( diff --git a/src/condition.js b/src/condition.js index 37bf2c85..df028057 100644 --- a/src/condition.js +++ b/src/condition.js @@ -1,7 +1,7 @@ import { ExecutionScope } from './activity/ExecutionScope.js'; /** * Script condition - * @param {import('types').ElementBase} owner + * @param {import('#types').ElementBase} owner * @param {any} script * @param {string} language */ @@ -30,7 +30,7 @@ ScriptCondition.prototype.execute = function execute(message, callback) { /** * Expression condition - * @param {import('types').ElementBase} owner + * @param {import('#types').ElementBase} owner * @param {string} expression */ export function ExpressionCondition(owner, expression) { @@ -41,7 +41,7 @@ export function ExpressionCondition(owner, expression) { /** * Execute - * @param {any} message + * @param {import('#types').ElementBrokerMessage} message * @param {CallableFunction} callback */ ExpressionCondition.prototype.execute = function execute(message, callback) { diff --git a/src/definition/Definition.js b/src/definition/Definition.js index f5a85329..5ceeb72a 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -18,8 +18,8 @@ import { /** * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and * mediates inter-process messaging. - * @param {import('types').ContextInstance} context - * @param {import('types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged + * @param {import('../Context.js').ContextInstance} context + * @param {import('#types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged */ export function Definition(context, options) { if (!(this instanceof Definition)) return new Definition(context, options); @@ -40,19 +40,15 @@ export function Definition(context, options) { this.context = context; } - /** @private */ this[K_COUNTERS] = { completed: 0, discarded: 0, }; - /** @private */ this[K_STOPPED] = false; - /** @private */ this[K_EXECUTION] = new Map(); const onBrokerReturn = this._onBrokerReturnFn.bind(this); - /** @private */ this[K_MESSAGE_HANDLERS] = { onBrokerReturn, onApiMessage: this._onApiMessage.bind(this), @@ -70,6 +66,7 @@ export function Definition(context, options) { this.emit = emit; this.emitFatal = emitFatal; + /** @type {import('#types').ILogger} */ this.logger = environment.Logger(type.toLowerCase()); } @@ -116,8 +113,8 @@ Object.defineProperties(Definition.prototype, { /** * Start running the definition. Accepts run options, a callback, or both. * The callback fires once on leave, stop, or error. - * @param {Record | import('types').runCallback} [optionsOrCallback] - * @param {import('types').runCallback} [optionalCallback] + * @param {Record | import('#types').runCallback} [optionsOrCallback] + * @param {import('#types').runCallback} [optionalCallback] * @returns {this} * @throws {Error} when already running and no callback is supplied */ @@ -153,7 +150,7 @@ Definition.prototype.run = function run(optionsOrCallback, optionalCallback) { /** * Resume after recover by republishing the last run message. The callback fires once on * leave, stop, or error. - * @param {import('types').runCallback} [callback] + * @param {import('#types').runCallback} [callback] * @returns {this} */ Definition.prototype.resume = function resume(callback) { @@ -163,7 +160,6 @@ Definition.prototype.resume = function resume(callback) { throw err; } - /** @private */ this[K_STOPPED] = false; if (!this.status) return this; @@ -195,7 +191,7 @@ Definition.prototype.getState = function getState() { /** * Restore definition state captured by getState. - * @param {import('types').DefinitionState} [state] + * @param {import('#types').DefinitionState} [state] * @returns {this} * @throws {Error} when called on a running definition */ @@ -203,15 +199,12 @@ Definition.prototype.recover = function recover(state) { if (this.isRunning) throw new Error('cannot recover running definition'); if (!state) return this; - /** @private */ this[K_STOPPED] = !!state.stopped; - /** @private */ this[K_STATUS] = state.status; const exec = this[K_EXECUTION]; exec.set('executionId', state.executionId); if (state.counters) { - /** @private */ this[K_COUNTERS] = { ...this[K_COUNTERS], ...state.counters }; } @@ -329,7 +322,7 @@ Definition.prototype.getElementById = function getElementById(elementId) { /** * List currently postponed activities as Api wrappers. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ Definition.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; @@ -339,7 +332,8 @@ Definition.prototype.getPostponed = function getPostponed(...args) { /** * Resolve a Definition Api wrapper, preferring the running execution if any. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} * @throws {Error} when the definition is not running and no message is given */ Definition.prototype.getApi = function getApi(message) { @@ -352,7 +346,7 @@ Definition.prototype.getApi = function getApi(message) { /** * Send a delegated signal to the running definition. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Definition.prototype.signal = function signal(message) { return this.getApi().signal(message, { delegate: true }); @@ -360,7 +354,7 @@ Definition.prototype.signal = function signal(message) { /** * Cancel a running activity inside the definition by delegated api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Definition.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { delegate: true }); @@ -394,7 +388,6 @@ Definition.prototype.stop = function stop() { /** @internal */ Definition.prototype._activateRunConsumers = function activateRunConsumers() { - /** @private */ this[K_CONSUMING] = true; const broker = this.broker; const { onApiMessage, onRunMessage } = this[K_MESSAGE_HANDLERS]; @@ -414,7 +407,6 @@ Definition.prototype._deactivateRunConsumers = function deactivateRunConsumers() broker.cancel('_definition-api'); broker.cancel('_definition-run'); broker.cancel('_definition-execution'); - /** @private */ this[K_CONSUMING] = false; }; @@ -437,14 +429,12 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) } const exec = this[K_EXECUTION]; - /** @private */ this[K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this.logger.debug(`<${this.executionId} (${this.id})> enter`); - /** @private */ this[K_STATUS] = 'entered'; if (fields.redelivered) break; @@ -454,20 +444,17 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) } case 'run.start': { this.logger.debug(`<${this.executionId} (${this.id})> start`); - /** @private */ this[K_STATUS] = 'start'; this._publishEvent('start', content); break; } case 'run.execute': { - /** @private */ this[K_STATUS] = 'executing'; const executeMessage = cloneMessage(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - /** @private */ this[K_EXECUTE_MESSAGE] = message; this.broker.getQueue('execution-q').assertConsumer(this[K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, @@ -488,11 +475,9 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) case 'run.end': { if (this[K_STATUS] === 'end') break; - /** @private */ this[K_COUNTERS].completed++; this.logger.debug(`<${this.executionId} (${this.id})> completed`); - /** @private */ this[K_STATUS] = 'end'; this.broker.publish('run', 'run.leave', content); this._publishEvent('end', content); @@ -512,17 +497,14 @@ Definition.prototype._onRunMessage = function onRunMessage(routingKey, message) case 'run.discarded': { if (this[K_STATUS] === 'discarded') break; - /** @private */ this[K_COUNTERS].discarded++; - /** @private */ this[K_STATUS] = 'discarded'; this.broker.publish('run', 'run.leave', content); break; } case 'run.leave': { message.ack(); - /** @private */ this[K_STATUS] = undefined; this._deactivateRunConsumers(); @@ -578,7 +560,6 @@ Definition.prototype._onExecutionMessage = function onExecutionMessage(routingKe } const executeMessage = this[K_EXECUTE_MESSAGE]; - /** @private */ this[K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; @@ -604,7 +585,6 @@ Definition.prototype._publishEvent = function publishEvent(action, content, msgO /** @internal */ Definition.prototype._onStop = function onStop() { - /** @private */ this[K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop', this._createMessage()); @@ -621,7 +601,6 @@ Definition.prototype._onBrokerReturnFn = function onBrokerReturn(message) { /** @internal */ Definition.prototype._reset = function reset() { - /** @private */ this[K_EXECUTION].delete('executionId'); this._deactivateRunConsumers(); this.broker.purgeQueue('run-q'); diff --git a/src/definition/DefinitionExecution.js b/src/definition/DefinitionExecution.js index ef948fbb..1a79175f 100644 --- a/src/definition/DefinitionExecution.js +++ b/src/definition/DefinitionExecution.js @@ -10,13 +10,12 @@ const K_PROCESSES = Symbol.for('processes'); /** * Drives the execution of a Definition. Activates executable processes, routes inter-process * delegate messages and call activity hand-offs, and rolls completion up to the Definition. - * @param {import('types').Definition} definition - * @param {import('types').ContextInstance} context + * @param {import('./Definition.js').Definition} definition + * @param {import('../Context.js').ContextInstance} context */ export function DefinitionExecution(definition, context) { const broker = definition.broker; - /** @private */ this[K_PARENT] = definition; this.id = definition.id; this.type = definition.type; @@ -27,7 +26,7 @@ export function DefinitionExecution(definition, context) { const processes = context.getProcesses(); /** @type {Set} */ const ids = new Set(); - /** @type {Set} */ + /** @type {Set} */ const executable = new Set(); for (const bp of processes) { bp.environment.assignVariables(environment.variables); @@ -36,33 +35,26 @@ export function DefinitionExecution(definition, context) { if (bp.isExecutable) executable.add(bp); } - /** @private */ this[K_PROCESSES] = { /** @type {import('../process/Process.js').Process[]} */ processes, ids, executable, - /** @type {Set} */ + /** @type {Set} */ running: new Set(), - /** @type {Set} */ + /** @type {Set} */ postponed: new Set(), }; broker.assertExchange('execution', 'topic', { autoDelete: false, durable: true }); this.executionId = undefined; - /** @private */ this[K_COMPLETED] = false; - /** @private */ this[K_STOPPED] = false; - /** @private */ this[K_ACTIVATED] = false; - /** @private */ this[K_STATUS] = 'init'; - /** @private */ this[K_PROCESSES_Q] = undefined; - /** @private */ this[K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onCallActivity: this._onCallActivity.bind(this), @@ -135,7 +127,7 @@ Object.defineProperties(DefinitionExecution.prototype, { /** * Activate executable processes and start the definition execution. Resumes if the message * is redelivered. When `content.processId` is set, only that process is started. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage * @throws {Error} when message or executionId is missing */ DefinitionExecution.prototype.execute = function execute(executeMessage) { @@ -144,16 +136,13 @@ DefinitionExecution.prototype.execute = function execute(executeMessage) { const executionId = (this.executionId = content.executionId); if (!executionId) throw new Error('Definition execution requires execution id'); - /** @private */ this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage, { executionId, state: 'start', }); - /** @private */ this[K_STOPPED] = false; - /** @private */ this[K_PROCESSES_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); if (executeMessage.fields.redelivered) { @@ -190,7 +179,6 @@ DefinitionExecution.prototype.resume = function resume() { const { running, postponed } = this[K_PROCESSES]; this._activate(running); postponed.clear(); - /** @private */ this[K_PROCESSES_Q].consume(this[K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}`, @@ -203,18 +191,15 @@ DefinitionExecution.prototype.resume = function resume() { /** * Restore execution state captured by getState. Reinstates running processes from the snapshot. - * @param {import('types').DefinitionExecutionState} [state] + * @param {import('#types').DefinitionExecutionState} [state] * @returns {this} */ DefinitionExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - /** @private */ this[K_STOPPED] = state.stopped; - /** @private */ this[K_COMPLETED] = state.completed; - /** @private */ this[K_STATUS] = state.status; this._debug(`recover ${this[K_STATUS]} definition execution`); @@ -318,7 +303,8 @@ DefinitionExecution.prototype.getState = function getState() { /** * Resolve a Definition Api or, when the message belongs to a child process, its process Api. - * @param {import('types').ElementBrokerMessage} [apiMessage] + * @param {import('#types').ElementBrokerMessage} [apiMessage] + * @returns {import('#types').IApi} */ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { if (!apiMessage) apiMessage = this[K_EXECUTE_MESSAGE] || { content: this._createMessage() }; @@ -346,7 +332,7 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { /** * List currently postponed activities across every running process. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { let result = []; @@ -367,14 +353,12 @@ DefinitionExecution.prototype._start = function start() { return this._complete('error', { error: new Error('No executable process') }); } - /** @private */ this[K_STATUS] = 'start'; for (const bp of executable) bp.init(); for (const bp of executable) bp.run(); postponed.clear(); - /** @private */ this[K_PROCESSES_Q].assertConsumer(this[K_MESSAGE_HANDLERS].onProcessMessage, { prefetch: 1000, consumerTag: `_definition-activity-${this.executionId}`, @@ -388,7 +372,6 @@ DefinitionExecution.prototype._activate = function activate(processList) { consumerTag: '_definition-api-consumer', }); for (const bp of processList) this._activateProcess(bp); - /** @private */ this[K_ACTIVATED] = true; }; @@ -440,7 +423,6 @@ DefinitionExecution.prototype._onChildEvent = function onChildEvent(routingKey, this.broker.publish('event', routingKey, content, { ...message.properties, mandatory: false }); if (!isDirectChild) return; - /** @private */ this[K_PROCESSES_Q].queueMessage(message.fields, cloneContent(content), message.properties); }; @@ -449,7 +431,6 @@ DefinitionExecution.prototype._deactivate = function deactivate() { this.broker.cancel('_definition-api-consumer'); this.broker.cancel(`_definition-activity-${this.executionId}`); for (const bp of this[K_PROCESSES].running) this._deactivateProcess(bp); - /** @private */ this[K_ACTIVATED] = false; }; @@ -484,7 +465,6 @@ DefinitionExecution.prototype._onProcessMessage = function onProcessMessage(rout switch (routingKey) { case 'process.enter': - /** @private */ this[K_STATUS] = 'executing'; break; case 'process.discarded': { @@ -574,12 +554,10 @@ DefinitionExecution.prototype._onProcessCompleted = function onProcessCompleted( DefinitionExecution.prototype._onStopped = function onStopped(message) { const running = this[K_PROCESSES].running; this._debug(`stop definition execution (stop process executions ${running.size})`); - /** @private */ this[K_PROCESSES_Q].close(); for (const bp of new Set(running)) bp.stop(); this._deactivate(); - /** @private */ this[K_STOPPED] = true; return this.broker.publish( 'execution', @@ -610,7 +588,6 @@ DefinitionExecution.prototype._onApiMessage = function onApiMessage(routingKey, if (this.executionId !== message.content.executionId) return; if (messageType === 'stop') { - /** @private */ this[K_PROCESSES_Q].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false }); } }; @@ -673,7 +650,6 @@ DefinitionExecution.prototype._onMessageOutbound = function onMessageOutbound(ro targetProcess = targetProcess || this.context.getNewProcessById(target.processId); this._activateProcess(targetProcess); - /** @private */ this[K_PROCESSES].running.add(targetProcess); targetProcess.init(); targetProcess.run(); @@ -707,7 +683,6 @@ DefinitionExecution.prototype._onCallActivity = function onCallActivity(routingK this._debug(`call from <${fromParent.id}.${fromId}> to <${calledElement}>`); this._activateProcess(targetProcess); - /** @private */ this[K_PROCESSES].running.add(targetProcess); targetProcess.init(bpExecutionId); targetProcess.run({ inbound: [cloneContent(content)] }); @@ -789,9 +764,7 @@ DefinitionExecution.prototype._complete = function complete(completionType, cont const stateMessage = this[K_EXECUTE_MESSAGE]; this._debug(`definition execution ${completionType} in ${Date.now() - stateMessage.properties.timestamp}ms`); if (!content) content = this._createMessage(); - /** @private */ this[K_COMPLETED] = true; - /** @private */ this[K_STATUS] = completionType; this.broker.deleteQueue(this[K_PROCESSES_Q].name); @@ -847,6 +820,5 @@ DefinitionExecution.prototype._getProcessApiByExecutionId = function getProcessA /** @internal */ DefinitionExecution.prototype._debug = function debug(logMessage) { - /** @private */ this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; diff --git a/src/eventDefinitions/CancelEventDefinition.js b/src/eventDefinitions/CancelEventDefinition.js index 0be889a8..1bd2834c 100644 --- a/src/eventDefinitions/CancelEventDefinition.js +++ b/src/eventDefinitions/CancelEventDefinition.js @@ -26,9 +26,7 @@ CancelEventDefinition.prototype.execute = function execute(executeMessage) { }; CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[K_COMPLETED] = false; const executeContent = executeMessage.content; @@ -94,7 +92,6 @@ CancelEventDefinition.prototype._onCatchMessage = function onCatchMessage(_, mes }; CancelEventDefinition.prototype._complete = function complete(output) { - /** @private */ this[K_COMPLETED] = true; this._stop(); this._debug('completed'); @@ -108,7 +105,6 @@ CancelEventDefinition.prototype._complete = function complete(output) { CancelEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) { switch (message.properties.type) { case 'discard': { - /** @private */ this[K_COMPLETED] = true; this._stop(); const content = cloneContent(this[K_EXECUTE_MESSAGE].content); diff --git a/src/eventDefinitions/CompensateEventDefinition.js b/src/eventDefinitions/CompensateEventDefinition.js index 89fce2fa..098d93dc 100644 --- a/src/eventDefinitions/CompensateEventDefinition.js +++ b/src/eventDefinitions/CompensateEventDefinition.js @@ -17,14 +17,10 @@ export function CompensateEventDefinition(activity, eventDefinition, context) { this.logger = environment.Logger(type.toLowerCase()); if (!isThrowing) { - /** @private */ this[K_COMPLETED] = false; - /** @private */ this[K_ASSOCIATIONS] = context.getOutboundAssociations(id); const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-q`; - /** @private */ this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - /** @private */ this[K_COMPENSATE_Q] = broker.assertQueue('compensate-q', { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 400 }); } @@ -41,13 +37,10 @@ CompensateEventDefinition.prototype.execute = function execute(executeMessage) { }; CompensateEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[K_COMPLETED] = false; if (executeMessage.fields.routingKey === 'execute.compensating') { this._debug('resumed at compensating'); - /** @private */ this[K_COMPLETED] = true; return this._compensate(); } @@ -65,7 +58,6 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute consumerTag: '_oncollect-messages', }); - /** @private */ this[K_MESSAGE_Q].consume(this._onCompensateApiMessage.bind(this), { noAck: true, consumerTag: `_oncompensate-${executionId}`, @@ -117,7 +109,6 @@ CompensateEventDefinition.prototype._onCollect = function onCollect(routingKey, }; CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompensateApiMessage(routingKey, message) { - /** @private */ this[K_COMPLETED] = true; const output = message.content.message; const broker = this.broker; @@ -133,7 +124,6 @@ CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompens }); catchContent.parent = shiftParent(catchContent.parent); - /** @private */ this[K_COMPENSATE_Q].queueMessage({ routingKey: 'execute.compensated' }, cloneContent(executeContent)); broker.publish('execution', 'execute.compensating', cloneContent(executeContent, { message: { ...output } })); @@ -156,10 +146,8 @@ CompensateEventDefinition.prototype._onCollected = function onCollected(routingK }; CompensateEventDefinition.prototype._onDiscardApiMessage = function onDiscardApiMessage(routingKey, message) { - /** @private */ this[K_COMPLETED] = true; this._stop(); - /** @private */ this[K_COMPENSATE_Q].purge(); for (const association of this[K_ASSOCIATIONS]) association.discard(cloneMessage(message)); return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content)); @@ -186,7 +174,6 @@ CompensateEventDefinition.prototype._stopCollect = function stopCollect() { broker.cancel(`_api-${executionId}`); broker.cancel(`_oncompensate-${executionId}`); broker.cancel('_oncollect-messages'); - /** @private */ this[K_MESSAGE_Q].purge(); }; diff --git a/src/eventDefinitions/ConditionalEventDefinition.js b/src/eventDefinitions/ConditionalEventDefinition.js index 2ac0699a..717e2826 100644 --- a/src/eventDefinitions/ConditionalEventDefinition.js +++ b/src/eventDefinitions/ConditionalEventDefinition.js @@ -24,7 +24,6 @@ Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { }); ConditionalEventDefinition.prototype.execute = function execute(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; if (!this.condition) return this._setup(executeMessage); @@ -68,7 +67,7 @@ ConditionalEventDefinition.prototype._setup = function setup(executeMessage) { /** * Evaluate condition - * @param {import('types').ElementBrokerMessage} message + * @param {import('#types').ElementBrokerMessage} message * @param {CallableFunction} callback */ ConditionalEventDefinition.prototype.evaluate = function evaluate(message, callback) { diff --git a/src/eventDefinitions/ErrorEventDefinition.js b/src/eventDefinitions/ErrorEventDefinition.js index d91ac043..b45dcace 100644 --- a/src/eventDefinitions/ErrorEventDefinition.js +++ b/src/eventDefinitions/ErrorEventDefinition.js @@ -23,11 +23,9 @@ export function ErrorEventDefinition(activity, eventDefinition) { const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing) { - /** @private */ this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - /** @private */ this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 300 }); } @@ -44,9 +42,7 @@ ErrorEventDefinition.prototype.execute = function execute(executeMessage) { }; ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[K_COMPLETED] = false; const executeContent = executeMessage.content; @@ -55,7 +51,6 @@ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessa const info = (this[K_REFERENCE_INFO] = this._getReferenceInfo(executeMessage)); - /** @private */ this[K_MESSAGE_Q].consume(this._onThrowApiMessage.bind(this), { noAck: true, consumerTag: `_onthrow-${executionId}`, @@ -149,7 +144,6 @@ ErrorEventDefinition.prototype._onThrowApiMessage = function onThrowApiMessage(r }; ErrorEventDefinition.prototype._catchError = function catchError(routingKey, message, error) { - /** @private */ this[K_COMPLETED] = true; this._stop(); @@ -188,7 +182,6 @@ ErrorEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, switch (messageType) { case 'discard': { - /** @private */ this[K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content)); @@ -206,7 +199,6 @@ ErrorEventDefinition.prototype._stop = function stop() { broker.cancel(`_onthrow-${executionId}`); broker.cancel(`_onerror-${executionId}`); broker.cancel(`_api-${executionId}`); - /** @private */ this[K_MESSAGE_Q].purge(); }; diff --git a/src/eventDefinitions/EscalationEventDefinition.js b/src/eventDefinitions/EscalationEventDefinition.js index db1e237e..fb5cbb42 100644 --- a/src/eventDefinitions/EscalationEventDefinition.js +++ b/src/eventDefinitions/EscalationEventDefinition.js @@ -25,11 +25,9 @@ export function EscalationEventDefinition(activity, eventDefinition) { const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing) { - /** @private */ this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - /** @private */ this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 400 }); } @@ -46,9 +44,7 @@ EscalationEventDefinition.prototype.execute = function execute(executeMessage) { }; EscalationEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[K_COMPLETED] = false; const executeContent = executeMessage.content; @@ -56,7 +52,6 @@ EscalationEventDefinition.prototype.executeCatch = function executeCatch(execute const info = (this[K_REFERENCE] = this._getReferenceInfo(executeMessage)); const broker = this.broker; - /** @private */ this[K_MESSAGE_Q].consume(this._onCatchMessage.bind(this), { noAck: true, consumerTag: `_onescalate-${executionId}`, @@ -106,7 +101,6 @@ EscalationEventDefinition.prototype._onCatchMessage = function onCatchMessage(ro if (getPropertyValue(message, 'content.message.id') !== info.message.id) return; const output = message.content.message; - /** @private */ this[K_COMPLETED] = true; this._stop(); @@ -133,7 +127,6 @@ EscalationEventDefinition.prototype._onApiMessage = function onApiMessage(routin return this._onCatchMessage(routingKey, message); } case 'discard': { - /** @private */ this[K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content)); diff --git a/src/eventDefinitions/EventDefinitionExecution.js b/src/eventDefinitions/EventDefinitionExecution.js index 68c41f1c..eaecfcf7 100644 --- a/src/eventDefinitions/EventDefinitionExecution.js +++ b/src/eventDefinitions/EventDefinitionExecution.js @@ -7,24 +7,20 @@ export function EventDefinitionExecution(activity, eventDefinitions, completedRo this.broker = activity.broker; this.eventDefinitions = eventDefinitions; this.completedRoutingKey = completedRoutingKey; - /** @private */ this[K_COMPLETED] = false; - /** @private */ this[K_STOPPED] = false; - /** @private */ this[K_EXECUTE_MESSAGE] = null; } -Object.defineProperties(EventDefinitionExecution.prototype, { - completed: { - get() { - return this[K_COMPLETED]; - }, +Object.defineProperty(EventDefinitionExecution.prototype, 'completed', { + get() { + return this[K_COMPLETED]; }, - stopped: { - get() { - return this[K_STOPPED]; - }, +}); + +Object.defineProperty(EventDefinitionExecution.prototype, 'stopped', { + get() { + return this[K_STOPPED]; }, }); @@ -36,7 +32,6 @@ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { const broker = this.broker; - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; const executionId = content.executionId; @@ -111,7 +106,6 @@ EventDefinitionExecution.prototype._onExecuteMessage = function onExecuteMessage EventDefinitionExecution.prototype._complete = function complete(message) { const { executionId, type, index, parent } = message.content; - /** @private */ this[K_COMPLETED] = true; this._debug(executionId, `event definition ${type} completed, index ${index}`); @@ -135,7 +129,6 @@ EventDefinitionExecution.prototype._executeDefinition = function executeDefiniti }; EventDefinitionExecution.prototype._stop = function stop() { - /** @private */ this[K_STOPPED] = true; this.broker.cancel('_eventdefinition-execution-execute-tag'); this.broker.cancel('_eventdefinition-execution-api-tag'); diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 4c743873..149655a2 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -60,7 +60,6 @@ LinkEventDefinition.prototype.execute = function execute(executeMessage) { }; LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; diff --git a/src/eventDefinitions/MessageEventDefinition.js b/src/eventDefinitions/MessageEventDefinition.js index 3cdc6439..dd6770c0 100644 --- a/src/eventDefinitions/MessageEventDefinition.js +++ b/src/eventDefinitions/MessageEventDefinition.js @@ -23,11 +23,9 @@ export function MessageEventDefinition(activity, eventDefinition) { const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing) { - /** @private */ this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - /** @private */ this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); } @@ -44,9 +42,7 @@ MessageEventDefinition.prototype.execute = function execute(executeMessage) { }; MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[K_COMPLETED] = false; const executeContent = executeMessage.content; @@ -58,7 +54,6 @@ MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMes const broker = this.broker; const onCatchMessage = this._onCatchMessage.bind(this); - /** @private */ this[K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-message-${executionId}`, @@ -138,7 +133,6 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe return this._complete('got signal with', message.content.message, { correlationId }); } case 'discard': { - /** @private */ this[K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content), { correlationId }); @@ -150,7 +144,6 @@ MessageEventDefinition.prototype._onApiMessage = function onApiMessage(routingKe }; MessageEventDefinition.prototype._complete = function complete(verb, output, options) { - /** @private */ this[K_COMPLETED] = true; this._stop(); @@ -184,7 +177,6 @@ MessageEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-${executionId}`); broker.cancel(`_api-parent-${executionId}`); broker.cancel(`_api-delegated-${executionId}`); - /** @private */ this[K_MESSAGE_Q].purge(); }; diff --git a/src/eventDefinitions/SignalEventDefinition.js b/src/eventDefinitions/SignalEventDefinition.js index 2be46198..7fc50954 100644 --- a/src/eventDefinitions/SignalEventDefinition.js +++ b/src/eventDefinitions/SignalEventDefinition.js @@ -23,11 +23,9 @@ export function SignalEventDefinition(activity, eventDefinition) { const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); if (!isThrowing && isStart) { - /** @private */ this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; - /** @private */ this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); } @@ -44,9 +42,7 @@ SignalEventDefinition.prototype.execute = function execute(executeMessage) { }; SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; - /** @private */ this[K_COMPLETED] = false; const executeContent = executeMessage.content; @@ -58,7 +54,6 @@ SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMess const onCatchMessage = this._onCatchMessage.bind(this); if (this.activity.isStart) { - /** @private */ this[K_MESSAGE_Q].consume(onCatchMessage, { noAck: true, consumerTag: `_api-signal-${executionId}`, @@ -115,7 +110,6 @@ SignalEventDefinition.prototype.executeThrow = function executeThrow(executeMess SignalEventDefinition.prototype._onCatchMessage = function onCatchMessage(routingKey, message) { const info = this[K_REFERENCE_INFO]; if (getPropertyValue(message, 'content.message.id') !== info.message.id) return; - /** @private */ this[K_COMPLETED] = true; this._stop(); @@ -143,7 +137,6 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey return this._complete(message.content.message, { correlationId }); } case 'discard': { - /** @private */ this[K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content), { correlationId }); @@ -156,7 +149,6 @@ SignalEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey }; SignalEventDefinition.prototype._complete = function complete(output, options) { - /** @private */ this[K_COMPLETED] = true; this._stop(); this._debug(`signaled with ${this[K_REFERENCE_INFO].description}`); diff --git a/src/eventDefinitions/TimerEventDefinition.js b/src/eventDefinitions/TimerEventDefinition.js index b9b4b3ba..44f4b3e2 100644 --- a/src/eventDefinitions/TimerEventDefinition.js +++ b/src/eventDefinitions/TimerEventDefinition.js @@ -22,27 +22,25 @@ export function TimerEventDefinition(activity, eventDefinition) { this.broker = activity.broker; this.logger = environment.Logger(type.toLowerCase()); - /** @private */ this[K_STOPPED] = false; - /** @private */ this[K_TIMER] = null; } -Object.defineProperties(TimerEventDefinition.prototype, { - executionId: { - get() { - return this[K_TIMER_CONTENT]?.executionId; - }, +Object.defineProperty(TimerEventDefinition.prototype, 'executionId', { + get() { + return this[K_TIMER_CONTENT]?.executionId; }, - stopped: { - get() { - return this[K_STOPPED]; - }, +}); + +Object.defineProperty(TimerEventDefinition.prototype, 'stopped', { + get() { + return this[K_STOPPED]; }, - timer: { - get() { - return this[K_TIMER]; - }, +}); + +Object.defineProperty(TimerEventDefinition.prototype, 'timer', { + get() { + return this[K_TIMER]; }, }); @@ -54,7 +52,6 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { } if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); - /** @private */ this[K_STOPPED] = false; const content = executeMessage.content; @@ -96,7 +93,6 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) { const timers = this.environment.timers.register(timerContent); const delay = timerContent.timeout; - /** @private */ this[K_TIMER] = timers.setTimeout(this._completed.bind(this), delay, { id: content.id, type: this.type, @@ -192,7 +188,6 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, }; TimerEventDefinition.prototype._stop = function stop() { - /** @private */ this[K_STOPPED] = true; const timer = this[K_TIMER]; if (timer) this[K_TIMER] = this.environment.timers.clearTimeout(timer); diff --git a/src/events/BoundaryEvent.js b/src/events/BoundaryEvent.js index 5134a812..83737172 100644 --- a/src/events/BoundaryEvent.js +++ b/src/events/BoundaryEvent.js @@ -19,26 +19,22 @@ export function BoundaryEventBehaviour(activity) { this.activity = activity; this.environment = activity.environment; this.broker = activity.broker; - /** @private */ this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions, 'execute.bound.completed'); - /** @private */ this[K_SHOVELS] = new Set(); - /** @private */ this[K_ATTACHED_TAGS] = new Set(); } -Object.defineProperties(BoundaryEventBehaviour.prototype, { - executionId: { - get() { - return this[K_EXECUTE_MESSAGE]?.content.executionId; - }, +Object.defineProperty(BoundaryEventBehaviour.prototype, 'executionId', { + get() { + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, - cancelActivity: { - get() { - const behaviour = this.activity.behaviour || {}; - return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true; - }, +}); + +Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', { + get() { + const behaviour = this.activity.behaviour || {}; + return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true; }, }); @@ -47,7 +43,6 @@ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { const eventDefinitionExecution = this[K_EXECUTION]; if (isRootScope && executeMessage.content.id === this.id) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; const broker = this.broker; @@ -62,7 +57,6 @@ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { consumerTag, priority: 300, }); - /** @private */ this[K_ATTACHED_TAGS].add(consumerTag); broker.subscribeOnce('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), { @@ -113,7 +107,6 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, { conten ); } - /** @private */ this[K_COMPLETE_CONTENT] = content; const { inbound, executionId } = this[K_EXECUTE_MESSAGE].content; @@ -126,7 +119,6 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, { conten if (content.isRecovered && !attachedTo.isRunning) { const attachedExecuteTag = `_on-attached-execute-${executionId}`; - /** @private */ this[K_ATTACHED_TAGS].add(attachedExecuteTag); attachedTo.broker.subscribeOnce( 'execution', @@ -155,7 +147,6 @@ BoundaryEventBehaviour.prototype._onExpectMessage = function onExpectMessage(_, const attachedTo = this.attachedTo; const errorConsumerTag = `_bound-error-listener-${executionId}`; - /** @private */ this[K_ATTACHED_TAGS].add(errorConsumerTag); attachedTo.broker.subscribeTmp( @@ -187,7 +178,6 @@ BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_, const { executionId: detachId, bindExchange, sourceExchange, sourcePattern } = content; const shovelName = `_detached-${brokerSafeId(id)}_${detachId}`; - /** @private */ this[K_SHOVELS].add(shovelName); const broker = this.broker; @@ -249,10 +239,8 @@ BoundaryEventBehaviour.prototype._stop = function stop(detach) { broker = this.broker, executionId = this.executionId; for (const tag of this[K_ATTACHED_TAGS]) attachedTo.broker.cancel(tag); - /** @private */ this[K_ATTACHED_TAGS].clear(); for (const shovelName of this[K_SHOVELS]) attachedTo.broker.closeShovel(shovelName); - /** @private */ this[K_SHOVELS].clear(); broker.cancel('_execution-tag'); diff --git a/src/events/EndEvent.js b/src/events/EndEvent.js index 017e79a2..a91c9f4d 100644 --- a/src/events/EndEvent.js +++ b/src/events/EndEvent.js @@ -11,7 +11,6 @@ export function EndEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - /** @private */ this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } diff --git a/src/events/IntermediateCatchEvent.js b/src/events/IntermediateCatchEvent.js index 81cadefa..6f2237f3 100644 --- a/src/events/IntermediateCatchEvent.js +++ b/src/events/IntermediateCatchEvent.js @@ -11,7 +11,6 @@ export function IntermediateCatchEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - /** @private */ this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } diff --git a/src/events/IntermediateThrowEvent.js b/src/events/IntermediateThrowEvent.js index 82a6884b..5edb2156 100644 --- a/src/events/IntermediateThrowEvent.js +++ b/src/events/IntermediateThrowEvent.js @@ -11,7 +11,6 @@ export function IntermediateThrowEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; - /** @private */ this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } diff --git a/src/events/StartEvent.js b/src/events/StartEvent.js index ae931651..0ca790a7 100644 --- a/src/events/StartEvent.js +++ b/src/events/StartEvent.js @@ -12,7 +12,6 @@ export function StartEventBehaviour(activity) { this.type = activity.type; this.activity = activity; this.broker = activity.broker; - /** @private */ this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } @@ -35,7 +34,6 @@ StartEventBehaviour.prototype.execute = function execute(executeMessage) { } const executionId = content.executionId; - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; broker.subscribeTmp('api', `activity.#.${executionId}`, (...args) => this._onApiMessage(...args), { noAck: true, diff --git a/src/flows/Association.js b/src/flows/Association.js index bbd850b9..c058350d 100644 --- a/src/flows/Association.js +++ b/src/flows/Association.js @@ -8,7 +8,7 @@ import { K_COUNTERS } from '../constants.js'; * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. * @param {import('moddle-context-serializer').SerializableElement} associationDef - * @param {import('types').ContextInstance} context + * @param {import('#types').ContextInstance} context */ export function Association(associationDef, { environment }) { const { id, type = 'association', name, parent, targetId, sourceId, behaviour = {} } = associationDef; @@ -24,7 +24,6 @@ export function Association(associationDef, { environment }) { this.environment = environment; const logger = (this.logger = environment.Logger(type.toLowerCase())); - /** @private */ this[K_COUNTERS] = { take: 0, discard: 0, @@ -75,7 +74,7 @@ Association.prototype.discard = function discard(content) { /** * Snapshot association state. Returns undefined when broker has no state and * `disableTrackState` is set. - * @returns {import('types').AssociationState | undefined} + * @returns {import('#types').AssociationState | undefined} */ Association.prototype.getState = function getState() { const brokerState = this.broker.getState(true); @@ -91,7 +90,7 @@ Association.prototype.getState = function getState() { /** * Restore association state captured by getState. - * @param {import('types').AssociationState} state + * @param {import('#types').AssociationState} state */ Association.prototype.recover = function recover(state) { Object.assign(this[K_COUNTERS], state.counters); @@ -100,7 +99,8 @@ Association.prototype.recover = function recover(state) { /** * Resolve an association-scoped Api wrapper. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ Association.prototype.getApi = function getApi(message) { return new Api('association', this.broker, message || { content: this._createMessageContent() }); diff --git a/src/flows/MessageFlow.js b/src/flows/MessageFlow.js index 3be91797..dca3a38b 100644 --- a/src/flows/MessageFlow.js +++ b/src/flows/MessageFlow.js @@ -11,7 +11,7 @@ const K_SOURCE_ELEMENT = Symbol.for('sourceElement'); * source's `end` event and publishes `message.outbound` whenever the source completes, * carrying any message payload through to the target. * @param {import('moddle-context-serializer').SerializableElement} flowDef - * @param {import('types').ContextInstance} context + * @param {import('#types').ContextInstance} context */ export function MessageFlow(flowDef, context) { const { id, type = 'messageflow', name, target, source, behaviour, parent } = flowDef; @@ -26,7 +26,6 @@ export function MessageFlow(flowDef, context) { this.environment = context.environment; this.context = context; - /** @private */ this[K_COUNTERS] = { messages: 0, }; @@ -38,7 +37,6 @@ export function MessageFlow(flowDef, context) { this.emit = emit; this.waitFor = waitFor; - /** @private */ this[K_SOURCE_ELEMENT] = context.getActivityById(source.id) || context.getProcessById(source.processId); this.logger = context.environment.Logger(type.toLowerCase()); } @@ -53,7 +51,7 @@ Object.defineProperty(MessageFlow.prototype, 'counters', { /** * Snapshot message-flow state. Returns undefined when broker has no state and * `disableTrackState` is set. - * @returns {import('types').MessageFlowState | undefined} + * @returns {import('#types').MessageFlowState | undefined} */ MessageFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); @@ -69,7 +67,7 @@ MessageFlow.prototype.getState = function getState() { /** * Restore message-flow state captured by getState. - * @param {import('types').MessageFlowState} state + * @param {import('#types').MessageFlowState} state */ MessageFlow.prototype.recover = function recover(state) { Object.assign(this[K_COUNTERS], state.counters); @@ -78,7 +76,8 @@ MessageFlow.prototype.recover = function recover(state) { /** * Resolve a message-scoped Api wrapper. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ MessageFlow.prototype.getApi = function getApi(message) { return new Api('message', this.broker, message || { content: this._createMessageContent() }); diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index 1d8adc4c..fa7251f8 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -9,7 +9,7 @@ import { K_COUNTERS } from '../constants.js'; * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. * @param {import('moddle-context-serializer').SerializableElement} flowDef - * @param {import('types').ContextInstance} context + * @param {import('#types').ContextInstance} context */ export function SequenceFlow(flowDef, { environment }) { const { id, type = 'sequenceflow', name, parent, targetId, sourceId, isDefault, behaviour = {} } = flowDef; @@ -26,7 +26,6 @@ export function SequenceFlow(flowDef, { environment }) { this.environment = environment; const logger = (this.logger = environment.Logger(type.toLowerCase())); - /** @private */ this[K_COUNTERS] = { looped: 0, take: 0, @@ -91,7 +90,7 @@ SequenceFlow.prototype.discard = function discard(content = {}) { /** * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` * is set. - * @returns {import('types').SequenceFlowState | undefined} + * @returns {import('#types').SequenceFlowState | undefined} */ SequenceFlow.prototype.getState = function getState() { const brokerState = this.broker.getState(true); @@ -107,7 +106,7 @@ SequenceFlow.prototype.getState = function getState() { /** * Restore flow state captured by getState. - * @param {import('types').SequenceFlowState} state + * @param {import('#types').SequenceFlowState} state */ SequenceFlow.prototype.recover = function recover(state) { Object.assign(this[K_COUNTERS], state.counters); @@ -116,7 +115,8 @@ SequenceFlow.prototype.recover = function recover(state) { /** * Resolve a Flow Api wrapper. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ SequenceFlow.prototype.getApi = function getApi(message) { return FlowApi(this.broker, message || { content: this.createMessage() }); @@ -132,7 +132,7 @@ SequenceFlow.prototype.stop = function stop() { /** * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop * when the target was already visited, otherwise flow.shake. - * @param {import('types').ElementBrokerMessage} message + * @param {import('#types').ElementBrokerMessage} message */ SequenceFlow.prototype.shake = function shake(message) { const content = cloneContent(message.content); @@ -161,7 +161,7 @@ SequenceFlow.prototype.shake = function shake(message) { /** * Resolve the flow's condition (script or expression). Returns null when no condition is set. * Emits a fatal error when the script language is missing or unsupported. - * @returns {import('types').ISequenceFlowCondition | null} + * @returns {import('#types').ISequenceFlowCondition | null} */ SequenceFlow.prototype.getCondition = function getCondition() { const conditionExpression = this.behaviour.conditionExpression; @@ -203,7 +203,7 @@ SequenceFlow.prototype.createMessage = function createMessage(override) { /** * Evaluate the flow's condition for the source activity message. Default flows are always taken. - * @param {import('types').ElementBrokerMessage} fromMessage Source activity message + * @param {import('#types').ElementBrokerMessage} fromMessage Source activity message * @param {(err: Error | null, result?: boolean | object) => void} callback Callback with truthy result if flow should be taken */ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { diff --git a/src/gateways/EventBasedGateway.js b/src/gateways/EventBasedGateway.js index 7b4b67df..c7caac96 100644 --- a/src/gateways/EventBasedGateway.js +++ b/src/gateways/EventBasedGateway.js @@ -12,7 +12,6 @@ export function EventBasedGatewayBehaviour(activity, context) { this.activity = activity; this.broker = activity.broker; this.context = context; - /** @private */ this[K_TARGETS] = new Set(activity.outbound.map((flow) => context.getActivityById(flow.targetId))); } @@ -21,7 +20,6 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) const { executionId, outbound = [], outboundTaken } = executeContent; const targets = this[K_TARGETS]; - /** @private */ this[K_COMPLETED] = false; if (!targets.size) return this._complete(executeContent); @@ -43,7 +41,6 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) consumerTag: '_api-stop-execution', }); - /** @private */ this[K_COMPLETED] = false; if (!executeMessage.fields.redelivered) { @@ -75,7 +72,6 @@ EventBasedGatewayBehaviour.prototype._onTargetCompleted = function onTargetCompl }; EventBasedGatewayBehaviour.prototype._complete = function complete(completedContent) { - /** @private */ this[K_COMPLETED] = true; this.broker.publish('execution', 'execute.completed', cloneContent(completedContent)); }; diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index cd9653b9..eb4dfa55 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -52,15 +52,12 @@ export function ParallelGatewayBehaviour(activity) { this.inbound = new Set(); this.isConverging = new Set(activity.inbound.map(({ sourceId }) => sourceId)).size > 1; - /** @private */ this[K_EXECUTE_MESSAGE] = undefined; } -Object.defineProperties(ParallelGatewayBehaviour.prototype, { - executionId: { - get() { - return this[K_EXECUTE_MESSAGE]?.content.executionId; - }, +Object.defineProperty(ParallelGatewayBehaviour.prototype, 'executionId', { + get() { + return this[K_EXECUTE_MESSAGE]?.content.executionId; }, }); @@ -70,7 +67,6 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; if (executeContent.isRootScope) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; switch (routingKey) { @@ -89,7 +85,6 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { const peerIds = new Set([...this.activity[K_PEERS].values()].map((v) => [...v]).flat()); - /** @private */ this[K_TARGETS] = new Map([...peerIds].map((pid) => [pid, this.activity.getActivityById(pid)])); this.peerMonitor = new PeerMonitor(this.activity, this.activity[K_INBOUND_SOURCE_IDS], this[K_TARGETS]); diff --git a/src/io/EnvironmentDataObject.js b/src/io/EnvironmentDataObject.js index f1a189c6..f8538f8c 100644 --- a/src/io/EnvironmentDataObject.js +++ b/src/io/EnvironmentDataObject.js @@ -23,6 +23,10 @@ EnvironmentDataObject.prototype.write = function write(broker, exchange, routing return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; +/** + * @private + * Create content + */ EnvironmentDataObject.prototype._createContent = function createContent(value) { return { id: this.id, diff --git a/src/io/InputOutputSpecification.js b/src/io/InputOutputSpecification.js index 68a19103..e1fb5f5f 100644 --- a/src/io/InputOutputSpecification.js +++ b/src/io/InputOutputSpecification.js @@ -20,7 +20,6 @@ IoSpecification.prototype.activate = function activate(message) { if (message?.fields.redelivered && message.fields.routingKey === 'run.end') { this._onFormatComplete(message); } - /** @private */ this[K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); }; diff --git a/src/io/Properties.js b/src/io/Properties.js index 33bd5b5b..fa50517d 100644 --- a/src/io/Properties.js +++ b/src/io/Properties.js @@ -67,7 +67,6 @@ Properties.prototype.activate = function activate(message) { this._onActivityEvent('activity.extension.resume', message); } - /** @private */ this[K_CONSUMING] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), { noAck: true }); }; diff --git a/src/process/Lane.js b/src/process/Lane.js index 2847107f..448aca1a 100644 --- a/src/process/Lane.js +++ b/src/process/Lane.js @@ -3,14 +3,13 @@ const K_PROCESS = Symbol.for('process'); /** * Process lane. Wraps a `` definition and points back to its owning process; * activities reference their lane through `Activity.lane`. - * @param {import('types').Process} process + * @param {import('#types').Process} process * @param {import('moddle-context-serializer').SerializableElement} laneDefinition */ export function Lane(process, laneDefinition) { const { broker, environment } = process; const { id, type, behaviour } = laneDefinition; - /** @private */ this[K_PROCESS] = process; this.id = id; @@ -28,7 +27,7 @@ export function Lane(process, laneDefinition) { } Object.defineProperty(Lane.prototype, 'process', { - /** @returns {import('types').Process} */ + /** @returns {import('#types').Process} */ get() { return this[K_PROCESS]; }, diff --git a/src/process/Process.js b/src/process/Process.js index 3c7a50f2..2d272234 100644 --- a/src/process/Process.js +++ b/src/process/Process.js @@ -21,8 +21,8 @@ const K_LANES = Symbol.for('lanes'); /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. - * @param {import('moddle-context-serializer').SerializableElement} processDef - * @param {import('types').ContextInstance} context + * @param {import('moddle-context-serializer').MappedProcess} processDef + * @param {import('#types').ContextInstance} context */ export function Process(processDef, context) { const { id, type = 'process', name, parent, behaviour = {} } = processDef; @@ -32,23 +32,17 @@ export function Process(processDef, context) { this.parent = parent ? cloneParent(parent) : {}; this.behaviour = behaviour; - const { isExecutable } = behaviour; - this.isExecutable = isExecutable; + this.isExecutable = behaviour.isExecutable; const environment = (this.environment = context.environment); this.context = context; - /** @private */ this[K_COUNTERS] = { completed: 0, discarded: 0, }; - /** @private */ this[K_CONSUMING] = false; - /** @private */ this[K_EXECUTION] = new Map(); - /** @private */ this[K_STATUS] = undefined; - /** @private */ this[K_STOPPED] = false; const { broker, on, once, waitFor } = ProcessBroker(this); @@ -57,7 +51,6 @@ export function Process(processDef, context) { this.once = once; this.waitFor = waitFor; - /** @private */ this[K_MESSAGE_HANDLERS] = { onApiMessage: this._onApiMessage.bind(this), onRunMessage: this._onRunMessage.bind(this), @@ -67,10 +60,8 @@ export function Process(processDef, context) { this.logger = environment.Logger(type.toLowerCase()); if (behaviour.lanes) { - /** @private */ this[K_LANES] = behaviour.lanes.map((lane) => new lane.Behaviour(this, lane)); } - /** @private */ this[K_EXTENSIONS] = context.loadExtensions(this); } @@ -130,7 +121,6 @@ Object.defineProperties(Process.prototype, { */ Process.prototype.init = function init(useAsExecutionId) { const initExecutionId = useAsExecutionId || getUniqueId(this.id); - /** @private */ this[K_EXECUTION].set('initExecutionId', initExecutionId); this._debug(`initialized with executionId <${initExecutionId}>`); @@ -169,7 +159,6 @@ Process.prototype.resume = function resume() { if (this.isRunning) throw new Error(`cannot resume running process <${this.id}>`); if (!this.status) return this; - /** @private */ this[K_STOPPED] = false; const content = this._createMessage(); @@ -197,7 +186,7 @@ Process.prototype.getState = function getState() { /** * Restore process state captured by getState. - * @param {import('types').ProcessState} [state] + * @param {import('#types').ProcessState} [state] * @returns {this} * @throws {Error} when called on a running process */ @@ -205,13 +194,10 @@ Process.prototype.recover = function recover(state) { if (this.isRunning) throw new Error(`cannot recover running process <${this.id}>`); if (!state) return this; - /** @private */ this[K_STOPPED] = !!state.stopped; - /** @private */ this[K_STATUS] = state.status; const exec = this[K_EXECUTION]; exec.set('executionId', state.executionId); - /** @private */ this[K_COUNTERS] = { ...this[K_COUNTERS], ...state.counters }; this.environment.recover(state.environment); @@ -243,7 +229,8 @@ Process.prototype.stop = function stop() { /** * Resolve a Process Api wrapper, preferring the running execution if any. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ Process.prototype.getApi = function getApi(message) { const execution = this.execution; @@ -253,7 +240,7 @@ Process.prototype.getApi = function getApi(message) { /** * Send a delegated signal to the running process. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Process.prototype.signal = function signal(message) { return this.getApi().signal(message, { delegate: true }); @@ -261,7 +248,7 @@ Process.prototype.signal = function signal(message) { /** * Cancel a running activity inside the process by delegated api message. - * @param {import('types').signalMessage} [message] + * @param {import('#types').signalMessage} [message] */ Process.prototype.cancelActivity = function cancelActivity(message) { return this.getApi().cancel(message, { delegate: true }); @@ -269,7 +256,6 @@ Process.prototype.cancelActivity = function cancelActivity(message) { /** @internal */ Process.prototype._activateRunConsumers = function activateRunConsumers() { - /** @private */ this[K_CONSUMING] = true; const broker = this.broker; const { onApiMessage, onRunMessage } = this[K_MESSAGE_HANDLERS]; @@ -283,7 +269,6 @@ Process.prototype._deactivateRunConsumers = function deactivateRunConsumers() { broker.cancel('_process-api'); broker.cancel('_process-run'); broker.cancel('_process-execution'); - /** @private */ this[K_CONSUMING] = false; }; @@ -295,18 +280,15 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { return this._onResumeMessage(message); } - /** @private */ this[K_STATE_MESSAGE] = message; switch (routingKey) { case 'run.enter': { this._debug('enter'); - /** @private */ this[K_STATUS] = 'entered'; if (fields.redelivered) break; - /** @private */ this[K_EXECUTION].delete('execution'); this._publishEvent('enter', content); @@ -314,21 +296,18 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { } case 'run.start': { this._debug('start'); - /** @private */ this[K_STATUS] = 'start'; this._publishEvent('start', content); break; } case 'run.execute': { const exec = this[K_EXECUTION]; - /** @private */ this[K_STATUS] = 'executing'; const executeMessage = cloneMessage(message); let execution = exec.get('execution'); if (fields.redelivered && !execution) { executeMessage.fields.redelivered = undefined; } - /** @private */ this[K_EXECUTE_MESSAGE] = message; this.broker.getQueue('execution-q').assertConsumer(this[K_MESSAGE_HANDLERS].onExecutionMessage, { @@ -341,7 +320,6 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { return execution.execute(executeMessage); } case 'run.error': { - /** @private */ this[K_STATUS] = 'errored'; this._publishEvent( 'error', @@ -352,13 +330,11 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { break; } case 'run.end': { - /** @private */ this[K_STATUS] = 'end'; if (fields.redelivered) break; this._debug('completed'); - /** @private */ this[K_COUNTERS].completed++; this.broker.publish('run', 'run.leave', content); @@ -367,11 +343,9 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { break; } case 'run.discarded': { - /** @private */ this[K_STATUS] = 'discarded'; if (fields.redelivered) break; - /** @private */ this[K_COUNTERS].discarded++; this.broker.publish('run', 'run.leave', content); @@ -380,7 +354,6 @@ Process.prototype._onRunMessage = function onRunMessage(routingKey, message) { break; } case 'run.leave': { - /** @private */ this[K_STATUS] = undefined; message.ack(); this._deactivateRunConsumers(); @@ -440,7 +413,6 @@ Process.prototype._onExecutionMessage = function onExecutionMessage(routingKey, } const executeMessage = this[K_EXECUTE_MESSAGE]; - /** @private */ this[K_EXECUTE_MESSAGE] = null; executeMessage.ack(); }; @@ -454,7 +426,7 @@ Process.prototype._publishEvent = function publishEvent(state, content) { /** * Deliver a message to a target activity or start activity that references it. * Starts the process if a target is found and the process is idle. - * @param {import('types').ElementBrokerMessage} message + * @param {import('#types').ElementBrokerMessage} message */ Process.prototype.sendMessage = function sendMessage(message) { const messageContent = message?.content; @@ -495,7 +467,7 @@ Process.prototype.getActivities = function getActivities() { /** * Get start activities, optionally filtered by referenced event definition. - * @param {import('types').startActivityFilterOptions} [filterOptions] + * @param {import('#types').startActivityFilterOptions} [filterOptions] */ Process.prototype.getStartActivities = function getStartActivities(filterOptions) { return this.context.getStartActivities(filterOptions, this.id); @@ -521,7 +493,7 @@ Process.prototype.getLaneById = function getLaneById(laneId) { /** * List currently postponed activities as Api wrappers. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ Process.prototype.getPostponed = function getPostponed(...args) { const execution = this.execution; @@ -544,7 +516,6 @@ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { /** @internal */ Process.prototype._onStop = function onStop() { - /** @private */ this[K_STOPPED] = true; this._deactivateRunConsumers(); return this._publishEvent('stop'); diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 7d379d36..8ca93be2 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -12,13 +12,12 @@ const K_TRACKER = Symbol.for('activity tracker'); /** * Drives the execution of a single process or sub-process: activates children, routes activity * events, and rolls completion up to the owning Process or sub-process Activity. - * @param {import('types').Process | import('types').Activity} parentActivity - * @param {import('types').ContextInstance} context + * @param {import('#types').Process | import('#types').Activity} parentActivity + * @param {import('#types').ContextInstance} context */ export function ProcessExecution(parentActivity, context) { const { id, type, broker, isSubProcess, isTransaction } = parentActivity; - /** @private */ this[K_PARENT] = parentActivity; this.id = id; this.type = type; @@ -28,7 +27,6 @@ export function ProcessExecution(parentActivity, context) { this.environment = context.environment; this.context = context; - /** @private */ this[K_ELEMENTS] = { postponed: new Set(), children: context.getActivities(id), @@ -45,19 +43,13 @@ export function ProcessExecution(parentActivity, context) { const exchangeName = (this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution'); broker.assertExchange(exchangeName, 'topic', { autoDelete: false, durable: true }); - /** @private */ this[K_COMPLETED] = false; - /** @private */ this[K_STOPPED] = false; - /** @private */ this[K_ACTIVATED] = false; - /** @private */ this[K_STATUS] = 'init'; - /** @private */ this[K_TRACKER] = new ActivityTracker(id); this.executionId = undefined; - /** @private */ this[K_MESSAGE_HANDLERS] = { onActivityEvent: this._onActivityEvent.bind(this), onApiMessage: this._onApiMessage.bind(this), @@ -101,7 +93,7 @@ Object.defineProperties(ProcessExecution.prototype, { /** * Activate children and start the process execution. Resumes if the message is redelivered. - * @param {import('types').ElementBrokerMessage} executeMessage + * @param {import('#types').ElementBrokerMessage} executeMessage * @throws {Error} when message or executionId is missing */ ProcessExecution.prototype.execute = function execute(executeMessage) { @@ -110,17 +102,14 @@ ProcessExecution.prototype.execute = function execute(executeMessage) { const executionId = (this.executionId = executeMessage.content.executionId); - /** @private */ this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage, { executionId, state: 'start', }); - /** @private */ this[K_STOPPED] = false; this.environment.assignVariables(executeMessage); - /** @private */ this[K_ACTIVITY_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false }); if (executeMessage.fields.redelivered) { @@ -156,7 +145,6 @@ ProcessExecution.prototype.resume = function resume() { postponed.clear(); detachedActivities.clear(); - /** @private */ this[K_ACTIVITY_Q].consume(this[K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}`, @@ -189,6 +177,7 @@ ProcessExecution.prototype.resume = function resume() { /** * Snapshot execution state including children, flows, message flows, and associations. + * @returns {import('#types').ProcessExecutionState} */ ProcessExecution.prototype.getState = function getState() { const { children, flows, outboundMessageFlows, associations } = this[K_ELEMENTS]; @@ -220,18 +209,15 @@ ProcessExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. - * @param {import('types').ProcessExecutionState} [state] + * @param {import('#types').ProcessExecutionState} [state] * @returns {this} */ ProcessExecution.prototype.recover = function recover(state) { if (!state) return this; this.executionId = state.executionId; - /** @private */ this[K_STOPPED] = state.stopped; - /** @private */ this[K_COMPLETED] = state.completed; - /** @private */ this[K_STATUS] = state.status; this._debug(`recover process execution at ${this.status}`); @@ -289,7 +275,7 @@ ProcessExecution.prototype.stop = function stop() { /** * List currently postponed children as Api wrappers. - * @param {import('types').filterPostponed} [filterFn] + * @param {import('#types').filterPostponed} [filterFn] */ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { const result = []; @@ -306,7 +292,6 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { * Queue a discard message that propagates to all running children. */ ProcessExecution.prototype.discard = function discard() { - /** @private */ this[K_STATUS] = 'discard'; return this[K_ACTIVITY_Q].queueMessage( { routingKey: 'execution.discard' }, @@ -364,7 +349,8 @@ ProcessExecution.prototype.getAssociations = function getAssociations() { /** * Resolve a process or child Api for the given message. - * @param {import('types').ElementBrokerMessage} [message] + * @param {import('#types').ElementBrokerMessage} [message] + * @returns {import('#types').IApi} */ ProcessExecution.prototype.getApi = function getApi(message) { if (!message) return ProcessApi(this.broker, this[K_EXECUTE_MESSAGE]); @@ -397,7 +383,6 @@ ProcessExecution.prototype._start = function start() { return this._complete('completed'); } - /** @private */ this[K_STATUS] = 'start'; const executeContent = { ...this[K_EXECUTE_MESSAGE].content, state: this.status }; @@ -414,7 +399,6 @@ ProcessExecution.prototype._start = function start() { } for (const a of startActivities) a.init(); - /** @private */ this[K_STATUS] = 'executing'; for (const a of startActivities) a.run(); @@ -426,7 +410,6 @@ ProcessExecution.prototype._start = function start() { postponed.clear(); detachedActivities.clear(); - /** @private */ this[K_ACTIVITY_Q].assertConsumer(this[K_MESSAGE_HANDLERS].onChildMessage, { prefetch: 1000, consumerTag: `_process-activity-${this.executionId}`, @@ -452,7 +435,6 @@ ProcessExecution.prototype._activate = function activate() { } const { outboundMessageFlows, flows, associations, startActivities, startSequences, triggeredByEvent, convergingGateways, children } = - /** @private */ this[K_ELEMENTS]; for (const flow of outboundMessageFlows) { @@ -504,7 +486,6 @@ ProcessExecution.prototype._activate = function activate() { } } - /** @private */ this[K_ACTIVATED] = true; }; @@ -536,7 +517,6 @@ ProcessExecution.prototype._deactivate = function deactivate() { flow.broker.cancel('_process-message-consumer'); } - /** @private */ this[K_ACTIVATED] = false; }; @@ -669,7 +649,6 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe if (delegate) delegate = this._onDelegateEvent(message); - /** @private */ this[K_TRACKER].track(routingKey, message); this.broker.publish('event', routingKey, content, { ...properties, delegate, mandatory: false }); if (shaking) return this._onShakeMessage(message); @@ -685,7 +664,6 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe return; } - /** @private */ this[K_ACTIVITY_Q].queueMessage(message.fields, cloneContent(content), { persistent: true, ...message.properties }); }; @@ -735,7 +713,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, switch (routingKey) { case 'activity.detach': { - /** @private */ this[K_ELEMENTS].detachedActivities.add(cloneMessage(message)); break; } @@ -764,7 +741,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, } } if (eventCaughtBy) { - /** @private */ this[K_ACTIVITY_Q].queueMessage({ routingKey: 'activity.error.caught' }, cloneContent(content), { persistent: true, ...message.properties, @@ -876,7 +852,6 @@ ProcessExecution.prototype._stopExecution = function stopExecution(message) { for (const api of this.getPostponed()) api.stop(); } this._deactivate(); - /** @private */ this[K_STOPPED] = true; return this.broker.publish( this._exchangeName, @@ -906,7 +881,6 @@ ProcessExecution.prototype._onDiscard = function onDiscard() { for (const msg of running) this._getChildApi(msg).discard(); } - /** @private */ this[K_ACTIVITY_Q].purge(); return this._complete('discard'); }; @@ -920,7 +894,6 @@ ProcessExecution.prototype._onCancel = function onCancel() { if (isTransaction) { this._debug(`cancel transaction execution (cancel child executions ${running.size})`); - /** @private */ this[K_STATUS] = 'cancel'; this.broker.publish( 'event', @@ -965,7 +938,6 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes case 'discard': return this.discard(message); case 'stop': - /** @private */ this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false }); break; } @@ -1003,7 +975,6 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou /** @internal */ ProcessExecution.prototype._complete = function complete(completionType, content) { this._deactivate(); - /** @private */ this[K_COMPLETED] = true; const status = this.status; @@ -1017,15 +988,13 @@ ProcessExecution.prototype._complete = function complete(completionType, content break; default: this._debug(`process execution ${completionType}`); - /** @private */ this[K_STATUS] = completionType; } const broker = this.broker; - /** @private */ this[K_ACTIVITY_Q].delete(); - return broker.publish( + broker.publish( this._exchangeName, `execution.${completionType}.${this.executionId}`, cloneContent(this[K_EXECUTE_MESSAGE].content, { @@ -1039,7 +1008,6 @@ ProcessExecution.prototype._complete = function complete(completionType, content /** @internal */ ProcessExecution.prototype._terminate = function terminate(message) { - /** @private */ this[K_STATUS] = 'terminated'; this._debug('terminating process execution'); @@ -1058,7 +1026,6 @@ ProcessExecution.prototype._terminate = function terminate(message) { msg.ack(); } - /** @private */ this[K_ACTIVITY_Q].purge(); }; @@ -1116,6 +1083,5 @@ ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { /** @internal */ ProcessExecution.prototype._debug = function debugMessage(logMessage) { - /** @private */ this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); }; diff --git a/src/tasks/CallActivity.js b/src/tasks/CallActivity.js index 62d48bae..581751af 100644 --- a/src/tasks/CallActivity.js +++ b/src/tasks/CallActivity.js @@ -2,6 +2,12 @@ import { Activity } from '../activity/Activity.js'; import { ActivityError } from '../error/Errors.js'; import { cloneContent } from '../messageHelper.js'; +/** + * Create call activity + * @param {import('moddle-context-serializer').MappedActivity} activityDef + * @param {import('../Context.js').ContextInstance} context + * @returns Call activity + */ export function CallActivity(activityDef, context) { return new Activity(CallActivityBehaviour, activityDef, context); } diff --git a/src/tasks/ReceiveTask.js b/src/tasks/ReceiveTask.js index b30cb54a..47008acf 100644 --- a/src/tasks/ReceiveTask.js +++ b/src/tasks/ReceiveTask.js @@ -28,7 +28,6 @@ export function ReceiveTaskBehaviour(activity) { this.activity = activity; this.broker = activity.broker; - /** @private */ this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); } @@ -46,12 +45,10 @@ function ReceiveTaskExecution(parent) { this.loopCharacteristics = loopCharacteristics; this.referenceElement = parent[K_REFERENCE_ELEMENT]; - /** @private */ this[K_COMPLETED] = false; } ReceiveTaskExecution.prototype.execute = function execute(executeMessage) { - /** @private */ this[K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; @@ -127,7 +124,6 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, return this._complete(message.content.message, { correlationId }); } case 'discard': { - /** @private */ this[K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.discard', cloneContent(this[K_EXECUTE_MESSAGE].content), { correlationId }); @@ -139,7 +135,6 @@ ReceiveTaskExecution.prototype._onApiMessage = function onApiMessage(routingKey, }; ReceiveTaskExecution.prototype._complete = function complete(output, options) { - /** @private */ this[K_COMPLETED] = true; this._stop(); return this.broker.publish('execution', 'execute.completed', cloneContent(this[K_EXECUTE_MESSAGE].content, { output }), options); diff --git a/src/tasks/SubProcess.js b/src/tasks/SubProcess.js index 9057b1c4..26dfd780 100644 --- a/src/tasks/SubProcess.js +++ b/src/tasks/SubProcess.js @@ -38,22 +38,19 @@ export function SubProcessBehaviour(activity, context) { this.broker = activity.broker; this.executionId = undefined; - /** @private */ this[K_EXECUTIONS] = new Set(); - /** @private */ this[K_ON_EXECUTION_COMPLETED] = this._onExecutionCompleted.bind(this); } -Object.defineProperties(SubProcessBehaviour.prototype, { - execution: { - get() { - return [...this[K_EXECUTIONS]][0]; - }, +Object.defineProperty(SubProcessBehaviour.prototype, 'execution', { + get() { + return [...this[K_EXECUTIONS]][0]; }, - executions: { - get() { - return [...this[K_EXECUTIONS]]; - }, +}); + +Object.defineProperty(SubProcessBehaviour.prototype, 'executions', { + get() { + return [...this[K_EXECUTIONS]]; }, }); @@ -139,7 +136,6 @@ SubProcessBehaviour.prototype._upsertExecution = function upsertExecution(execut const subContext = this.context.clone(subEnvironment, this.activity); execution = new ProcessExecution(this.activity, subContext); - /** @private */ this[K_EXECUTIONS].add(execution); this._addListeners(executionId); @@ -185,7 +181,6 @@ SubProcessBehaviour.prototype._onExecutionCompleted = function onExecutionComple SubProcessBehaviour.prototype._completeExecution = function completeExecution(completeRoutingKey, content) { if (this.loopCharacteristics) { const execution = this._getExecutionById(content.executionId); - /** @private */ this[K_EXECUTIONS].delete(execution); } diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index 38a4a6ec..1513547c 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -1,4 +1,4 @@ -import { Activity } from '../../src/activity/Activity.js'; +import { Activity } from 'bpmn-elements'; import { Association } from '../../src/flows/Association.js'; import { Environment } from '../../src/Environment.js'; import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; diff --git a/test/feature/BoundaryEvent-feature.js b/test/feature/BoundaryEvent-feature.js index e2ebffb8..b9e55c92 100644 --- a/test/feature/BoundaryEvent-feature.js +++ b/test/feature/BoundaryEvent-feature.js @@ -3,6 +3,7 @@ import { Definition } from 'bpmn-elements'; Feature('BoundaryEvent', () => { Scenario('task with boundary event followed by a join', () => { + /** @type {import('bpmn-elements').Process} */ let bp; Given('a process', async () => { const source = ` @@ -123,6 +124,7 @@ Feature('BoundaryEvent', () => { }); Scenario('user task with non-interrupting boundary event followed by a join', () => { + /** @type {import('bpmn-elements').Process} */ let bp; Given('a process', async () => { const source = ` diff --git a/test/feature/Definition-feature.js b/test/feature/Definition-feature.js index 08536270..ce84fbce 100644 --- a/test/feature/Definition-feature.js +++ b/test/feature/Definition-feature.js @@ -20,7 +20,9 @@ Feature('Definition', () => { `; - let definition, assertMessage; + /** @type {Definition} */ + let definition; + let assertMessage; const messages = []; Given('a definition', async () => { const context = await testHelpers.context(source); diff --git a/test/feature/activity-io-feature.js b/test/feature/activity-io-feature.js index 9ae26036..5194e340 100644 --- a/test/feature/activity-io-feature.js +++ b/test/feature/activity-io-feature.js @@ -45,7 +45,7 @@ Feature('Activity IO', () => { }); Scenario('Activity with properties that references output DataObject by association', () => { - /** @type {import('../../src/definition/Definition.js').Definition} */ + /** @type {Definition} */ let definition; let taskMessage; Given('a process with an activity with property', async () => { diff --git a/test/feature/call-activity-feature.js b/test/feature/call-activity-feature.js index 5acc2fbf..5f11070d 100644 --- a/test/feature/call-activity-feature.js +++ b/test/feature/call-activity-feature.js @@ -1,8 +1,9 @@ import * as ck from 'chronokinesis'; +import { Definition } from 'bpmn-elements'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; -import { Definition } from 'bpmn-elements'; + Feature('Call activity', () => { after(ck.reset); diff --git a/test/feature/io-feature.js b/test/feature/io-feature.js index 345cf737..6c26f86d 100644 --- a/test/feature/io-feature.js +++ b/test/feature/io-feature.js @@ -1,10 +1,11 @@ -import camunda from '../resources/extensions/CamundaExtension.js'; import { Definition } from 'bpmn-elements'; +import camunda from '../resources/extensions/CamundaExtension.js'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; Feature('IO', () => { Scenario('DataStoreReference and DataInput- and DataOutputAssociation', () => { + /** @type {Definition} */ let definition; Given('two tasks associated with a data store reference only', async () => { const context = await testHelpers.context(factory.resource('signals.bpmn'), { diff --git a/tsconfig.json b/tsconfig.json index 98925029..7ac8fb21 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,5 @@ { "include": ["src/**/*", "types"], - "exclude": ["types/augmentations.d.ts"], "compilerOptions": { "emitDeclarationOnly": true, "sourceMap": false, @@ -24,8 +23,7 @@ "noUnusedParameters": true, "types": ["node"], "paths": { - "types": ["./types/types.js"], - "src/*": ["./src/*"] + "#types": ["./types/interfaces.d.ts"] } } } diff --git a/types/augmentations.d.ts b/types/augmentations.d.ts deleted file mode 100644 index 9fc1b57f..00000000 --- a/types/augmentations.d.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Augmentations for the dts-buddy-generated bundle in types/index.d.ts. -// These interfaces add the prototype getters defined via Object.defineProperties -// in src/, which TypeScript cannot pick up from constructor functions. -// The build script (scripts/build-types.js) appends this file to types/index.d.ts. - -declare module 'bpmn-elements' { - interface Activity { - get counters(): { taken: number; discarded: number }; - get execution(): import('types').ActivityExecution | undefined; - get executionId(): string | undefined; - get extensions(): import('types').IExtension; - get bpmnIo(): import('types').IExtension | undefined; - get formatter(): any; - get isRunning(): boolean; - get outbound(): import('types').SequenceFlow[]; - get inbound(): import('types').SequenceFlow[]; - get isEnd(): boolean; - get isStart(): boolean; - get isSubProcess(): boolean; - get isTransaction(): boolean; - get isMultiInstance(): boolean; - get isThrowing(): boolean; - get isCatching(): boolean; - get isForCompensation(): boolean; - get isParallelJoin(): boolean; - get triggeredByEvent(): boolean; - get attachedTo(): import('types').Activity | null; - get lane(): import('types').Lane | undefined; - get eventDefinitions(): any[]; - /** Parent element process or sub process reference */ - get parentElement(): import('types').Process | import('types').Activity; - get initialized(): boolean; - } - - interface Process { - get counters(): { completed: number; discarded: number }; - get lanes(): import('types').Lane[] | undefined; - get extensions(): import('types').IExtension | undefined; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string | undefined; - get execution(): import('types').ProcessExecution | undefined; - get status(): string | undefined; - get activityStatus(): string; - } - - interface Definition { - get counters(): { completed: number; discarded: number }; - get execution(): import('types').DefinitionExecution | undefined; - get executionId(): string | undefined; - get isRunning(): boolean; - get status(): string | undefined; - get stopped(): boolean; - get activityStatus(): string; - } - - interface Environment { - get variables(): Record; - get services(): Record; - set services(value: Record); - } - - interface ContextInstance { - /** Process or sub-process activity that owns this context */ - get owner(): import('types').Process | import('types').Activity | undefined; - } - - interface ProcessExecution { - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - - interface DefinitionExecution { - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get processes(): import('types').Process[]; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - - interface ActivityExecution { - get completed(): boolean; - } -} diff --git a/types/bundle-errors.d.ts b/types/bundle-errors.d.ts new file mode 100644 index 00000000..c2183572 --- /dev/null +++ b/types/bundle-errors.d.ts @@ -0,0 +1 @@ +export * from '../src/error/Errors.js'; diff --git a/types/bundle-eventDefinitions.d.ts b/types/bundle-eventDefinitions.d.ts new file mode 100644 index 00000000..3e507ef0 --- /dev/null +++ b/types/bundle-eventDefinitions.d.ts @@ -0,0 +1 @@ +export * from '../src/eventDefinitions/index.js'; diff --git a/types/bundle-events.d.ts b/types/bundle-events.d.ts new file mode 100644 index 00000000..dd29ff84 --- /dev/null +++ b/types/bundle-events.d.ts @@ -0,0 +1 @@ +export * from '../src/events/index.js'; diff --git a/types/bundle-flows.d.ts b/types/bundle-flows.d.ts new file mode 100644 index 00000000..4bc80561 --- /dev/null +++ b/types/bundle-flows.d.ts @@ -0,0 +1 @@ +export * from '../src/flows/index.js'; diff --git a/types/bundle-gateways.d.ts b/types/bundle-gateways.d.ts new file mode 100644 index 00000000..4d3592f3 --- /dev/null +++ b/types/bundle-gateways.d.ts @@ -0,0 +1 @@ +export * from '../src/gateways/index.js'; diff --git a/types/bundle-tasks.d.ts b/types/bundle-tasks.d.ts new file mode 100644 index 00000000..6e9124c8 --- /dev/null +++ b/types/bundle-tasks.d.ts @@ -0,0 +1 @@ +export * from '../src/tasks/index.js'; diff --git a/types/bundle.d.ts b/types/bundle.d.ts new file mode 100644 index 00000000..f3f45eba --- /dev/null +++ b/types/bundle.d.ts @@ -0,0 +1,63 @@ +// Hand-written entry for dts-buddy. Re-exports the runtime classes once each +// and the shared interfaces in one place so the emitted bundle has a single +// declaration per name (no `_1` aliases, no per-module duplicates). +export * from './interfaces.js'; + +export { Activity } from '../src/activity/Activity.js'; +export { ActivityExecution } from '../src/activity/ActivityExecution.js'; +export { BpmnErrorActivity as BpmnError } from '../src/error/BpmnError.js'; +export { Context } from '../src/Context.js'; +export { Definition } from '../src/definition/Definition.js'; +export { DefinitionExecution } from '../src/definition/DefinitionExecution.js'; +export { DummyActivity as Dummy } from '../src/activity/Dummy.js'; +export { DummyActivity as TextAnnotation } from '../src/activity/Dummy.js'; +export { DummyActivity as Group } from '../src/activity/Dummy.js'; +export { DummyActivity as Category } from '../src/activity/Dummy.js'; +export { Environment } from '../src/Environment.js'; +export { EnvironmentDataObject as DataObject } from '../src/io/EnvironmentDataObject.js'; +export { EnvironmentDataStore as DataStore } from '../src/io/EnvironmentDataStore.js'; +export { EnvironmentDataStoreReference as DataStoreReference } from '../src/io/EnvironmentDataStoreReference.js'; +export { Escalation } from '../src/activity/Escalation.js'; +export { IoSpecification as InputOutputSpecification } from '../src/io/InputOutputSpecification.js'; +export { Lane } from '../src/process/Lane.js'; +export { LoopCharacteristics as MultiInstanceLoopCharacteristics } from '../src/tasks/LoopCharacteristics.js'; +export { Message } from '../src/activity/Message.js'; +export { Process } from '../src/process/Process.js'; +export { Properties } from '../src/io/Properties.js'; +export { ServiceImplementation } from '../src/tasks/ServiceImplementation.js'; +export { Signal } from '../src/activity/Signal.js'; +export { StandardLoopCharacteristics } from '../src/tasks/StandardLoopCharacteristics.js'; +export { Timers } from '../src/Timers.js'; + +export { Association, MessageFlow, SequenceFlow } from '../src/flows/index.js'; +export { BoundaryEvent, EndEvent, IntermediateCatchEvent, IntermediateThrowEvent, StartEvent } from '../src/events/index.js'; +export { EventBasedGateway, ExclusiveGateway, InclusiveGateway, ParallelGateway } from '../src/gateways/index.js'; +export { + CallActivity, + ReceiveTask, + ServiceTask, + ServiceTask as BusinessRuleTask, + ServiceTask as SendTask, + ScriptTask, + SignalTask, + SignalTask as ManualTask, + SignalTask as UserTask, + SubProcess, + SubProcess as AdHocSubProcess, + Task, + Transaction, +} from '../src/tasks/index.js'; +export { + CancelEventDefinition, + CompensateEventDefinition, + ConditionalEventDefinition, + EscalationEventDefinition, + ErrorEventDefinition, + LinkEventDefinition, + MessageEventDefinition, + SignalEventDefinition, + TerminateEventDefinition, + TimerEventDefinition, +} from '../src/eventDefinitions/index.js'; + +export { ActivityError, RunError } from '../src/error/Errors.js'; diff --git a/types/index.d.ts b/types/index.d.ts index 15335581..3d7c4f70 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,263 +1,755 @@ declare module 'bpmn-elements' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; + import type { Broker, BrokerState, Consumer, MessageEnvelope, MessageFields, MessageProperties } from 'smqp'; + import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; + // --- Broker / message contracts ----------------------------------------------- + + export interface ElementBroker extends Broker { + get owner(): T; + } + + export type signalMessage = { /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory + * Optional signal id + * - Activity id + * - Signal-, Message-, Escalation id, etc */ - export class Activity { - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; - /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; - /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message - */ - init(initContent?: Record): void; - /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; - /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; - /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; - /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; - /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; - /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; - /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; - /** - * Stop the activity. If not currently running, just cancels the inbound consumer. - */ - stop(): any; - /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. - */ - next(): any; - /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; - /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest - * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; - /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Look up another activity in the same context. - * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; - - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): any; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; - - private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; - export function BpmnError(errorDef: any, context: any): { - id: any; - type: any; - name: any; - errorCode: any; - resolve: (executionMessage: any, error: any) => { - id: any; - type: any; - messageType: string; - name: any; - code: any; - }; - }; + id?: string; /** - * Build a runtime Context from a parsed BPMN definition. - * @param environment Existing environment to clone; a fresh one is created when omitted + * Optional execution id + * e.g. excutionId of a parallel multi instance user task */ - export function Context(definitionContext: import("moddle-context-serializer").SerializableContext, environment?: Environment): ContextInstance; + executionId?: string; + /** Any other input that will be added to completed activity output */ + [x: string]: any; + }; + + export interface ElementMessageContent { + id?: string; + type?: string; + executionId?: string; + parent?: ElementParent; + [x: string]: any; + } + + export interface ElementBrokerMessage extends MessageEnvelope { + content: ElementMessageContent; + } + + export interface ElementParent { + get id(): string; + get type(): string; + get executionId(): string; + get path(): ElementParent[]; + } + + // --- Element abstract bases --------------------------------------------------- + + export class ElementBase { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + get behaviour(): SerializableElement; + get broker(): Broker; + get environment(): Environment; + /** Per-execution context registry (see `Context`/`ContextInstance` from src). */ + get context(): ContextInstance; + get logger(): ILogger; + } + + export class Element extends ElementBase { + get broker(): ElementBroker; + stop(): void; + resume(): void; + getApi(message?: ElementBrokerMessage): IApi; + on(eventName: string, callback: CallableFunction, options?: any): any; + once(eventName: string, callback: CallableFunction, options?: any): any; + waitFor(eventName: string, options?: any): Promise>; + } + + export class MessageElement { + get id(): string; + get type(): string; + get name(): string; + get parent(): ElementParent; + resolve(executionMessage: ElementBrokerMessage): { + parent: ElementParent; + name: string; + id: string; + type: string; + messageType: string; + }; + } + + // --- Event definitions -------------------------------------------------------- + + // Common ancestor for the typed event definitions; concrete types live in src/eventDefinitions. + export class EventDefinition { + constructor(activity: Activity, eventDefinitionElement: SerializableElement, context?: ContextInstance, index?: number); + get id(): string; + get type(): string; + get executionId(): string; + get isThrowing(): boolean; + get activity(): Activity; + get broker(): Broker; + get logger(): ILogger; + get reference(): { + id?: string; + name: string; + referenceType: string; + }; + [x: string]: any; + execute(executeMessage: ElementBrokerMessage): void; + } + + export enum TimerType { + TimeCycle = 'timeCycle', + TimeDuration = 'timeDuration', + TimeDate = 'timeDate', + } + + export type parsedTimer = { + /** Expires at date time */ + expireAt?: Date; + /** Repeat number of times */ + repeat?: number; + /** Delay in milliseconds */ + delay?: number; + }; + + // --- Conditions --------------------------------------------------------------- + + export interface ICondition { + /** Condition type */ + get type(): string; + [x: string]: any; + execute(message: ElementBrokerMessage, callback: CallableFunction): void; + } + + export interface ISequenceFlowCondition { + /** Condition type, e.g. script or expression */ + get type(): string; /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context + * Execute sequence flow condition + * @param message Source element execution message + * @param callback Callback with truthy result if flow should be taken */ - class ContextInstance { - /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); - id: string; - name: string; - type: string; - sid: string; - definitionContext: import("moddle-context-serializer").SerializableContext; - environment: Environment; - extensionsMapper: ExtensionsMapper; - refs: Map>; - get owner(): Activity | Process | undefined; - /** - * Get or create the activity instance for the given id. - * */ - getActivityById(activityId: string): any; - /** - * Return the cached activity instance, instantiating it the first time it is referenced. - * */ - upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; - /** - * Get or create the sequence flow instance for the given id. - * */ - getSequenceFlowById(sequenceFlowId: string): any; - - getInboundSequenceFlows(activityId: string): any[]; - - getOutboundSequenceFlows(activityId: string): any[]; + execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + } + + // --- Activity behaviour & extensions ------------------------------------------ + + export interface IActivityBehaviour { + id: string; + type: string; + activity: Activity; + environment: Environment; + new (activity: Activity, context: ContextInstance): IActivityBehaviour; + execute(executeMessage: ElementBrokerMessage): void; + } + + // Custom activity behaviour factory signature. + export function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; + + export type Extension = (activity: any, context: any) => IExtension; + export interface IExtension { + activate(message: ElementBrokerMessage): void; + deactivate(message: ElementBrokerMessage): void; + } + + export interface IExpressions { + resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; + } + + // --- Environment -------------------------------------------------------------- + + export interface EnvironmentSettings { + /** true returns dummy service function for service task if not found */ + enableDummyService?: boolean; + /** true forces activity runs to go forward in steps, defaults to false */ + step?: boolean; + /** strict mode, see documentation, defaults to false */ + strict?: boolean; + /** positive integer to control parallel loop batch size, defaults to 50 */ + batchSize?: number; + /** + * disable tracking state between recover and resume + * true will only return state for elements that are actually running + * Defaults to falsy + */ + disableTrackState?: boolean; + /** + * Skip discarding outbound sequence flows. + * Defaults to false + */ + skipDiscard?: boolean; + [x: string]: any; + } + + export interface EnvironmentOptions { + settings?: EnvironmentSettings; + variables?: Record; + services?: Record; + Logger?: LoggerFactory; + timers?: ITimers; + scripts?: IScripts; + extensions?: Record; + /** + * optional override expressions handler + */ + expressions?: IExpressions; + } + + // --- Filter / callback shapes ------------------------------------------------- + + export type startActivityFilterOptions = { + /** Event definition id, i.e. Message, Signal, Error, etc */ + referenceId?: string; + /** Event definition type, i.e. message, signal, error, etc */ + referenceType?: string; + }; + + export type filterPostponed = (elementApi: any) => boolean; + + export type runCallback = (err: Error, definitionApi: any) => void; + + // --- Run-status enums --------------------------------------------------------- + + export enum DefinitionRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + End = 'end', + Discarded = 'discarded', + } + + export enum ProcessRunStatus { + Entered = 'entered', + Start = 'start', + Executing = 'executing', + Errored = 'errored', + End = 'end', + Discarded = 'discarded', + } + + /** + * Activity status + * Can be used to decide when to save states, Timer and Wait is recommended. + */ + export enum ActivityStatus { + /** Idle, not running anything */ + Idle = 'idle', + /** + * At least one activity is executing, + * e.g. a service task making a asynchronous request + */ + Executing = 'executing', + /** + * At least one activity is waiting for a timer to complete, + * usually only TimerEventDefinition's + */ + Timer = 'timer', + /** + * At least one activity is waiting for a signal of some sort, + * e.g. user tasks, intermediate catch events, etc + */ + Wait = 'wait', + } + + /** + * Activity run status + */ + export enum ActivityRunStatus { + /** Run entered, triggered by taken inbound flow */ + Entered = 'entered', + /** Run started */ + Started = 'started', + /** Executing activity behaviour */ + Executing = 'executing', + /** Activity behaviour execution completed successfully */ + Executed = 'executed', + /** Run end, take outbound flows */ + End = 'end', + /** Entering discard run, triggered by discarded inbound flow */ + Discard = 'discard', + /** Run was discarded, discard outbound flows */ + Discarded = 'discarded', + /** Activity behaviour execution failed, discard run */ + Error = 'error', + /** Formatting next run message */ + Formatting = 'formatting', + } + + // --- State snapshots ---------------------------------------------------------- + + export interface ElementState { + id: string; + type: string; + broker?: BrokerState; + [x: string]: any; + } + + export interface EnvironmentState { + settings: EnvironmentSettings; + variables: Record; + output: Record; + } + + export type completedCounters = { completed: number; discarded: number }; + + export interface ActivityExecutionState { + completed: boolean; + [x: string]: any; + } + + export interface ActivityState extends ElementState { + status?: string; + executionId: string; + stopped: boolean; + counters: { taken: number; discarded: number }; + execution?: ActivityExecutionState; + } + + export interface SequenceFlowState extends ElementState { + counters: { take: number; discard: number; looped: number }; + } + + export interface MessageFlowState extends ElementState { + counters: { messages: number }; + } + + export interface AssociationState extends ElementState { + counters: { take: number; discard: number }; + } + + export interface ProcessExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + children: ActivityState[]; + flows?: SequenceFlowState[]; + messageFlows?: MessageFlowState[]; + associations?: AssociationState[]; + } + + export interface ProcessState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: ProcessExecutionState; + } + + export interface DefinitionExecutionState { + executionId: string; + stopped: boolean; + completed: boolean; + status: string; + processes: ProcessState[]; + } + + export interface DefinitionState extends ElementState { + status: string; + stopped: boolean; + executionId?: string; + counters: completedCounters; + environment: EnvironmentState; + execution?: DefinitionExecutionState; + } + + // --- Flow references ---------------------------------------------------------- + + export interface MessageFlowReference { + /** activity id */ + get id(): string; + get processId(): string; + } + + // --- Logging ------------------------------------------------------------------ + + export type LoggerFactory = (scope: string) => ILogger; + + export interface ILogger { + debug(...args: any[]): void; + error(...args: any[]): void; + warn(...args: any[]): void; + [x: string]: any; + } + + // --- Timers ------------------------------------------------------------------- + + export type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; + export type wrappedClearTimeout = (ref: any) => void; + + export interface Timer { + /** The function to call when the timer elapses */ + readonly callback: CallableFunction; + /** The number of milliseconds to wait before calling the callback */ + readonly delay: number; + /** Optional arguments to pass when the callback is called */ + readonly args?: any[]; + /** Timer owner if any */ + readonly owner?: any; + /** Timer Id */ + readonly timerId: string; + /** Timeout, return from setTimeout */ + readonly timerRef: any; + [x: string]: any; + } + + export interface RegisteredTimer { + owner?: any; + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + } + + export interface ITimers { + get setTimeout(): wrappedSetTimeout; + get clearTimeout(): wrappedClearTimeout; + register(owner?: any): RegisteredTimer; + [x: string]: any; + } + + export interface TimersOptions { + /** Defaults to builtin setTimeout */ + setTimeout?: typeof setTimeout; + /** Defaults to builtin clearTimeout */ + clearTimeout?: typeof clearTimeout; + [x: string]: any; + } + + // --- Scripts ------------------------------------------------------------------ + + export interface IScripts { + register(activity: any): Script | undefined; + getScript(language: string, identifier: { id: string; [x: string]: any }): Script; + } + + export interface Script { + execute(executionContext: any, callback: CallableFunction): void; + } + + // --- Generic api shape; constructed via Activity/Process/Definition/Flow Api factories. + + export interface IApi extends ElementBrokerMessage { + get id(): string; + get type(): string; + get name(): string; + get executionId(): string; + get environment(): Environment; + get broker(): ElementBroker; + get owner(): T; + cancel(message?: signalMessage, options?: any): void; + discard(): void; + fail(error: Error): void; + signal(message?: signalMessage, options?: any): void; + stop(): void; + resolveExpression(expression: string): any; + sendApiMessage(action: string, content?: signalMessage, options?: any): void; + getPostponed(...args: any[]): any[]; + createMessage(content?: Record): any; + getExecuting(): IApi[]; + } + + // --- Scope passed to user scripts/services ----------------------------------- + + export interface ExecutionScope { + /** Calling element id */ + id: string; + /** Calling element type */ + type: string; + /** Execution message fields */ + fields: any; + /** Execution message content */ + content: ElementMessageContent; + /** Execution message properties */ + properties: any; + environment: Environment; + /** Calling element logger instance */ + logger?: ILogger; + /** + * Resolve expression with the current scope + * @param expression expression string + * @returns Whatever the expression returns + */ + resolveExpression: (expression: string) => any; + ActivityError: ActivityError; + } + + // --- Context -- + export interface IExtensionsMapper { + get(activity: any): IExtensions[]; + } + + export interface IExtensions extends IExtension { + readonly count: number; + } + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + export class Activity { + /** + * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. + * @param Behaviour Element-specific behaviour constructor invoked per execution + * @param activityDef Parsed BPMN element definition + * @param context Per-execution registry and factory + */ + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + behaviour: { + eventDefinitions: any; + }; + Behaviour: IActivityBehaviour; - getInboundAssociations(activityId: string): any[]; + parent: import("moddle-context-serializer").Parent; + logger: ILogger; + environment: Environment; + context: ContextInstance; - getOutboundAssociations(activityId: string): any[]; + status: ActivityRunStatus; + broker: import("smqp").Broker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + emitFatal: (error: Error, content?: Record) => void; /** - * Get every activity in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id + * Subscribe to inbound flows and start consuming the inbound queue. + * */ + activate(): void; + /** + * Cancel inbound subscriptions and any pending run/format consumers. */ - getActivities(scopeId?: string): any[]; + deactivate(): void; + /** + * Initialise activity executionId and emit init event without starting the run. + * @param initContent Optional content merged into the init message + */ + init(initContent?: Record): void; + /** + * Start running the activity by publishing run.enter and run.start. + * @param runContent Optional content merged into the run message + * @throws {Error} if the activity is already running + */ + run(runContent?: Record): void; + /** + * Snapshot activity state for recover. + * Returns undefined when nothing is running and `disableTrackState` is set. + * */ + getState(): ActivityState; + /** + * Restore activity state captured by getState. Cannot be called while running. + * @returns this when state was applied + * @throws {Error} when activity is currently running + */ + recover(state?: ActivityState): this; + stopped: boolean | undefined; + /** + * Resume after recover. If no run has been started, falls back to activate. + * @throws {Error} when called on a running activity + */ + resume(): void; + /** + * Discard the activity. Stops execution if running and discards outbound flows. + * @param discardContent Optional content propagated with the discard + */ + discard(discardContent?: Record): any; + /** + * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). + * @returns count of subscribed triggers + */ + addInboundListeners(): any; + /** + * Cancel inbound trigger subscriptions added by addInboundListeners. + */ + removeInboundListeners(): void; + /** + * Stop the activity. If not currently running, just cancels the inbound consumer. + */ + stop(): boolean | void; + /** + * Advance one run-step when the environment runs in step mode. No-op otherwise. + */ + next(): false | ElementBrokerMessage | undefined; + /** + * Walk outbound flows to discover the activity graph from this point. + */ + shake(): void; + /** + * Evaluate outbound sequence flows for the given source message. + * @param fromMessage Source run message + * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * */ + evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): void; + /** + * Resolve an Api wrapper for the activity, preferring the running execution if any. + * */ + getApi(message?: ElementBrokerMessage): IApi; + /** + * Look up another activity in the same context. + * */ + getActivityById(elementId: string): Activity | null; + get counters(): { + taken: number; + discarded: number; + }; + get execution(): ActivityExecution | undefined; + get executionId(): string | undefined; + get extensions(): IExtension; + get bpmnIo(): IExtension | undefined; + get formatter(): Formatter; + get isRunning(): boolean; + get outbound(): SequenceFlow[]; + get inbound(): SequenceFlow[]; + get isEnd(): boolean; + get isStart(): boolean; + get isSubProcess(): boolean; + get isTransaction(): boolean; + get isMultiInstance(): boolean; + get isThrowing(): boolean; + get isCatching(): boolean; + get isForCompensation(): boolean; + get isParallelJoin(): boolean; + get triggeredByEvent(): boolean; + get attachedTo(): Activity | null; + get lane(): Lane | undefined; + get eventDefinitions(): any[]; + get parentElement(): Activity | Process; + get initialized(): boolean; + } + /** + * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour + * and drives the execute message flow over the activity broker. + * */ + export class ActivityExecution { + /** + * Per-run execution orchestrator for an Activity. Instantiates the element-specific behaviour + * and drives the execute message flow over the activity broker. + * */ + constructor(activity: Activity, context: ContextInstance); + activity: Activity; + context: ContextInstance; + id: string | undefined; + broker: import("smqp").Broker; + get completed(): boolean; + /** + * Begin executing the activity behaviour. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing + */ + execute(executeMessage: ElementBrokerMessage): any; + executionId: string | undefined; + source: IActivityBehaviour | undefined; + /** + * Bind the execute queue and start consuming execute and api messages. + */ + activate(): void; + /** + * Cancel execute and api consumers and unbind the execute queue. + */ + deactivate(): void; + /** + * Discard the running execution. + */ + discard(): void; + /** + * Resolve an Api wrapper, preferring a behaviour-specific Api when the source exposes one. + * */ + getApi(apiMessage?: ElementBrokerMessage): IApi; + /** + * Pass an execute message straight to the behaviour, executing first if no source is set up yet. + * */ + passthrough(executeMessage: ElementBrokerMessage): any; + /** + * List currently postponed executions as Api wrappers, including those from sub-process behaviours. + */ + getPostponed(): IApi[]; + /** + * Snapshot execution state, merging behaviour-specific state when the source provides it. + */ + getState(): any; + /** + * Restore execution state captured by getState. + * */ + recover(state?: ActivityExecutionState): this; + /** + * Stop the execution via the activity api. + */ + stop(): void; + } + export function BpmnError(errorDef: any, context: any): { + id: any; + type: any; + name: any; + errorCode: any; + resolve: (executionMessage: any, error: any) => { + id: any; + type: any; + messageType: string; + name: any; + code: any; + }; + }; + /** + * Build a runtime Context from a parsed BPMN definition. + * @param environment Existing environment to clone; a fresh one is created when omitted + */ + export function Context(definitionContext: import("moddle-context-serializer").SerializableContext, environment?: Environment): ContextInstance; + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + export class ContextInstance { + /** + * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. + * @param owner Process or sub-process activity that owns this context + */ + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); + id: string; + name: string; + type: string; + sid: string; + definitionContext: import("moddle-context-serializer").SerializableContext; + environment: Environment; + + extensionsMapper: IExtensionsMapper; + refs: Map>; + get owner(): Activity | Process | undefined; + /** + * Get or create the activity instance for the given id. + * */ + getActivityById(activityId: string): Activity | null; + /** + * Return the cached activity instance, instantiating it the first time it is referenced. + * */ + upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): Activity; + /** + * Get or create the sequence flow instance for the given id. + * */ + getSequenceFlowById(sequenceFlowId: string): SequenceFlow | null; + + getInboundSequenceFlows(activityId: string): any[]; + + getOutboundSequenceFlows(activityId: string): any[]; + + getInboundAssociations(activityId: string): any[]; + + getOutboundAssociations(activityId: string): any[]; + /** + * Get every activity in the definition, optionally narrowed to a parent scope. + * @param scopeId Process or sub-process id + */ + getActivities(scopeId?: string): Activity[]; /** * Get every sequence flow in the definition, optionally narrowed to a parent scope. * @param scopeId Process or sub-process id @@ -281,7 +773,7 @@ declare module 'bpmn-elements' { /** * Get or create the process instance for the given id. Each process gets its own cloned environment. * */ - getProcessById(processId: string): any; + getProcessById(processId: string): Process | null; /** * Build a fresh, uncached process instance for the given id. Used by call activities. * */ @@ -289,11 +781,11 @@ declare module 'bpmn-elements' { /** * Get every process in the definition. */ - getProcesses(): any[]; + getProcesses(): (Process | null)[]; /** * Get processes flagged executable in the definition. */ - getExecutableProcesses(): any[]; + getExecutableProcesses(): (Process | null)[]; /** * Get message flows that originate from the given process id. * @param sourceId Source process id @@ -311,92 +803,16 @@ declare module 'bpmn-elements' { * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. * @param scopeId Process or sub-process id */ - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; /** * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. * Returns undefined when the activity has no extensions to attach. * */ - loadExtensions(activity: ElementBase): Extensions | undefined; + loadExtensions(activity: ElementBase): IExtension | undefined; /** * Resolve the parent process or sub-process activity that owns the given activity. * */ - getActivityParentById(activityId: string): any; - - private [K_OWNER]; - } - class ExtensionsMapper { - constructor(context: any); - context: any; - get(activity: any): Extensions; - - _getExtensions(): any[]; - } - class Extensions { - constructor(activity: any, context: any, extensions: any); - extensions: any[]; - get count(): number; - activate(message: any): void; - deactivate(message: any): void; - - private [K_ACTIVATED]; - } - const K_OWNER: unique symbol; - export class DataObject { - constructor(dataObjectDef: any, { environment }: { - environment: any; - }); - id: any; - type: any; - name: any; - behaviour: any; - parent: any; - environment: any; - read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; - write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; - _createContent(value: any): { - id: any; - type: any; - name: any; - value: any; - }; - } - export class DataStore { - constructor(dataStoreDef: any, { environment }: { - environment: any; - }); - id: any; - type: any; - name: any; - behaviour: any; - parent: any; - environment: any; - read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; - write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; - _createContent(value: any): { - id: any; - type: any; - name: any; - value: any; - }; - } - export class DataStoreReference { - constructor(dataObjectDef: any, { environment }: { - environment: any; - }); - id: any; - type: any; - name: any; - behaviour: any; - parent: any; - environment: any; - read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; - write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; - _createContent(value: any): { - id: any; - type: any; - name: any; - value: any; - }; + getActivityParentById(activityId: string): Activity | Process | null; } /** * Top-level wrapper for an executable BPMN definition. Owns its DefinitionExecution and @@ -417,12 +833,18 @@ declare module 'bpmn-elements' { context: ContextInstance | undefined; broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emit: any; - emitFatal: any; - logger: any; + on: ((eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer) | undefined; + once: ((eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer) | undefined; + waitFor: ((eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise) | undefined; + emit: ((eventName: string, content?: Record, props?: any) => void) | undefined; + emitFatal: ((error: Error, content?: Record) => void) | undefined; + + logger: ILogger; /** * Start running the definition. Accepts run options, a callback, or both. * The callback fires once on leave, stop, or error. @@ -449,20 +871,18 @@ declare module 'bpmn-elements' { * */ shake(startId?: string): {} | undefined; - - _shakeProcess(shakeBp: any, startId: any): any; /** * Get every process in the definition. */ - getProcesses(): any; + getProcesses(): any[]; /** * Get processes flagged executable in the definition. */ - getExecutableProcesses(): any; + getExecutableProcesses(): any[]; /** * Get processes that are currently running. */ - getRunningProcesses(): any; + getRunningProcesses(): any[]; getProcessById(processId: string): any; /** @@ -472,27 +892,27 @@ declare module 'bpmn-elements' { /** * Lookup any element (activity, flow, etc.) in the parsed definition by id. * */ - getElementById(elementId: string): any; + getElementById(elementId: string): Activity | null; /** * List currently postponed activities as Api wrappers. * */ - getPostponed(...args: any[]): any; + getPostponed(...args: any[]): any[]; /** * Resolve a Definition Api wrapper, preferring the running execution if any. * @throws {Error} when the definition is not running and no message is given */ - getApi(message?: ElementBrokerMessage): any; + getApi(message?: ElementBrokerMessage): IApi; /** * Send a delegated signal to the running definition. * */ - signal(message?: signalMessage): any; + signal(message?: signalMessage): void; /** * Cancel a running activity inside the definition by delegated api message. * */ - cancelActivity(message?: signalMessage): any; + cancelActivity(message?: signalMessage): void; /** * Deliver a message to a referenced element. Resolves the message reference when the * target element exposes a `resolve` method (e.g. message-, signal-, escalation events). @@ -500,62 +920,113 @@ declare module 'bpmn-elements' { sendMessage(message: { id?: string; [x: string]: any; - }): any; + }): void; /** * Stop the definition if running. */ stop(): void; - - _activateRunConsumers(): void; - - _deactivateRunConsumers(): void; - - _createMessage(override: any): any; - - _onRunMessage(routingKey: any, message: any): any; - - _onResumeMessage(message: any): any; - - _onExecutionMessage(routingKey: any, message: any): void; - - _onApiMessage(routingKey: any, message: any): void; - - _publishEvent(action: any, content: any, msgOpts: any): void; - - _onStop(): void; - - _onBrokerReturnFn(message: any): void; - - _reset(): void; - - _debug(msg: any): void; - - private [K_COUNTERS]; - - private [K_STOPPED]; - - private [K_EXECUTION]; - - private [K_MESSAGE_HANDLERS]; - - private [K_STATUS]; - - private [K_CONSUMING]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; + get counters(): { + completed: number; + discarded: number; + }; + get execution(): DefinitionExecution | undefined; + get executionId(): string | undefined; + get isRunning(): boolean; + get status(): string | undefined; + get stopped(): boolean; + get activityStatus(): string; } - export function Category(activityDef: any): { - id: any; - type: any; - name: any; - behaviour: any; - parent: any; - placeholder: boolean; - }; /** - * Holds global execution config: variables, injected services, timers, scripts engine, + * Drives the execution of a Definition. Activates executable processes, routes inter-process + * delegate messages and call activity hand-offs, and rolls completion up to the Definition. + * */ + export class DefinitionExecution { + /** + * Drives the execution of a Definition. Activates executable processes, routes inter-process + * delegate messages and call activity hand-offs, and rolls completion up to the Definition. + * */ + constructor(definition: Definition, context: ContextInstance); + id: string | undefined; + type: string | undefined; + broker: import("smqp").Broker; + environment: any; + context: ContextInstance; + executionId: string | undefined; + /** + * Activate executable processes and start the definition execution. Resumes if the message + * is redelivered. When `content.processId` is set, only that process is started. + * @throws {Error} when message or executionId is missing + */ + execute(executeMessage: ElementBrokerMessage): any; + /** + * Resume after recover by reactivating running processes. + */ + resume(): any; + /** + * Restore execution state captured by getState. Reinstates running processes from the snapshot. + * */ + recover(state?: DefinitionExecutionState): this; + /** + * Stop the running execution via the api. + */ + stop(): void; + /** + * Get every process in the definition (running first, then any non-running by id). + */ + getProcesses(): any[]; + + getProcessById(processId: string): any; + /** + * Get every process matching the given id (call activities can spawn duplicates). + * */ + getProcessesById(processId: string): any[]; + + getProcessByExecutionId(processExecutionId: string): any; + /** + * Get processes that have an executionId, i.e. are currently running. + */ + getRunningProcesses(): any[]; + /** + * Get processes flagged executable in the definition. + */ + getExecutableProcesses(): any[]; + /** + * Snapshot execution state for recover. + */ + getState(): { + executionId: string | undefined; + stopped: any; + completed: any; + status: any; + processes: any[]; + }; + /** + * Resolve a Definition Api or, when the message belongs to a child process, its process Api. + * */ + getApi(apiMessage?: ElementBrokerMessage): IApi; + /** + * List currently postponed activities across every running process. + * + */ + getPostponed(...args: any[]): any[]; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get processes(): Process[]; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + export function Category(activityDef: any): { + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + placeholder: boolean; + }; + /** + * Holds global execution config: variables, injected services, timers, scripts engine, * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. * */ @@ -570,8 +1041,8 @@ declare module 'bpmn-elements' { expressions: IExpressions; extensions: Record | undefined; output: any; - scripts: IScripts | Scripts; - timers: ITimers | Timers; + scripts: Scripts | IScripts; + timers: Timers | ITimers; settings: { enableDummyService?: boolean; step?: boolean; @@ -580,7 +1051,10 @@ declare module 'bpmn-elements' { disableTrackState?: boolean; skipDiscard: boolean; }; - Logger: LoggerFactory | typeof DummyLogger; + Logger: LoggerFactory; + get variables(): Record; + set services(value: Record); + get services(): Record; /** * Snapshot environment state for recover. */ @@ -639,18 +1113,46 @@ declare module 'bpmn-elements' { * Register a service callable by name. * */ addService(name: string, fn: CallableFunction): void; - - private [K_SERVICES]; - - private [K_VARIABLES]; } - function DummyLogger(): { - debug: () => void; - error: () => void; - warn: () => void; - }; - const K_SERVICES: unique symbol; - const K_VARIABLES: unique symbol; + export class DataObject { + constructor(dataObjectDef: any, { environment }: { + environment: any; + }); + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + environment: any; + read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; + write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + } + export class DataStore { + constructor(dataStoreDef: any, { environment }: { + environment: any; + }); + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + environment: any; + read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; + write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + } + export class DataStoreReference { + constructor(dataObjectDef: any, { environment }: { + environment: any; + }); + id: any; + type: any; + name: any; + behaviour: any; + parent: any; + environment: any; + read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; + write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + } export function Escalation(signalDef: any, context: any): { id: any; type: any; @@ -674,20 +1176,7 @@ declare module 'bpmn-elements' { context: any; activate(message: any): void; deactivate(): void; - _onActivityEvent(routingKey: any, message: any): any; - _onFormatEnter(): any; - _onFormatComplete(message: any): any; - _getDataOutputs(dataOutputs: any): any; - - private [K_CONSUMING]; } - export function Message(messageDef: any, context: any): { - id: any; - type: any; - name: any; - parent: any; - resolve: (executionMessage: any) => any; - }; /** * Process lane. Wraps a `` definition and points back to its owning process; * activities reference their lane through `Activity.lane`. @@ -711,16 +1200,9 @@ declare module 'bpmn-elements' { environment: Environment; broker: import("smqp").Broker; context: ContextInstance; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; + logger: ILogger; get process(): Process; - - private [K_PROCESS]; } - const K_PROCESS: unique symbol; export class MultiInstanceLoopCharacteristics { constructor(activity: any, loopCharacteristics: any); activity: any; @@ -735,6 +1217,13 @@ declare module 'bpmn-elements' { execution: any; execute(executeMessage: any): any; } + export function Message(messageDef: any, context: any): { + id: any; + type: any; + name: any; + parent: any; + resolve: (executionMessage: any) => any; + }; /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. @@ -744,24 +1233,25 @@ declare module 'bpmn-elements' { * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. * */ - constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + constructor(processDef: import("moddle-context-serializer").MappedProcess, context: ContextInstance); id: string | undefined; type: string; name: any; parent: any; - behaviour: Record; + behaviour: {}; isExecutable: any; environment: Environment; context: ContextInstance; broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + logger: ILogger; /** * Allocate an executionId and emit init event without starting the run. * @param useAsExecutionId Override for the generated execution id @@ -784,7 +1274,7 @@ declare module 'bpmn-elements' { getState(): { id: string | undefined; type: string; - executionId: any; + executionId: string | undefined; environment: { settings: { enableDummyService?: boolean; @@ -799,9 +1289,12 @@ declare module 'bpmn-elements' { }; output: any; }; - status: any; - stopped: any; - counters: any; + status: string | undefined; + stopped: boolean; + counters: { + completed: number; + discarded: number; + }; broker: { exchanges: { bindings?: { @@ -831,7 +1324,7 @@ declare module 'bpmn-elements' { messages?: import("smqp").MessageEnvelope[]; }[] | undefined; } | undefined; - execution: any; + execution: ProcessExecutionState | undefined; }; /** * Restore process state captured by getState. @@ -849,31 +1342,18 @@ declare module 'bpmn-elements' { stop(): void; /** * Resolve a Process Api wrapper, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; + * */ + getApi(message?: ElementBrokerMessage): IApi; /** * Send a delegated signal to the running process. * */ - signal(message?: signalMessage): any; + signal(message?: signalMessage): void; /** * Cancel a running activity inside the process by delegated api message. * */ - cancelActivity(message?: signalMessage): any; - - _activateRunConsumers(): void; - - _deactivateRunConsumers(): void; - - _onRunMessage(routingKey: any, message: any): any; - - _onResumeMessage(message: any): any; - - _onExecutionMessage(routingKey: any, message: any): void; - - _publishEvent(state: any, content: any): void; + cancelActivity(message?: signalMessage): void; /** * Deliver a message to a target activity or start activity that references it. * Starts the process if a target is found and the process is idle. @@ -889,7 +1369,7 @@ declare module 'bpmn-elements' { * Get start activities, optionally filtered by referenced event definition. * */ - getStartActivities(filterOptions?: startActivityFilterOptions): any[]; + getStartActivities(filterOptions?: startActivityFilterOptions): Activity[]; /** * Get sequence flows in the process scope. */ @@ -900,56 +1380,27 @@ declare module 'bpmn-elements' { * List currently postponed activities as Api wrappers. * */ - getPostponed(...args: any[]): any; - - _onApiMessage(routingKey: any, message: any): void; - - _onStop(): void; - - _createMessage(override: any): any; - - _debug(msg: any): void; - - private [K_COUNTERS]; - - private [K_CONSUMING]; - - private [K_EXECUTION]; - - private [K_STATUS]; - - private [K_STOPPED]; - - private [K_MESSAGE_HANDLERS]; - - private [K_LANES]; - - private [K_EXTENSIONS]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; + getPostponed(...args: any[]): any[]; + get counters(): { + completed: number; + discarded: number; + }; + get lanes(): Lane[] | undefined; + get extensions(): IExtension | undefined; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string | undefined; + get execution(): ProcessExecution | undefined; + get status(): string | undefined; + get activityStatus(): string; } - const K_LANES: unique symbol; export class Properties { constructor(activity: any, propertiesDef: any, context: any); activity: any; broker: any; activate(message: any): void; deactivate(): void; - _onActivityEvent(routingKey: any, message: any): any; - _formatOnEnter(message: any): any; - _formatOnComplete(message: any): any; - _getProperties(message: any, values: any): {}; - [K_PROPERTIES]: { - properties: Set; - dataInputObjects: Set; - dataOutputObjects: Set; - }; - - private [K_CONSUMING]; } - const K_PROPERTIES: unique symbol; export class ServiceImplementation { constructor(activity: any); type: string; @@ -973,18 +1424,12 @@ declare module 'bpmn-elements' { clearTimeout: any; get executing(): any[]; register(owner: any): RegisteredTimers; - _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; - _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; - - private [K_EXECUTING]; } class RegisteredTimers { constructor(timersApi: any, owner: any); owner: any; setTimeout: any; clearTimeout: any; - - private [K_TIMER_API]; } class Timer_1 { constructor(owner: any, timerId: any, callback: any, delay: any, args: any); @@ -996,5508 +1441,770 @@ declare module 'bpmn-elements' { expireAt: Date; timerRef: any; } - const K_EXECUTING: unique symbol; - const K_TIMER_API: unique symbol; - export class ActivityError extends Error { - constructor(description: any, sourceMessage: any, inner: any); - type: string; - name: any; - description: any; - source: { - fields: any; - content: any; - properties: any; - } | undefined; - inner: any; - code: any; - } - export class RunError extends ActivityError { - constructor(...args: any[]); - } - export function CallActivity(activityDef: any, context: any): Activity; - export function ReceiveTask(activityDef: any, context: any): Activity; - export function ScriptTask(activityDef: any, context: any): Activity; - export function ServiceTask(activityDef: any, context: any): Activity; - export function SignalTask(activityDef: any, context: any): Activity; - export function SubProcess(activityDef: any, context: any): Activity; - export function Task(activityDef: any, context: any): Activity; - export function Transaction(activityDef: any, context: any): Activity; - /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. - * */ - export class Association { - /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. - * */ - constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - sourceId: any; - targetId: any; - isAssociation: boolean; - environment: Environment; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - get counters(): { - take: number; - discard: number; - }; - /** - * Take the association and publish association.take. - * - */ - take(content?: Record): boolean; - /** - * Discard the association and publish association.discard. - * - */ - discard(content?: Record): boolean; - /** - * Snapshot association state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): AssociationState | undefined; - /** - * Restore association state captured by getState. - * */ - recover(state: AssociationState): void; - /** - * Resolve an association-scoped Api wrapper. - * - */ - getApi(message?: ElementBrokerMessage): Api; - /** - * Stop the association's broker. - */ - stop(): void; - - _publishEvent(action: any, content: any): void; - - _createMessageContent(override: any): any; - - private [K_COUNTERS]; - } - /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - export class MessageFlow { - /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - source: any; - target: any; - behaviour: Record; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - emit: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - get counters(): { - messages: number; - }; - /** - * Snapshot message-flow state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): MessageFlowState | undefined; - /** - * Restore message-flow state captured by getState. - * */ - recover(state: MessageFlowState): void; - /** - * Resolve a message-scoped Api wrapper. - * - */ - getApi(message?: ElementBrokerMessage): Api; - /** - * Subscribe to the source element's message and end events to bridge the message across. - */ - activate(): void; - /** - * Cancel the source element subscriptions added by activate. - */ - deactivate(): void; - - _onSourceEnd({ content }: { - content: any; - }): void; - - _createMessageContent(message: any): { - id: string | undefined; - type: string; - name: any; - source: any; - target: any; - parent: any; - message: any; - }; - - private [K_COUNTERS]; - - private [K_SOURCE_ELEMENT]; - } - const K_SOURCE_ELEMENT: unique symbol; - /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - export class SequenceFlow { - /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - sourceId: any; - targetId: any; - isDefault: any; - isSequenceFlow: boolean; - environment: Environment; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - get counters(): { - take: number; - discard: number; - looped: number; - }; - /** - * Take the flow and publish flow.take. - * - */ - take(content?: Record): boolean; - /** - * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits - * flow.looped instead when the target id is already in the sequence. - * - */ - discard(content?: Record): void; - /** - * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` - * is set. - * */ - getState(): SequenceFlowState | undefined; - /** - * Restore flow state captured by getState. - * */ - recover(state: SequenceFlowState): void; - /** - * Resolve a Flow Api wrapper. - * - */ - getApi(message?: ElementBrokerMessage): Api; - /** - * Stop the flow's broker. - */ - stop(): void; - /** - * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop - * when the target was already visited, otherwise flow.shake. - * */ - shake(message: ElementBrokerMessage): any; - /** - * Resolve the flow's condition (script or expression). Returns null when no condition is set. - * Emits a fatal error when the script language is missing or unsupported. - * */ - getCondition(): ISequenceFlowCondition | null; - /** - * Build a flow event message body, optionally merging override content. - * - */ - createMessage(override?: Record): { - id: string | undefined; - type: string; - name: any; - sourceId: any; - targetId: any; - isSequenceFlow: boolean; - isDefault: any; - parent: any; - }; - /** - * Evaluate the flow's condition for the source activity message. Default flows are always taken. - * @param fromMessage Source activity message - * @param callback Callback with truthy result if flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; - - _publishEvent(action: any, content: any): void; - - private [K_COUNTERS]; - } - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - // --- Element abstract bases --------------------------------------------------- - - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - } - - // --- Activity behaviour & extensions ------------------------------------------ - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - // --- Environment -------------------------------------------------------------- - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - // --- Filter / callback shapes ------------------------------------------------- - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - type runCallback = (err: Error, definitionApi: any) => void; - - // --- State snapshots ---------------------------------------------------------- - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - interface DefinitionExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - processes: ProcessState[]; - } - - interface DefinitionState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: DefinitionExecutionState; - } - - // --- Logging ------------------------------------------------------------------ - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - // --- Timers ------------------------------------------------------------------- - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - // --- Scripts ------------------------------------------------------------------ - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - - /** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ - const K_ACTIVATED: unique symbol; - const K_COMPLETED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXECUTION: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_MESSAGE_Q: unique symbol; - const K_REFERENCE_ELEMENT: unique symbol; - const K_REFERENCE_INFO: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STATUS: unique symbol; - const K_STOPPED: unique symbol; - export function BoundaryEvent(activityDef: any, context: any): Activity; - export function EndEvent(activityDef: any, context: any): Activity; - export function IntermediateCatchEvent(activityDef: any, context: any): Activity; - export function IntermediateThrowEvent(activityDef: any, context: any): Activity; - export function StartEvent(activityDef: any, context: any): Activity; - export class CancelEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(_: any, message: any): any; - _complete(output: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _debug(msg: any): void; - - private [K_EXECUTE_MESSAGE]; - - private [K_COMPLETED]; - } - export class CompensateEventDefinition { - constructor(activity: any, eventDefinition: any, context: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; - _onCollect(routingKey: any, message: any): any; - _onCompensateApiMessage(routingKey: any, message: any): any; - _compensate(): any; - _onCollected(routingKey: any, message: any): any; - _onDiscardApiMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stopCollect(): void; - _stop(): void; - _debug(msg: any): void; - - private [K_COMPLETED]; - - private [K_ASSOCIATIONS]; - - private [K_MESSAGE_Q]; - - private [K_COMPENSATE_Q]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ASSOCIATIONS: unique symbol; - const K_COMPENSATE_Q: unique symbol; - export class ConditionalEventDefinition { - constructor(activity: any, eventDefinition: any, _context: any, index: any); - id: any; - type: any; - behaviour: any; - activity: any; - environment: any; - broker: any; - logger: any; - condition: ScriptCondition | ExpressionCondition | null; - get executionId(): any; - execute(executeMessage: any): void; - _setup(executeMessage: any): void; - /** - * Evaluate condition - * */ - evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; - /** - * Handle evaluate result or error - * @param err Condition evaluation error - * @param result Result from evaluated condition, completes execution if truthy - */ - evaluateCallback(err: Error | null, result: any): any; - /** - * Get condition - * @param index Eventdefinition sequence number, used to name registered script - * */ - getCondition(index: number): ExpressionCondition | ScriptCondition | null; - _onDelegateApiMessage(routingKey: any, message: any): void; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _debug(msg: any): void; - - private [K_EXECUTE_MESSAGE]; - } - export class ErrorEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onErrorMessage(routingKey: any, message: any): any; - _onThrowApiMessage(routingKey: any, message: any): any; - _catchError(routingKey: any, message: any, error: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - export class EscalationEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - const K_REFERENCE: unique symbol; - export class LinkEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - id: any; - linkName: any; - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; - _onLinkApiMessage(_: any, message: any): void; - _onShakeMessage(_: any, message: any): void; - - private [K_EXECUTE_MESSAGE]; - } - export class MessageEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): void; - _onApiMessage(routingKey: any, message: any): any; - _complete(verb: any, output: any, options: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - export class SignalEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _complete(output: any, options: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - export class TerminateEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - activity: any; - broker: any; - logger: any; - execute(executeMessage: any): void; - } - export class TimerEventDefinition { - constructor(activity: any, eventDefinition: any); - type: any; - activity: any; - environment: any; - eventDefinition: any; - timeDuration: any; - timeCycle: any; - timeDate: any; - broker: any; - logger: any; - execute(executeMessage: any): void; - startedAt: Date | undefined; - stop(): void; - _completed(completeContent: any, options: any): void; - _onDelegatedApiMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - parse(timerType: any, value: any): { - expireAt: Date | undefined; - repeat: number | undefined; - delay: number | undefined; - }; - _getTimers(executeMessage: any): { - expireAt?: Date | undefined; - }; - _debug(msg: any): void; - - private [K_STOPPED]; - - private [K_TIMER]; - [K_TIMER_CONTENT]: any; - } - const K_TIMER: unique symbol; - const K_TIMER_CONTENT: unique symbol; - class Scripts { - getScript(): void; - register(): void; - } - export function EventBasedGateway(activityDef: any, context: any): Activity; - export function ExclusiveGateway(activityDef: any, context: any): Activity; - export function InclusiveGateway(activityDef: any, context: any): Activity; - export class ParallelGateway { - constructor(activityDef: any, context: any); - id: string | undefined; - } - /** - * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. - * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` - * @param sourceMessage Cloned to back the api - * @param environment Defaults to `broker.owner.environment` - * @throws {Error} when sourceMessage is missing - */ - class Api { - /** - * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. - * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` - * @param sourceMessage Cloned to back the api - * @param environment Defaults to `broker.owner.environment` - * @throws {Error} when sourceMessage is missing - */ - constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment); - id: any; - type: any; - name: any; - executionId: any; - environment: any; - content: any; - fields: any; - messageProperties: any; - broker: any; - owner: any; - messagePrefix: string; - /** - * Send a cancel api message. - * - */ - cancel(message?: signalMessage, options?: any): void; - /** - * Send a discard api message. - */ - discard(): void; - /** - * Send an error api message that fails the activity. - * */ - fail(error: Error): void; - /** - * Send a signal api message. - * - */ - signal(message?: signalMessage, options?: any): void; - /** - * Send a stop api message. - */ - stop(): void; - /** - * Resolve an expression with the api message as scope and the broker owner as context. - * */ - resolveExpression(expression: string): any; - /** - * Publish a custom api message to the broker. - * @param action Routing key suffix, e.g. `signal`, `cancel` - * @param content Merged into the message content - * - */ - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - /** - * List currently postponed activities, falling back to a sub-process execution when applicable. - * - */ - getPostponed(...args: any[]): any; - /** - * Build a message body by merging the given content onto the source content. - * - */ - createMessage(content?: Record): any; - } - /** - * Script condition - * */ - class ScriptCondition { - /** - * Script condition - * */ - constructor(owner: ElementBase, script: any, language: string); - type: string; - language: string; - _owner: ElementBase; - _script: any; - /** - * Execute - * */ - execute(message: any, callback: CallableFunction): any; - } - /** - * Expression condition - * */ - class ExpressionCondition { - /** - * Expression condition - * */ - constructor(owner: ElementBase, expression: string); - type: string; - expression: string; - _owner: ElementBase; - /** - * Execute - * */ - execute(message: any, callback: CallableFunction): any; - } - - export {}; -} - -declare module 'bpmn-elements/errors' { - export function makeErrorFromMessage(errorMessage: any): any; - export class ActivityError extends Error { - constructor(description: any, sourceMessage: any, inner: any); - type: string; - name: any; - description: any; - source: { - fields: any; - content: any; - properties: any; - } | undefined; - inner: any; - code: any; - } - export class RunError extends ActivityError { - constructor(...args: any[]); - } - export class BpmnError extends Error { - constructor(description: any, behaviour: any, sourceMessage: any, inner: any); - type: string; - name: any; - description: any; - code: any; - id: any; - source: { - fields: any; - content: any; - properties: any; - } | undefined; - inner: any; - } - - export {}; -} - -declare module 'bpmn-elements/events' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - export function BoundaryEvent(activityDef: any, context: any): Activity; - export class BoundaryEventBehaviour { - constructor(activity: any); - id: any; - type: any; - attachedTo: any; - activity: any; - environment: any; - broker: any; - execute(executeMessage: any): any; - _onExecutionMessage(routingKey: any, message: any): any; - _onCompleted(_: any, { content }: { - content: any; - }): any; - _onAttachedLeave(_: any, { content }: { - content: any; - }): any; - _onExpectMessage(_: any, { content }: { - content: any; - }): void; - _onDetachMessage(_: any, message: any): void; - _onApiMessage(_: any, message: any): void; - _onRepeatMessage(_: any, message: any): void; - _stop(detach: any): void; - - private [K_EXECUTION]; - - private [K_SHOVELS]; - - private [K_ATTACHED_TAGS]; - - private [K_EXECUTE_MESSAGE]; - - private [K_COMPLETE_CONTENT]; - } - const K_SHOVELS: unique symbol; - const K_ATTACHED_TAGS: unique symbol; - const K_COMPLETE_CONTENT: unique symbol; - export function EndEvent(activityDef: any, context: any): Activity; - export class EndEventBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute(executeMessage: any): any; - - private [K_EXECUTION]; - } - export function IntermediateCatchEvent(activityDef: any, context: any): Activity; - export class IntermediateCatchEventBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute(executeMessage: any): any; - _onApiMessage(executeMessage: any, routingKey: any, message: any): any; - - private [K_EXECUTION]; - } - export function IntermediateThrowEvent(activityDef: any, context: any): Activity; - export class IntermediateThrowEventBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute(executeMessage: any): any; - - private [K_EXECUTION]; - } - export function StartEvent(activityDef: any, context: any): Activity; - export class StartEventBehaviour { - constructor(activity: any); - id: any; - type: any; - activity: any; - broker: any; - get executionId(): any; - execute(executeMessage: any): any; - _onApiMessage(routingKey: any, message: any): any; - _onDelegatedApiMessage(routingKey: any, message: any): any; - _stop(): void; - - private [K_EXECUTION]; - - private [K_EXECUTE_MESSAGE]; - } - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - class Activity { - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; - /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; - /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message - */ - init(initContent?: Record): void; - /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; - /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; - /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; - /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; - /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; - /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; - /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; - /** - * Stop the activity. If not currently running, just cancels the inbound consumer. - */ - stop(): any; - /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. - */ - next(): any; - /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; - /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest - * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; - /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Look up another activity in the same context. - * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; - - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): any; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; - - private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; - const K_ACTIVATED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXECUTION: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STATUS: unique symbol; - const K_STOPPED: unique symbol; - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - // --- Element abstract bases --------------------------------------------------- - - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - // --- Activity behaviour & extensions ------------------------------------------ - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - // --- Environment -------------------------------------------------------------- - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - // --- Filter / callback shapes ------------------------------------------------- - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - // --- State snapshots ---------------------------------------------------------- - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - // --- Logging ------------------------------------------------------------------ - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - // --- Timers ------------------------------------------------------------------- - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - // --- Scripts ------------------------------------------------------------------ - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - - /** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ - /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - class Environment { - /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - constructor(options?: EnvironmentOptions); - options: {}; - expressions: IExpressions; - extensions: Record | undefined; - output: any; - scripts: IScripts | Scripts; - timers: ITimers | Timers; - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - Logger: LoggerFactory | typeof DummyLogger; - /** - * Snapshot environment state for recover. - */ - getState(): { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - /** - * Restore environment state captured by getState. Merges into the existing settings, - * variables, and output rather than replacing them. - * */ - recover(state?: EnvironmentState): this; - /** - * Clone the environment, optionally overriding options. Services are merged when - * `overrideOptions.services` is supplied. - * - */ - clone(overrideOptions?: EnvironmentOptions): any; - /** - * Merge variables into the environment. Non-objects are ignored. - * */ - assignVariables(newVars: Record): void; - /** - * Merge settings into the environment. Non-objects are ignored. - * */ - assignSettings(newSettings: EnvironmentSettings): this; - /** - * Resolve a registered script by language and identifier. - * */ - getScript(...args: any[]): void | Script; - /** - * Register a script for an activity, delegating to the configured scripts engine. - * */ - registerScript(...args: any[]): void | Script; - /** - * Lookup a registered service by name. - * */ - getServiceByName(serviceName: string): CallableFunction; - /** - * Resolve an expression with the environment as scope, optionally extended by an element message. - * @param message Element message merged onto the resolution scope - * - */ - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - /** - * Register a service callable by name. - * */ - addService(name: string, fn: CallableFunction): void; - - private [K_SERVICES]; - - private [K_VARIABLES]; - } - function DummyLogger(): { - debug: () => void; - error: () => void; - warn: () => void; - }; - const K_SERVICES: unique symbol; - const K_VARIABLES: unique symbol; - /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - class ContextInstance { - /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); - id: string; - name: string; - type: string; - sid: string; - definitionContext: import("moddle-context-serializer").SerializableContext; - environment: Environment; - extensionsMapper: ExtensionsMapper; - refs: Map>; - get owner(): Activity | Process | undefined; - /** - * Get or create the activity instance for the given id. - * */ - getActivityById(activityId: string): any; - /** - * Return the cached activity instance, instantiating it the first time it is referenced. - * */ - upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; - /** - * Get or create the sequence flow instance for the given id. - * */ - getSequenceFlowById(sequenceFlowId: string): any; - - getInboundSequenceFlows(activityId: string): any[]; - - getOutboundSequenceFlows(activityId: string): any[]; - - getInboundAssociations(activityId: string): any[]; - - getOutboundAssociations(activityId: string): any[]; - /** - * Get every activity in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id - */ - getActivities(scopeId?: string): any[]; - /** - * Get every sequence flow in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id - */ - getSequenceFlows(scopeId?: string): any[]; - /** - * Return the cached sequence flow, instantiating it the first time it is referenced. - * */ - upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; - /** - * @param scopeId Process or sub-process id - */ - getAssociations(scopeId?: string): any[]; - - upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; - /** - * Create a new context that shares the parsed definition but optionally swaps environment and owner. - * - */ - clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; - /** - * Get or create the process instance for the given id. Each process gets its own cloned environment. - * */ - getProcessById(processId: string): any; - /** - * Build a fresh, uncached process instance for the given id. Used by call activities. - * */ - getNewProcessById(processId: string): any; - /** - * Get every process in the definition. - */ - getProcesses(): any[]; - /** - * Get processes flagged executable in the definition. - */ - getExecutableProcesses(): any[]; - /** - * Get message flows that originate from the given process id. - * @param sourceId Source process id - */ - getMessageFlows(sourceId: string): any[]; - /** - * Get or create a data object instance for the given reference id. - * */ - getDataObjectById(referenceId: string): any; - /** - * Get or create a data store instance for the given reference id. - * */ - getDataStoreById(referenceId: string): any; - /** - * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. - * @param scopeId Process or sub-process id - */ - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; - /** - * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. - * Returns undefined when the activity has no extensions to attach. - * */ - loadExtensions(activity: ElementBase): Extensions | undefined; - /** - * Resolve the parent process or sub-process activity that owns the given activity. - * */ - getActivityParentById(activityId: string): any; - - private [K_OWNER]; - } - class ExtensionsMapper { - constructor(context: any); - context: any; - get(activity: any): Extensions; - - _getExtensions(): any[]; - } - class Extensions { - constructor(activity: any, context: any, extensions: any); - extensions: any[]; - get count(): number; - activate(message: any): void; - deactivate(message: any): void; - - private [K_ACTIVATED]; - } - const K_OWNER: unique symbol; - /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. - * */ - class Process { - /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. - * */ - constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - isExecutable: any; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - /** - * Allocate an executionId and emit init event without starting the run. - * @param useAsExecutionId Override for the generated execution id - */ - init(useAsExecutionId?: string): void; - /** - * Start running the process by publishing run.enter, run.start, and run.execute. - * @param runContent Optional content merged into the run message - * @throws {Error} when the process is already running - */ - run(runContent?: Record): void; - /** - * Resume after recover by republishing the last run message. - * @throws {Error} when called on a running process - */ - resume(): this; - /** - * Snapshot process state for recover. - */ - getState(): { - id: string | undefined; - type: string; - executionId: any; - environment: { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - status: any; - stopped: any; - counters: any; - broker: { - exchanges: { - bindings?: { - id: string; - options: { - priority: number; - }; - queueName: string; - pattern: string; - }[] | undefined; - deliveryQueue?: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - } | undefined; - name: string; - type: import("smqp").exchangeType; - options: { - [x: string]: any; - durable?: boolean; - autoDelete?: boolean; - }; - }[] | undefined; - queues: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - }[] | undefined; - } | undefined; - execution: any; - }; - /** - * Restore process state captured by getState. - * @throws {Error} when called on a running process - */ - recover(state?: ProcessState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(startId?: string): any; - /** - * Stop the process if running. - */ - stop(): void; - /** - * Resolve a Process Api wrapper, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Send a delegated signal to the running process. - * - */ - signal(message?: signalMessage): any; - /** - * Cancel a running activity inside the process by delegated api message. - * - */ - cancelActivity(message?: signalMessage): any; - - _activateRunConsumers(): void; - - _deactivateRunConsumers(): void; - - _onRunMessage(routingKey: any, message: any): any; - - _onResumeMessage(message: any): any; - - _onExecutionMessage(routingKey: any, message: any): void; - - _publishEvent(state: any, content: any): void; - /** - * Deliver a message to a target activity or start activity that references it. - * Starts the process if a target is found and the process is idle. - * */ - sendMessage(message: ElementBrokerMessage): void; - - getActivityById(childId: string): any; - /** - * Get every activity in the process scope. - */ - getActivities(): any; - /** - * Get start activities, optionally filtered by referenced event definition. - * - */ - getStartActivities(filterOptions?: startActivityFilterOptions): any[]; - /** - * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; - - getLaneById(laneId: string): any; - /** - * List currently postponed activities as Api wrappers. - * - */ - getPostponed(...args: any[]): any; - - _onApiMessage(routingKey: any, message: any): void; - - _onStop(): void; - - _createMessage(override: any): any; - - _debug(msg: any): void; - - private [K_COUNTERS]; - - private [K_CONSUMING]; - - private [K_EXECUTION]; - - private [K_STATUS]; - - private [K_STOPPED]; - - private [K_MESSAGE_HANDLERS]; - - private [K_LANES]; - - private [K_EXTENSIONS]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_LANES: unique symbol; - class Timers { - constructor(options: any); - count: number; - options: any; - setTimeout: any; - clearTimeout: any; - get executing(): any[]; - register(owner: any): RegisteredTimers; - _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; - _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; - - private [K_EXECUTING]; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - - private [K_TIMER_API]; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; - } - const K_EXECUTING: unique symbol; - const K_TIMER_API: unique symbol; - class Scripts { - getScript(): void; - register(): void; - } - - export {}; -} - -declare module 'bpmn-elements/eventDefinitions' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - export class CancelEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(_: any, message: any): any; - _complete(output: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _debug(msg: any): void; - - private [K_EXECUTE_MESSAGE]; - - private [K_COMPLETED]; - } - export class CompensateEventDefinition { - constructor(activity: any, eventDefinition: any, context: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; - _onCollect(routingKey: any, message: any): any; - _onCompensateApiMessage(routingKey: any, message: any): any; - _compensate(): any; - _onCollected(routingKey: any, message: any): any; - _onDiscardApiMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stopCollect(): void; - _stop(): void; - _debug(msg: any): void; - - private [K_COMPLETED]; - - private [K_ASSOCIATIONS]; - - private [K_MESSAGE_Q]; - - private [K_COMPENSATE_Q]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ASSOCIATIONS: unique symbol; - const K_COMPENSATE_Q: unique symbol; - export class ConditionalEventDefinition { - constructor(activity: any, eventDefinition: any, _context: any, index: any); - id: any; - type: any; - behaviour: any; - activity: any; - environment: any; - broker: any; - logger: any; - condition: ScriptCondition | ExpressionCondition | null; - get executionId(): any; - execute(executeMessage: any): void; - _setup(executeMessage: any): void; - /** - * Evaluate condition - * */ - evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; - /** - * Handle evaluate result or error - * @param err Condition evaluation error - * @param result Result from evaluated condition, completes execution if truthy - */ - evaluateCallback(err: Error | null, result: any): any; - /** - * Get condition - * @param index Eventdefinition sequence number, used to name registered script - * */ - getCondition(index: number): ExpressionCondition | ScriptCondition | null; - _onDelegateApiMessage(routingKey: any, message: any): void; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _debug(msg: any): void; - - private [K_EXECUTE_MESSAGE]; - } - export class ErrorEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onErrorMessage(routingKey: any, message: any): any; - _onThrowApiMessage(routingKey: any, message: any): any; - _catchError(routingKey: any, message: any, error: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - export class EscalationEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - const K_REFERENCE: unique symbol; - export class LinkEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - id: any; - linkName: any; - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; - _onLinkApiMessage(_: any, message: any): void; - _onShakeMessage(_: any, message: any): void; - - private [K_EXECUTE_MESSAGE]; - } - export class MessageEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): void; - _onApiMessage(routingKey: any, message: any): any; - _complete(verb: any, output: any, options: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - export class SignalEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; - _onCatchMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _complete(output: any, options: any): any; - _stop(): void; - _getReferenceInfo(message: any): { - message: any; - } | { - message: any; - description: string; - }; - _debug(msg: any): void; - [K_REFERENCE_ELEMENT]: any; - - private [K_COMPLETED]; - - private [K_MESSAGE_Q]; - - private [K_EXECUTE_MESSAGE]; - [K_REFERENCE_INFO]: { - message: any; - } | { - message: any; - description: string; - } | undefined; - } - export class TerminateEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - activity: any; - broker: any; - logger: any; - execute(executeMessage: any): void; - } - export class TimerEventDefinition { - constructor(activity: any, eventDefinition: any); - type: any; - activity: any; - environment: any; - eventDefinition: any; - timeDuration: any; - timeCycle: any; - timeDate: any; - broker: any; - logger: any; - execute(executeMessage: any): void; - startedAt: Date | undefined; - stop(): void; - _completed(completeContent: any, options: any): void; - _onDelegatedApiMessage(routingKey: any, message: any): any; - _onApiMessage(routingKey: any, message: any): any; - _stop(): void; - parse(timerType: any, value: any): { - expireAt: Date | undefined; - repeat: number | undefined; - delay: number | undefined; - }; - _getTimers(executeMessage: any): { - expireAt?: Date | undefined; - }; - _debug(msg: any): void; - - private [K_STOPPED]; - - private [K_TIMER]; - [K_TIMER_CONTENT]: any; - } - const K_TIMER: unique symbol; - const K_TIMER_CONTENT: unique symbol; - const K_ACTIVATED: unique symbol; - const K_COMPLETED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXECUTION: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_MESSAGE_Q: unique symbol; - const K_REFERENCE_ELEMENT: unique symbol; - const K_REFERENCE_INFO: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STATUS: unique symbol; - const K_STOPPED: unique symbol; - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - // --- Element abstract bases --------------------------------------------------- - - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - // --- Activity behaviour & extensions ------------------------------------------ - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - // --- Environment -------------------------------------------------------------- - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - // --- Filter / callback shapes ------------------------------------------------- - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - // --- State snapshots ---------------------------------------------------------- - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - // --- Logging ------------------------------------------------------------------ - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - // --- Timers ------------------------------------------------------------------- - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - // --- Scripts ------------------------------------------------------------------ - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - - /** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ - /** - * Script condition - * */ - class ScriptCondition { - /** - * Script condition - * */ - constructor(owner: ElementBase, script: any, language: string); - type: string; - language: string; - _owner: ElementBase; - _script: any; - /** - * Execute - * */ - execute(message: any, callback: CallableFunction): any; - } - /** - * Expression condition - * */ - class ExpressionCondition { - /** - * Expression condition - * */ - constructor(owner: ElementBase, expression: string); - type: string; - expression: string; - _owner: ElementBase; - /** - * Execute - * */ - execute(message: any, callback: CallableFunction): any; - } - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - class Activity { - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; - /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; - /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message - */ - init(initContent?: Record): void; - /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; - /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; - /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; - /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; - /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; - /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; - /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; - /** - * Stop the activity. If not currently running, just cancels the inbound consumer. - */ - stop(): any; - /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. - */ - next(): any; - /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; - /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest - * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; - /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Look up another activity in the same context. - * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; - - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): any; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; - - private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; - /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. - * */ - class Process { - /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. - * */ - constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - isExecutable: any; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - /** - * Allocate an executionId and emit init event without starting the run. - * @param useAsExecutionId Override for the generated execution id - */ - init(useAsExecutionId?: string): void; - /** - * Start running the process by publishing run.enter, run.start, and run.execute. - * @param runContent Optional content merged into the run message - * @throws {Error} when the process is already running - */ - run(runContent?: Record): void; - /** - * Resume after recover by republishing the last run message. - * @throws {Error} when called on a running process - */ - resume(): this; - /** - * Snapshot process state for recover. - */ - getState(): { - id: string | undefined; - type: string; - executionId: any; - environment: { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - status: any; - stopped: any; - counters: any; - broker: { - exchanges: { - bindings?: { - id: string; - options: { - priority: number; - }; - queueName: string; - pattern: string; - }[] | undefined; - deliveryQueue?: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - } | undefined; - name: string; - type: import("smqp").exchangeType; - options: { - [x: string]: any; - durable?: boolean; - autoDelete?: boolean; - }; - }[] | undefined; - queues: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - }[] | undefined; - } | undefined; - execution: any; - }; - /** - * Restore process state captured by getState. - * @throws {Error} when called on a running process - */ - recover(state?: ProcessState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(startId?: string): any; - /** - * Stop the process if running. - */ - stop(): void; - /** - * Resolve a Process Api wrapper, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Send a delegated signal to the running process. - * - */ - signal(message?: signalMessage): any; - /** - * Cancel a running activity inside the process by delegated api message. - * - */ - cancelActivity(message?: signalMessage): any; - - _activateRunConsumers(): void; - - _deactivateRunConsumers(): void; - - _onRunMessage(routingKey: any, message: any): any; - - _onResumeMessage(message: any): any; - - _onExecutionMessage(routingKey: any, message: any): void; - - _publishEvent(state: any, content: any): void; - /** - * Deliver a message to a target activity or start activity that references it. - * Starts the process if a target is found and the process is idle. - * */ - sendMessage(message: ElementBrokerMessage): void; - - getActivityById(childId: string): any; - /** - * Get every activity in the process scope. - */ - getActivities(): any; - /** - * Get start activities, optionally filtered by referenced event definition. - * - */ - getStartActivities(filterOptions?: startActivityFilterOptions): any[]; - /** - * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; - - getLaneById(laneId: string): any; - /** - * List currently postponed activities as Api wrappers. - * - */ - getPostponed(...args: any[]): any; - - _onApiMessage(routingKey: any, message: any): void; - - _onStop(): void; - - _createMessage(override: any): any; - - _debug(msg: any): void; - - private [K_COUNTERS]; - - private [K_CONSUMING]; - - private [K_EXECUTION]; - - private [K_STATUS]; - - private [K_STOPPED]; - - private [K_MESSAGE_HANDLERS]; - - private [K_LANES]; - - private [K_EXTENSIONS]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_LANES: unique symbol; - /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - class Environment { - /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - constructor(options?: EnvironmentOptions); - options: {}; - expressions: IExpressions; - extensions: Record | undefined; - output: any; - scripts: IScripts | Scripts; - timers: ITimers | Timers; - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - Logger: LoggerFactory | typeof DummyLogger; - /** - * Snapshot environment state for recover. - */ - getState(): { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - /** - * Restore environment state captured by getState. Merges into the existing settings, - * variables, and output rather than replacing them. - * */ - recover(state?: EnvironmentState): this; - /** - * Clone the environment, optionally overriding options. Services are merged when - * `overrideOptions.services` is supplied. - * - */ - clone(overrideOptions?: EnvironmentOptions): any; - /** - * Merge variables into the environment. Non-objects are ignored. - * */ - assignVariables(newVars: Record): void; - /** - * Merge settings into the environment. Non-objects are ignored. - * */ - assignSettings(newSettings: EnvironmentSettings): this; - /** - * Resolve a registered script by language and identifier. - * */ - getScript(...args: any[]): void | Script; - /** - * Register a script for an activity, delegating to the configured scripts engine. - * */ - registerScript(...args: any[]): void | Script; - /** - * Lookup a registered service by name. - * */ - getServiceByName(serviceName: string): CallableFunction; - /** - * Resolve an expression with the environment as scope, optionally extended by an element message. - * @param message Element message merged onto the resolution scope - * - */ - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - /** - * Register a service callable by name. - * */ - addService(name: string, fn: CallableFunction): void; - - private [K_SERVICES]; - - private [K_VARIABLES]; - } - function DummyLogger(): { - debug: () => void; - error: () => void; - warn: () => void; - }; - const K_SERVICES: unique symbol; - const K_VARIABLES: unique symbol; - /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - class ContextInstance { - /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); - id: string; - name: string; - type: string; - sid: string; - definitionContext: import("moddle-context-serializer").SerializableContext; - environment: Environment; - extensionsMapper: ExtensionsMapper; - refs: Map>; - get owner(): Activity | Process | undefined; - /** - * Get or create the activity instance for the given id. - * */ - getActivityById(activityId: string): any; - /** - * Return the cached activity instance, instantiating it the first time it is referenced. - * */ - upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; - /** - * Get or create the sequence flow instance for the given id. - * */ - getSequenceFlowById(sequenceFlowId: string): any; - - getInboundSequenceFlows(activityId: string): any[]; - - getOutboundSequenceFlows(activityId: string): any[]; - - getInboundAssociations(activityId: string): any[]; - - getOutboundAssociations(activityId: string): any[]; - /** - * Get every activity in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id - */ - getActivities(scopeId?: string): any[]; - /** - * Get every sequence flow in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id - */ - getSequenceFlows(scopeId?: string): any[]; - /** - * Return the cached sequence flow, instantiating it the first time it is referenced. - * */ - upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; - /** - * @param scopeId Process or sub-process id - */ - getAssociations(scopeId?: string): any[]; - - upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; - /** - * Create a new context that shares the parsed definition but optionally swaps environment and owner. - * - */ - clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; - /** - * Get or create the process instance for the given id. Each process gets its own cloned environment. - * */ - getProcessById(processId: string): any; - /** - * Build a fresh, uncached process instance for the given id. Used by call activities. - * */ - getNewProcessById(processId: string): any; - /** - * Get every process in the definition. - */ - getProcesses(): any[]; - /** - * Get processes flagged executable in the definition. - */ - getExecutableProcesses(): any[]; - /** - * Get message flows that originate from the given process id. - * @param sourceId Source process id - */ - getMessageFlows(sourceId: string): any[]; - /** - * Get or create a data object instance for the given reference id. - * */ - getDataObjectById(referenceId: string): any; - /** - * Get or create a data store instance for the given reference id. - * */ - getDataStoreById(referenceId: string): any; - /** - * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. - * @param scopeId Process or sub-process id - */ - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; - /** - * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. - * Returns undefined when the activity has no extensions to attach. - * */ - loadExtensions(activity: ElementBase): Extensions | undefined; - /** - * Resolve the parent process or sub-process activity that owns the given activity. - * */ - getActivityParentById(activityId: string): any; - - private [K_OWNER]; - } - class ExtensionsMapper { - constructor(context: any); - context: any; - get(activity: any): Extensions; - - _getExtensions(): any[]; - } - class Extensions { - constructor(activity: any, context: any, extensions: any); - extensions: any[]; - get count(): number; - activate(message: any): void; - deactivate(message: any): void; - - private [K_ACTIVATED]; - } - const K_OWNER: unique symbol; - class Timers { - constructor(options: any); - count: number; - options: any; - setTimeout: any; - clearTimeout: any; - get executing(): any[]; - register(owner: any): RegisteredTimers; - _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; - _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; - - private [K_EXECUTING]; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - - private [K_TIMER_API]; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; - } - const K_EXECUTING: unique symbol; - const K_TIMER_API: unique symbol; - class Scripts { - getScript(): void; - register(): void; - } - - export {}; -} - -declare module 'bpmn-elements/flows' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. - * */ - export class Association { - /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. - * */ - constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - sourceId: any; - targetId: any; - isAssociation: boolean; - environment: Environment; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - get counters(): { - take: number; - discard: number; - }; - /** - * Take the association and publish association.take. - * - */ - take(content?: Record): boolean; - /** - * Discard the association and publish association.discard. - * - */ - discard(content?: Record): boolean; - /** - * Snapshot association state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): AssociationState | undefined; - /** - * Restore association state captured by getState. - * */ - recover(state: AssociationState): void; - /** - * Resolve an association-scoped Api wrapper. - * - */ - getApi(message?: ElementBrokerMessage): Api; - /** - * Stop the association's broker. - */ - stop(): void; - - _publishEvent(action: any, content: any): void; - - _createMessageContent(override: any): any; - - private [K_COUNTERS]; - } - /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - export class MessageFlow { - /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - source: any; - target: any; - behaviour: Record; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - emit: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - get counters(): { - messages: number; - }; - /** - * Snapshot message-flow state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): MessageFlowState | undefined; - /** - * Restore message-flow state captured by getState. - * */ - recover(state: MessageFlowState): void; - /** - * Resolve a message-scoped Api wrapper. - * - */ - getApi(message?: ElementBrokerMessage): Api; - /** - * Subscribe to the source element's message and end events to bridge the message across. - */ - activate(): void; - /** - * Cancel the source element subscriptions added by activate. - */ - deactivate(): void; - - _onSourceEnd({ content }: { - content: any; - }): void; - - _createMessageContent(message: any): { - id: string | undefined; - type: string; - name: any; - source: any; - target: any; - parent: any; - message: any; - }; - - private [K_COUNTERS]; - - private [K_SOURCE_ELEMENT]; - } - const K_SOURCE_ELEMENT: unique symbol; - /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - export class SequenceFlow { - /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - sourceId: any; - targetId: any; - isDefault: any; - isSequenceFlow: boolean; - environment: Environment; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - get counters(): { - take: number; - discard: number; - looped: number; - }; - /** - * Take the flow and publish flow.take. - * - */ - take(content?: Record): boolean; - /** - * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits - * flow.looped instead when the target id is already in the sequence. - * - */ - discard(content?: Record): void; - /** - * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` - * is set. - * */ - getState(): SequenceFlowState | undefined; - /** - * Restore flow state captured by getState. - * */ - recover(state: SequenceFlowState): void; - /** - * Resolve a Flow Api wrapper. - * - */ - getApi(message?: ElementBrokerMessage): Api; - /** - * Stop the flow's broker. - */ - stop(): void; - /** - * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop - * when the target was already visited, otherwise flow.shake. - * */ - shake(message: ElementBrokerMessage): any; - /** - * Resolve the flow's condition (script or expression). Returns null when no condition is set. - * Emits a fatal error when the script language is missing or unsupported. - * */ - getCondition(): ISequenceFlowCondition | null; - /** - * Build a flow event message body, optionally merging override content. - * - */ - createMessage(override?: Record): { - id: string | undefined; - type: string; - name: any; - sourceId: any; - targetId: any; - isSequenceFlow: boolean; - isDefault: any; - parent: any; - }; - /** - * Evaluate the flow's condition for the source activity message. Default flows are always taken. - * @param fromMessage Source activity message - * @param callback Callback with truthy result if flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; - - _publishEvent(action: any, content: any): void; - - private [K_COUNTERS]; - } - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - // --- Element abstract bases --------------------------------------------------- - - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; - /** - * Execute sequence flow condition - * @param message Source element execution message - * @param callback Callback with truthy result if flow should be taken - */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; - } - - // --- Activity behaviour & extensions ------------------------------------------ - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - // --- Environment -------------------------------------------------------------- - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - // --- Filter / callback shapes ------------------------------------------------- - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - // --- State snapshots ---------------------------------------------------------- - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - // --- Logging ------------------------------------------------------------------ - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - // --- Timers ------------------------------------------------------------------- - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - // --- Scripts ------------------------------------------------------------------ - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - - /** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ - /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - class Environment { - /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - constructor(options?: EnvironmentOptions); - options: {}; - expressions: IExpressions; - extensions: Record | undefined; - output: any; - scripts: IScripts | Scripts; - timers: ITimers | Timers; - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - Logger: LoggerFactory | typeof DummyLogger; - /** - * Snapshot environment state for recover. - */ - getState(): { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - /** - * Restore environment state captured by getState. Merges into the existing settings, - * variables, and output rather than replacing them. - * */ - recover(state?: EnvironmentState): this; - /** - * Clone the environment, optionally overriding options. Services are merged when - * `overrideOptions.services` is supplied. - * - */ - clone(overrideOptions?: EnvironmentOptions): any; - /** - * Merge variables into the environment. Non-objects are ignored. - * */ - assignVariables(newVars: Record): void; - /** - * Merge settings into the environment. Non-objects are ignored. - * */ - assignSettings(newSettings: EnvironmentSettings): this; - /** - * Resolve a registered script by language and identifier. - * */ - getScript(...args: any[]): void | Script; - /** - * Register a script for an activity, delegating to the configured scripts engine. - * */ - registerScript(...args: any[]): void | Script; - /** - * Lookup a registered service by name. - * */ - getServiceByName(serviceName: string): CallableFunction; - /** - * Resolve an expression with the environment as scope, optionally extended by an element message. - * @param message Element message merged onto the resolution scope - * - */ - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - /** - * Register a service callable by name. - * */ - addService(name: string, fn: CallableFunction): void; - - private [K_SERVICES]; - - private [K_VARIABLES]; - } - function DummyLogger(): { - debug: () => void; - error: () => void; - warn: () => void; - }; - const K_SERVICES: unique symbol; - const K_VARIABLES: unique symbol; - /** - * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. - * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` - * @param sourceMessage Cloned to back the api - * @param environment Defaults to `broker.owner.environment` - * @throws {Error} when sourceMessage is missing - */ - class Api { - /** - * Lightweight wrapper over the broker that exposes signal/cancel/fail/stop and other api actions. - * @param pfx Message prefix, e.g. `activity`, `process`, `definition`, `flow` - * @param sourceMessage Cloned to back the api - * @param environment Defaults to `broker.owner.environment` - * @throws {Error} when sourceMessage is missing - */ - constructor(pfx: string, broker: any, sourceMessage: ElementBrokerMessage, environment?: Environment); - id: any; - type: any; - name: any; - executionId: any; - environment: any; - content: any; - fields: any; - messageProperties: any; - broker: any; - owner: any; - messagePrefix: string; - /** - * Send a cancel api message. - * - */ - cancel(message?: signalMessage, options?: any): void; - /** - * Send a discard api message. - */ - discard(): void; - /** - * Send an error api message that fails the activity. - * */ - fail(error: Error): void; - /** - * Send a signal api message. - * - */ - signal(message?: signalMessage, options?: any): void; - /** - * Send a stop api message. - */ - stop(): void; - /** - * Resolve an expression with the api message as scope and the broker owner as context. - * */ - resolveExpression(expression: string): any; - /** - * Publish a custom api message to the broker. - * @param action Routing key suffix, e.g. `signal`, `cancel` - * @param content Merged into the message content - * - */ - sendApiMessage(action: string, content?: signalMessage, options?: any): void; - /** - * List currently postponed activities, falling back to a sub-process execution when applicable. - * - */ - getPostponed(...args: any[]): any; - /** - * Build a message body by merging the given content onto the source content. - * - */ - createMessage(content?: Record): any; - } - const K_ACTIVATED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXECUTION: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STATUS: unique symbol; - const K_STOPPED: unique symbol; - /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - class ContextInstance { - /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); - id: string; - name: string; - type: string; - sid: string; - definitionContext: import("moddle-context-serializer").SerializableContext; - environment: Environment; - extensionsMapper: ExtensionsMapper; - refs: Map>; - get owner(): Activity | Process | undefined; - /** - * Get or create the activity instance for the given id. - * */ - getActivityById(activityId: string): any; - /** - * Return the cached activity instance, instantiating it the first time it is referenced. - * */ - upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; - /** - * Get or create the sequence flow instance for the given id. - * */ - getSequenceFlowById(sequenceFlowId: string): any; - - getInboundSequenceFlows(activityId: string): any[]; - - getOutboundSequenceFlows(activityId: string): any[]; - - getInboundAssociations(activityId: string): any[]; - - getOutboundAssociations(activityId: string): any[]; - /** - * Get every activity in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id - */ - getActivities(scopeId?: string): any[]; - /** - * Get every sequence flow in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id - */ - getSequenceFlows(scopeId?: string): any[]; - /** - * Return the cached sequence flow, instantiating it the first time it is referenced. - * */ - upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; - /** - * @param scopeId Process or sub-process id - */ - getAssociations(scopeId?: string): any[]; - - upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; - /** - * Create a new context that shares the parsed definition but optionally swaps environment and owner. - * - */ - clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; - /** - * Get or create the process instance for the given id. Each process gets its own cloned environment. - * */ - getProcessById(processId: string): any; - /** - * Build a fresh, uncached process instance for the given id. Used by call activities. - * */ - getNewProcessById(processId: string): any; - /** - * Get every process in the definition. - */ - getProcesses(): any[]; - /** - * Get processes flagged executable in the definition. - */ - getExecutableProcesses(): any[]; - /** - * Get message flows that originate from the given process id. - * @param sourceId Source process id - */ - getMessageFlows(sourceId: string): any[]; - /** - * Get or create a data object instance for the given reference id. - * */ - getDataObjectById(referenceId: string): any; - /** - * Get or create a data store instance for the given reference id. - * */ - getDataStoreById(referenceId: string): any; - /** - * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. - * @param scopeId Process or sub-process id - */ - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; - /** - * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. - * Returns undefined when the activity has no extensions to attach. - * */ - loadExtensions(activity: ElementBase): Extensions | undefined; - /** - * Resolve the parent process or sub-process activity that owns the given activity. - * */ - getActivityParentById(activityId: string): any; - - private [K_OWNER]; - } - class ExtensionsMapper { - constructor(context: any); - context: any; - get(activity: any): Extensions; - - _getExtensions(): any[]; - } - class Extensions { - constructor(activity: any, context: any, extensions: any); - extensions: any[]; - get count(): number; - activate(message: any): void; - deactivate(message: any): void; - - private [K_ACTIVATED]; - } - const K_OWNER: unique symbol; - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - class Activity { - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; - /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; - /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message - */ - init(initContent?: Record): void; - /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; - /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; - /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; - /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; - /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; - /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; - /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; - /** - * Stop the activity. If not currently running, just cancels the inbound consumer. - */ - stop(): any; - /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. - */ - next(): any; - /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; - /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest - * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; - /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Look up another activity in the same context. - * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; - - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): any; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; - - private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; - /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. - * */ - class Process { - /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. - * */ - constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - parent: any; - behaviour: Record; - isExecutable: any; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - /** - * Allocate an executionId and emit init event without starting the run. - * @param useAsExecutionId Override for the generated execution id - */ - init(useAsExecutionId?: string): void; - /** - * Start running the process by publishing run.enter, run.start, and run.execute. - * @param runContent Optional content merged into the run message - * @throws {Error} when the process is already running - */ - run(runContent?: Record): void; - /** - * Resume after recover by republishing the last run message. - * @throws {Error} when called on a running process - */ - resume(): this; - /** - * Snapshot process state for recover. - */ - getState(): { - id: string | undefined; - type: string; - executionId: any; - environment: { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - status: any; - stopped: any; - counters: any; - broker: { - exchanges: { - bindings?: { - id: string; - options: { - priority: number; - }; - queueName: string; - pattern: string; - }[] | undefined; - deliveryQueue?: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - } | undefined; - name: string; - type: import("smqp").exchangeType; - options: { - [x: string]: any; - durable?: boolean; - autoDelete?: boolean; - }; - }[] | undefined; - queues: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - }[] | undefined; - } | undefined; - execution: any; - }; - /** - * Restore process state captured by getState. - * @throws {Error} when called on a running process - */ - recover(state?: ProcessState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(startId?: string): any; - /** - * Stop the process if running. - */ - stop(): void; - /** - * Resolve a Process Api wrapper, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Send a delegated signal to the running process. - * - */ - signal(message?: signalMessage): any; - /** - * Cancel a running activity inside the process by delegated api message. - * - */ - cancelActivity(message?: signalMessage): any; - - _activateRunConsumers(): void; - - _deactivateRunConsumers(): void; - - _onRunMessage(routingKey: any, message: any): any; - - _onResumeMessage(message: any): any; - - _onExecutionMessage(routingKey: any, message: any): void; - - _publishEvent(state: any, content: any): void; - /** - * Deliver a message to a target activity or start activity that references it. - * Starts the process if a target is found and the process is idle. - * */ - sendMessage(message: ElementBrokerMessage): void; - - getActivityById(childId: string): any; - /** - * Get every activity in the process scope. - */ - getActivities(): any; - /** - * Get start activities, optionally filtered by referenced event definition. - * - */ - getStartActivities(filterOptions?: startActivityFilterOptions): any[]; - /** - * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; - - getLaneById(laneId: string): any; - /** - * List currently postponed activities as Api wrappers. - * - */ - getPostponed(...args: any[]): any; - - _onApiMessage(routingKey: any, message: any): void; - - _onStop(): void; - - _createMessage(override: any): any; - - _debug(msg: any): void; - - private [K_COUNTERS]; - - private [K_CONSUMING]; - - private [K_EXECUTION]; - - private [K_STATUS]; - - private [K_STOPPED]; - - private [K_MESSAGE_HANDLERS]; - - private [K_LANES]; - - private [K_EXTENSIONS]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_LANES: unique symbol; - class Timers { - constructor(options: any); - count: number; - options: any; - setTimeout: any; - clearTimeout: any; - get executing(): any[]; - register(owner: any): RegisteredTimers; - _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; - _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; - - private [K_EXECUTING]; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - - private [K_TIMER_API]; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; - } - const K_EXECUTING: unique symbol; - const K_TIMER_API: unique symbol; - class Scripts { - getScript(): void; - register(): void; - } - - export {}; -} - -declare module 'bpmn-elements/gateways' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - export function EventBasedGateway(activityDef: any, context: any): Activity; - export class EventBasedGatewayBehaviour { - constructor(activity: any, context: any); - id: any; - type: any; - activity: any; - broker: any; - context: any; - execute(executeMessage: any): any; - _onTargetCompleted(executeMessage: any, _: any, message: any, owner: any): void; - _complete(completedContent: any): void; - _stop(): void; - - private [K_TARGETS]; - - private [K_COMPLETED]; - } - export function ExclusiveGateway(activityDef: any, context: any): Activity; - export class ExclusiveGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute({ content }: { - content: any; - }): void; - } - export function InclusiveGateway(activityDef: any, context: any): Activity; - export class InclusiveGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute({ content }: { - content: any; - }): void; - } - export class ParallelGateway { - constructor(activityDef: any, context: any); - id: string | undefined; - } - export class ParallelGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - activity: any; - broker: any; - inbound: Set; - isConverging: boolean; - execute(executeMessage: any): any; - setup(executeMessage: any): any; - peerMonitor: PeerMonitor | undefined; - _onExecuteMessage(routingKey: any, message: any): any; - _onPeerEnterMessage(_: any, message: any): void; - _complete(): any; - _stop(): void; - - private [K_EXECUTE_MESSAGE]; - - private [K_TARGETS]; - } - class PeerMonitor { - constructor(activity: any, peers: any, targets: any); - activity: any; - id: any; - broker: any; - running: Map; - index: number; - discarded: number; - watching: Map; - peers: any; - targets: any; - touched: Set; - inbound: any[]; - get isRunning(): boolean; - execute(executeMessage: any): number; - monitor(peerActivity: any): void; - _onCompleteMessage(_routingKey: any, message: any): boolean; - stop(): void; - } - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - class Activity { - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; - /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; - /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message - */ - init(initContent?: Record): void; - /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; - /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; - /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; - /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; - /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; - /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; - /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; - /** - * Stop the activity. If not currently running, just cancels the inbound consumer. - */ - stop(): any; - /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. - */ - next(): any; - /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; - /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest - * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; - /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; - /** - * Look up another activity in the same context. - * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; - - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): any; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; - - private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; - const K_ACTIVATED: unique symbol; - const K_COMPLETED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXECUTION: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STATUS: unique symbol; - const K_STOPPED: unique symbol; - const K_TARGETS: unique symbol; - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; - /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - // --- Element abstract bases --------------------------------------------------- - - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - // --- Activity behaviour & extensions ------------------------------------------ - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } - - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } - - // --- Environment -------------------------------------------------------------- - - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; - /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - // --- Filter / callback shapes ------------------------------------------------- - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - // --- State snapshots ---------------------------------------------------------- - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - // --- Logging ------------------------------------------------------------------ - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - // --- Timers ------------------------------------------------------------------- - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - // --- Scripts ------------------------------------------------------------------ - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - - /** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ + export class ActivityError extends Error { + constructor(description: any, sourceMessage: any, inner: any); + type: string; + name: any; + description: any; + source: { + fields: any; + content: any; + properties: any; + } | undefined; + inner: any; + code: any; + } + export class RunError extends ActivityError { + constructor(...args: any[]); + } /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - class Environment { + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + class ProcessExecution { /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + constructor(parentActivity: Process | Activity, context: ContextInstance); + id: string | undefined; + type: string; + isSubProcess: any; + isTransaction: any; + broker: import("smqp").Broker; + environment: Environment; + context: ContextInstance; + executionId: string | undefined; + /** + * Activate children and start the process execution. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing + */ + execute(executeMessage: ElementBrokerMessage): true | void; + /** + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. + */ + resume(): void; + /** + * Snapshot execution state including children, flows, message flows, and associations. + * */ + getState(): ProcessExecutionState; + /** + * Restore execution state captured by getState. + * */ + recover(state?: ProcessExecutionState): this; + /** + * Walk activity graph from the given start id, or every start activity when omitted. * */ - constructor(options?: EnvironmentOptions); - options: {}; - expressions: IExpressions; - extensions: Record | undefined; - output: any; - scripts: IScripts | Scripts; - timers: ITimers | Timers; - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - Logger: LoggerFactory | typeof DummyLogger; + shake(fromId?: string): any; /** - * Snapshot environment state for recover. + * Stop the running process execution via the api. */ - getState(): { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; + stop(): void; + /** + * List currently postponed children as Api wrappers. + * + */ + getPostponed(filterFn?: filterPostponed): any[]; + /** + * Queue a discard message that propagates to all running children. + */ + discard(): any; + /** + * Queue a cancel message that propagates to all running children. + */ + cancel(): any; + /** + * Get child activities in the process scope. + */ + getActivities(): any; + + getActivityById(activityId: string): any; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any; + /** + * Get associations in the process scope. + */ + getAssociations(): any; + /** + * Resolve a process or child Api for the given message. + * */ + getApi(message?: ElementBrokerMessage): IApi; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + /** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + export class SequenceFlow { + /** + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isDefault: any; + isSequenceFlow: boolean; + environment: Environment; + logger: ILogger; + broker: import("smqp").Broker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + emitFatal: (error: Error, content?: Record) => void; + get counters(): { + take: number; + discard: number; + looped: number; }; /** - * Restore environment state captured by getState. Merges into the existing settings, - * variables, and output rather than replacing them. + * Take the flow and publish flow.take. + * + */ + take(content?: Record): boolean; + /** + * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits + * flow.looped instead when the target id is already in the sequence. + * + */ + discard(content?: Record): void; + /** + * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` + * is set. * */ - recover(state?: EnvironmentState): this; + getState(): SequenceFlowState | undefined; /** - * Clone the environment, optionally overriding options. Services are merged when - * `overrideOptions.services` is supplied. + * Restore flow state captured by getState. + * */ + recover(state: SequenceFlowState): void; + /** + * Resolve a Flow Api wrapper. + * */ + getApi(message?: ElementBrokerMessage): IApi; + /** + * Stop the flow's broker. + */ + stop(): void; + /** + * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop + * when the target was already visited, otherwise flow.shake. + * */ + shake(message: ElementBrokerMessage): any; + /** + * Resolve the flow's condition (script or expression). Returns null when no condition is set. + * Emits a fatal error when the script language is missing or unsupported. + * */ + getCondition(): ISequenceFlowCondition | null; + /** + * Build a flow event message body, optionally merging override content. * */ - clone(overrideOptions?: EnvironmentOptions): any; + createMessage(override?: Record): { + id: string | undefined; + type: string; + name: any; + sourceId: any; + targetId: any; + isSequenceFlow: boolean; + isDefault: any; + parent: any; + }; /** - * Merge variables into the environment. Non-objects are ignored. + * Evaluate the flow's condition for the source activity message. Default flows are always taken. + * @param fromMessage Source activity message + * @param callback Callback with truthy result if flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; + } + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. * */ - assignVariables(newVars: Record): void; + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; /** - * Merge settings into the environment. Non-objects are ignored. + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. * */ - assignSettings(newSettings: EnvironmentSettings): this; + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; + } + class Scripts { + getScript(): void; + register(): void; + } + /** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + export class Association { /** - * Resolve a registered script by language and identifier. + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. * */ - getScript(...args: any[]): void | Script; + constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isAssociation: boolean; + environment: Environment; + logger: ILogger; + broker: import("smqp").Broker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + get counters(): { + take: number; + discard: number; + }; /** - * Register a script for an activity, delegating to the configured scripts engine. + * Take the association and publish association.take. + * + */ + take(content?: Record): boolean; + /** + * Discard the association and publish association.discard. + * + */ + discard(content?: Record): boolean; + /** + * Snapshot association state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): AssociationState | undefined; + /** + * Restore association state captured by getState. * */ - registerScript(...args: any[]): void | Script; + recover(state: AssociationState): void; /** - * Lookup a registered service by name. + * Resolve an association-scoped Api wrapper. * */ - getServiceByName(serviceName: string): CallableFunction; + getApi(message?: ElementBrokerMessage): IApi; /** - * Resolve an expression with the environment as scope, optionally extended by an element message. - * @param message Element message merged onto the resolution scope - * + * Stop the association's broker. */ - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; - /** - * Register a service callable by name. - * */ - addService(name: string, fn: CallableFunction): void; - - private [K_SERVICES]; - - private [K_VARIABLES]; + stop(): void; } - function DummyLogger(): { - debug: () => void; - error: () => void; - warn: () => void; - }; - const K_SERVICES: unique symbol; - const K_VARIABLES: unique symbol; /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - class ContextInstance { + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + export class MessageFlow { /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); - id: string; - name: string; + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; type: string; - sid: string; - definitionContext: import("moddle-context-serializer").SerializableContext; + name: any; + parent: any; + source: any; + target: any; + behaviour: Record; environment: Environment; - extensionsMapper: ExtensionsMapper; - refs: Map>; - get owner(): Activity | Process | undefined; + context: ContextInstance; + broker: import("smqp").Broker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + emit: (eventName: string, content?: Record, props?: any) => void; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + logger: ILogger; + get counters(): { + messages: number; + }; /** - * Get or create the activity instance for the given id. + * Snapshot message-flow state. Returns undefined when broker has no state and + * `disableTrackState` is set. * */ - getActivityById(activityId: string): any; + getState(): MessageFlowState | undefined; /** - * Return the cached activity instance, instantiating it the first time it is referenced. + * Restore message-flow state captured by getState. * */ - upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + recover(state: MessageFlowState): void; /** - * Get or create the sequence flow instance for the given id. + * Resolve a message-scoped Api wrapper. * */ - getSequenceFlowById(sequenceFlowId: string): any; - - getInboundSequenceFlows(activityId: string): any[]; - - getOutboundSequenceFlows(activityId: string): any[]; - - getInboundAssociations(activityId: string): any[]; - - getOutboundAssociations(activityId: string): any[]; + getApi(message?: ElementBrokerMessage): IApi; /** - * Get every activity in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id + * Subscribe to the source element's message and end events to bridge the message across. */ - getActivities(scopeId?: string): any[]; + activate(): void; /** - * Get every sequence flow in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id + * Cancel the source element subscriptions added by activate. */ - getSequenceFlows(scopeId?: string): any[]; + deactivate(): void; + } + export function BoundaryEvent(activityDef: any, context: any): Activity; + export function EndEvent(activityDef: any, context: any): Activity; + export function IntermediateCatchEvent(activityDef: any, context: any): Activity; + export function IntermediateThrowEvent(activityDef: any, context: any): Activity; + export function StartEvent(activityDef: any, context: any): Activity; + export function EventBasedGateway(activityDef: any, context: any): Activity; + export function ExclusiveGateway(activityDef: any, context: any): Activity; + export function InclusiveGateway(activityDef: any, context: any): Activity; + export class ParallelGateway { + constructor(activityDef: any, context: any); + id: string | undefined; + } + /** + * Create call activity + * @returns Call activity + */ + export function CallActivity(activityDef: import("moddle-context-serializer").MappedActivity, context: ContextInstance): Activity; + export function ReceiveTask(activityDef: any, context: any): Activity; + export function ScriptTask(activityDef: any, context: any): Activity; + export function SendTask(activityDef: any, context: any): Activity; + export function UserTask(activityDef: any, context: any): Activity; + export function AdHocSubProcess(activityDef: any, context: any): Activity; + export function Task(activityDef: any, context: any): Activity; + export function Transaction(activityDef: any, context: any): Activity; + export class CancelEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + environment: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + } + export class CompensateEventDefinition { + constructor(activity: any, eventDefinition: any, context: any); + id: any; + type: any; + reference: { + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + } + export class ConditionalEventDefinition { + constructor(activity: any, eventDefinition: any, _context: any, index: any); + id: any; + type: any; + behaviour: any; + activity: any; + environment: any; + broker: any; + logger: any; + condition: ScriptCondition | ExpressionCondition | null; + get executionId(): any; + execute(executeMessage: any): void; /** - * Return the cached sequence flow, instantiating it the first time it is referenced. + * Evaluate condition * */ - upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; /** - * @param scopeId Process or sub-process id + * Handle evaluate result or error + * @param err Condition evaluation error + * @param result Result from evaluated condition, completes execution if truthy */ - getAssociations(scopeId?: string): any[]; - - upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + evaluateCallback(err: Error | null, result: any): any; /** - * Create a new context that shares the parsed definition but optionally swaps environment and owner. - * - */ - clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; + * Get condition + * @param index Eventdefinition sequence number, used to name registered script + * */ + getCondition(index: number): ExpressionCondition | ScriptCondition | null; + } + export class ErrorEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + environment: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + } + export class EscalationEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + } + export class LinkEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: { + id: any; + linkName: any; + referenceType: string; + }; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; + } + export class MessageEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + } + export class SignalEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + } + export class TerminateEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + activity: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + } + export class TimerEventDefinition { + constructor(activity: any, eventDefinition: any); + type: any; + activity: any; + environment: any; + eventDefinition: any; + timeDuration: any; + timeCycle: any; + timeDate: any; + broker: any; + logger: any; + get executionId(): any; + get stopped(): boolean; + get timer(): any; + execute(executeMessage: any): void; + startedAt: Date | undefined; + stop(): void; + parse(timerType: any, value: any): { + expireAt: Date | undefined; + repeat: number | undefined; + delay: number | undefined; + }; + } + /** + * Script condition + * */ + class ScriptCondition { /** - * Get or create the process instance for the given id. Each process gets its own cloned environment. + * Script condition * */ - getProcessById(processId: string): any; + constructor(owner: ElementBase, script: any, language: string); + type: string; + language: string; /** - * Build a fresh, uncached process instance for the given id. Used by call activities. + * Execute * */ - getNewProcessById(processId: string): any; - /** - * Get every process in the definition. - */ - getProcesses(): any[]; - /** - * Get processes flagged executable in the definition. - */ - getExecutableProcesses(): any[]; - /** - * Get message flows that originate from the given process id. - * @param sourceId Source process id - */ - getMessageFlows(sourceId: string): any[]; + execute(message: any, callback: CallableFunction): any; + } + /** + * Expression condition + * */ + class ExpressionCondition { /** - * Get or create a data object instance for the given reference id. + * Expression condition * */ - getDataObjectById(referenceId: string): any; + constructor(owner: ElementBase, expression: string); + type: string; + expression: string; /** - * Get or create a data store instance for the given reference id. + * Execute * */ - getDataStoreById(referenceId: string): any; - /** - * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. - * @param scopeId Process or sub-process id - */ - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + execute(message: ElementBrokerMessage, callback: CallableFunction): any; + } + + export { Consumer, MessageFields, MessageProperties, SerializableContext, SerializableElement }; +} + +declare module 'bpmn-elements/errors' { + export function makeErrorFromMessage(errorMessage: any): any; + export class ActivityError extends Error { + constructor(description: any, sourceMessage: any, inner: any); + type: string; + name: any; + description: any; + source: { + fields: any; + content: any; + properties: any; + } | undefined; + inner: any; + code: any; + } + export class RunError extends ActivityError { + constructor(...args: any[]); + } + export class BpmnError extends Error { + constructor(description: any, behaviour: any, sourceMessage: any, inner: any); + type: string; + name: any; + description: any; + code: any; + id: any; + source: { + fields: any; + content: any; + properties: any; + } | undefined; + inner: any; + } + + export {}; +} + +declare module 'bpmn-elements/events' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; + import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + + export function BoundaryEvent(activityDef: any, context: any): Activity; + export class BoundaryEventBehaviour { + constructor(activity: any); + id: any; + type: any; + attachedTo: any; + activity: any; + environment: any; + broker: any; + get executionId(): any; + get cancelActivity(): any; + execute(executeMessage: any): any; + } + export function EndEvent(activityDef: any, context: any): Activity; + export class EndEventBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute(executeMessage: any): any; + } + export function IntermediateCatchEvent(activityDef: any, context: any): Activity; + export class IntermediateCatchEventBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute(executeMessage: any): any; + } + export function IntermediateThrowEvent(activityDef: any, context: any): Activity; + export class IntermediateThrowEventBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute(executeMessage: any): any; + } + export function StartEvent(activityDef: any, context: any): Activity; + export class StartEventBehaviour { + constructor(activity: any); + id: any; + type: any; + activity: any; + broker: any; + get executionId(): any; + execute(executeMessage: any): any; + } + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { /** - * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. - * Returns undefined when the activity has no extensions to attach. + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. * */ - loadExtensions(activity: ElementBase): Extensions | undefined; + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; /** - * Resolve the parent process or sub-process activity that owns the given activity. + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. * */ - getActivityParentById(activityId: string): any; - - private [K_OWNER]; - } - class ExtensionsMapper { - constructor(context: any); - context: any; - get(activity: any): Extensions; - - _getExtensions(): any[]; - } - class Extensions { - constructor(activity: any, context: any, extensions: any); - extensions: any[]; - get count(): number; - activate(message: any): void; - deactivate(message: any): void; - - private [K_ACTIVATED]; + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } - const K_OWNER: unique symbol; /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. * */ - class Process { + class ProcessExecution { /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. * */ - constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + constructor(parentActivity: Process | Activity, context: ContextInstance); id: string | undefined; type: string; - name: any; - parent: any; - behaviour: Record; - isExecutable: any; + isSubProcess: any; + isTransaction: any; + broker: import("smqp").Broker; environment: Environment; context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - /** - * Allocate an executionId and emit init event without starting the run. - * @param useAsExecutionId Override for the generated execution id - */ - init(useAsExecutionId?: string): void; - /** - * Start running the process by publishing run.enter, run.start, and run.execute. - * @param runContent Optional content merged into the run message - * @throws {Error} when the process is already running - */ - run(runContent?: Record): void; - /** - * Resume after recover by republishing the last run message. - * @throws {Error} when called on a running process - */ - resume(): this; + executionId: string | undefined; /** - * Snapshot process state for recover. + * Activate children and start the process execution. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing */ - getState(): { - id: string | undefined; - type: string; - executionId: any; - environment: { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - status: any; - stopped: any; - counters: any; - broker: { - exchanges: { - bindings?: { - id: string; - options: { - priority: number; - }; - queueName: string; - pattern: string; - }[] | undefined; - deliveryQueue?: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - } | undefined; - name: string; - type: import("smqp").exchangeType; - options: { - [x: string]: any; - durable?: boolean; - autoDelete?: boolean; - }; - }[] | undefined; - queues: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - }[] | undefined; - } | undefined; - execution: any; - }; + execute(executeMessage: ElementBrokerMessage): true | void; /** - * Restore process state captured by getState. - * @throws {Error} when called on a running process + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. */ - recover(state?: ProcessState): this; + resume(): void; + /** + * Snapshot execution state including children, flows, message flows, and associations. + * */ + getState(): ProcessExecutionState; + /** + * Restore execution state captured by getState. + * */ + recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. * */ - shake(startId?: string): any; + shake(fromId?: string): any; /** - * Stop the process if running. + * Stop the running process execution via the api. */ stop(): void; /** - * Resolve a Process Api wrapper, preferring the running execution if any. + * List currently postponed children as Api wrappers. * */ - getApi(message?: ElementBrokerMessage): any; + getPostponed(filterFn?: filterPostponed): any[]; /** - * Send a delegated signal to the running process. - * + * Queue a discard message that propagates to all running children. */ - signal(message?: signalMessage): any; + discard(): any; /** - * Cancel a running activity inside the process by delegated api message. - * + * Queue a cancel message that propagates to all running children. */ - cancelActivity(message?: signalMessage): any; - - _activateRunConsumers(): void; - - _deactivateRunConsumers(): void; - - _onRunMessage(routingKey: any, message: any): any; - - _onResumeMessage(message: any): any; - - _onExecutionMessage(routingKey: any, message: any): void; - - _publishEvent(state: any, content: any): void; - /** - * Deliver a message to a target activity or start activity that references it. - * Starts the process if a target is found and the process is idle. - * */ - sendMessage(message: ElementBrokerMessage): void; - - getActivityById(childId: string): any; + cancel(): any; /** - * Get every activity in the process scope. + * Get child activities in the process scope. */ getActivities(): any; - /** - * Get start activities, optionally filtered by referenced event definition. - * - */ - getStartActivities(filterOptions?: startActivityFilterOptions): any[]; + + getActivityById(activityId: string): any; /** * Get sequence flows in the process scope. */ getSequenceFlows(): any; - - getLaneById(laneId: string): any; /** - * List currently postponed activities as Api wrappers. - * + * Get associations in the process scope. */ - getPostponed(...args: any[]): any; - - _onApiMessage(routingKey: any, message: any): void; - - _onStop(): void; - - _createMessage(override: any): any; - - _debug(msg: any): void; - - private [K_COUNTERS]; - - private [K_CONSUMING]; - - private [K_EXECUTION]; - - private [K_STATUS]; - - private [K_STOPPED]; - - private [K_MESSAGE_HANDLERS]; - - private [K_LANES]; - - private [K_EXTENSIONS]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; + getAssociations(): any; + /** + * Resolve a process or child Api for the given message. + * */ + getApi(message?: ElementBrokerMessage): IApi; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; } - const K_LANES: unique symbol; - class Timers { - constructor(options: any); - count: number; - options: any; - setTimeout: any; - clearTimeout: any; - get executing(): any[]; - register(owner: any): RegisteredTimers; - _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; - _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; - - private [K_EXECUTING]; + class Scripts { + getScript(): void; + register(): void; } class RegisteredTimers { constructor(timersApi: any, owner: any); owner: any; setTimeout: any; clearTimeout: any; - - private [K_TIMER_API]; } class Timer_1 { constructor(owner: any, timerId: any, callback: any, delay: any, args: any); @@ -6509,330 +2216,213 @@ declare module 'bpmn-elements/gateways' { expireAt: Date; timerRef: any; } - const K_EXECUTING: unique symbol; - const K_TIMER_API: unique symbol; - class Scripts { - getScript(): void; - register(): void; - } export {}; } -declare module 'bpmn-elements/tasks' { +declare module 'bpmn-elements/eventDefinitions' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - export function CallActivity(activityDef: any, context: any): Activity; - export class CallActivityBehaviour { - constructor(activity: any); + import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + + export class CancelEventDefinition { + constructor(activity: any, eventDefinition: any); id: any; type: any; - calledElement: any; - loopCharacteristics: any; + reference: { + referenceType: string; + }; + isThrowing: any; activity: any; - broker: any; environment: any; + broker: any; + logger: any; + get executionId(): any; execute(executeMessage: any): any; - _onDelegatedApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; - _onApiMessage(calledElement: any, executeMessage: any, routingKey: any, message: any): any; - _stop(executionId: any): void; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; } - export function ReceiveTask(activityDef: any, context: any): Activity; - export class ReceiveTaskBehaviour { - constructor(activity: any); + export class CompensateEventDefinition { + constructor(activity: any, eventDefinition: any, context: any); id: any; type: any; - reference: any; - loopCharacteristics: any; + reference: { + referenceType: string; + }; + isThrowing: any; activity: any; broker: any; + logger: any; + get executionId(): any; execute(executeMessage: any): any; - - private [K_REFERENCE_ELEMENT]; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; } - export function ScriptTask(activityDef: any, context: any): Activity; - export class ScriptTaskBehaviour { - constructor(activity: any); + export class ConditionalEventDefinition { + constructor(activity: any, eventDefinition: any, _context: any, index: any); id: any; type: any; - scriptFormat: any; - loopCharacteristics: any; + behaviour: any; activity: any; environment: any; - execute(executeMessage: any): any; + broker: any; + logger: any; + condition: ScriptCondition | ExpressionCondition | null; + get executionId(): any; + execute(executeMessage: any): void; + /** + * Evaluate condition + * */ + evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; + /** + * Handle evaluate result or error + * @param err Condition evaluation error + * @param result Result from evaluated condition, completes execution if truthy + */ + evaluateCallback(err: Error | null, result: any): any; + /** + * Get condition + * @param index Eventdefinition sequence number, used to name registered script + * */ + getCondition(index: number): ExpressionCondition | ScriptCondition | null; } - export function ServiceTask(activityDef: any, context: any): Activity; - export class ServiceTaskBehaviour { - constructor(activity: any); + export class ErrorEventDefinition { + constructor(activity: any, eventDefinition: any); id: any; type: any; - loopCharacteristics: any; + reference: any; + isThrowing: any; activity: any; environment: any; broker: any; + logger: any; + get executionId(): any; execute(executeMessage: any): any; - service: any; - getService(message: any): any; - _onApiMessage(executeMessage: any, _: any, message: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; } - export function SignalTask(activityDef: any, context: any): Activity; - export class SignalTaskBehaviour { - constructor(activity: any); + export class EscalationEventDefinition { + constructor(activity: any, eventDefinition: any); id: any; type: any; - loopCharacteristics: any; + reference: any; + isThrowing: any; activity: any; broker: any; + logger: any; + get executionId(): any; execute(executeMessage: any): any; - _onDelegatedApiMessage(executeMessage: any, routingKey: any, message: any): any; - _onApiMessage(executeMessage: any, routingKey: any, message: any): any; - _stop(executionId: any): void; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; } - export function SubProcess(activityDef: any, context: any): Activity; - export class SubProcessBehaviour { - constructor(activity: any, context: any); + export class LinkEventDefinition { + constructor(activity: any, eventDefinition: any); id: any; type: any; - loopCharacteristics: any; + reference: { + id: any; + linkName: any; + referenceType: string; + }; + isThrowing: any; activity: any; - context: any; - environment: any; broker: any; - executionId: any; + logger: any; + get executionId(): any; execute(executeMessage: any): any; - getState(): any; - recover(state: any): ProcessExecution | undefined; - getPostponed(): any[]; - _upsertExecution(executeMessage: any): any; - _addListeners(executionId: any): void; - _onExecutionCompleted(_: any, message: any): any; - _completeExecution(completeRoutingKey: any, content: any): void; - getApi(apiMessage: any): any; - _getExecutionById(executionId: any): any; - - private [K_EXECUTIONS]; - - private [K_ON_EXECUTION_COMPLETED]; + executeCatch(executeMessage: any): any; + executeThrow(executeMessage: any): any; } - const K_EXECUTIONS: unique symbol; - const K_ON_EXECUTION_COMPLETED: unique symbol; - export function Task(activityDef: any, context: any): Activity; - export class TaskBehaviour { - constructor(activity: any); + export class MessageEventDefinition { + constructor(activity: any, eventDefinition: any); id: any; type: any; - loopCharacteristics: any; + reference: any; + isThrowing: any; + activity: any; broker: any; + logger: any; + get executionId(): any; execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; } - export function Transaction(activityDef: any, context: any): Activity; - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - class Activity { - /** - * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. - * @param Behaviour Element-specific behaviour constructor invoked per execution - * @param activityDef Parsed BPMN element definition - * @param context Per-execution registry and factory - */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; - name: any; - behaviour: { - eventDefinitions: any; - }; - Behaviour: IActivityBehaviour; - parent: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; + export class SignalEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + reference: any; + isThrowing: any; + activity: any; + broker: any; + logger: any; + get executionId(): any; + execute(executeMessage: any): any; + executeCatch(executeMessage: any): void; + executeThrow(executeMessage: any): any; + } + export class TerminateEventDefinition { + constructor(activity: any, eventDefinition: any); + id: any; + type: any; + activity: any; + broker: any; + logger: any; + execute(executeMessage: any): void; + } + export class TimerEventDefinition { + constructor(activity: any, eventDefinition: any); + type: any; + activity: any; + environment: any; + eventDefinition: any; + timeDuration: any; + timeCycle: any; + timeDate: any; + broker: any; + logger: any; + get executionId(): any; + get stopped(): boolean; + get timer(): any; + execute(executeMessage: any): void; + startedAt: Date | undefined; + stop(): void; + parse(timerType: any, value: any): { + expireAt: Date | undefined; + repeat: number | undefined; + delay: number | undefined; }; - environment: Environment; - context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - emitFatal: any; - /** - * Subscribe to inbound flows and start consuming the inbound queue. - */ - activate(): 0 | import("smqp").Consumer | undefined; - /** - * Cancel inbound subscriptions and any pending run/format consumers. - */ - deactivate(): void; - /** - * Initialise activity executionId and emit init event without starting the run. - * @param initContent Optional content merged into the init message - */ - init(initContent?: Record): void; - /** - * Start running the activity by publishing run.enter and run.start. - * @param runContent Optional content merged into the run message - * @throws {Error} if the activity is already running - */ - run(runContent?: Record): void; - /** - * Snapshot activity state for recover. - * Returns undefined when nothing is running and `disableTrackState` is set. - */ - getState(): any; - /** - * Restore activity state captured by getState. Cannot be called while running. - * @returns this when state was applied - * @throws {Error} when activity is currently running - */ - recover(state?: ActivityState): this; - stopped: boolean | undefined; - status: any; - /** - * Resume after recover. If no run has been started, falls back to activate. - * @throws {Error} when called on a running activity - */ - resume(): 0 | import("smqp").Consumer | undefined; - /** - * Discard the activity. Stops execution if running and discards outbound flows. - * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; - /** - * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers - */ - addInboundListeners(): number; - /** - * Cancel inbound trigger subscriptions added by addInboundListeners. - */ - removeInboundListeners(): void; - /** - * Stop the activity. If not currently running, just cancels the inbound consumer. - */ - stop(): any; - /** - * Advance one run-step when the environment runs in step mode. No-op otherwise. - */ - next(): any; + } + /** + * Script condition + * */ + class ScriptCondition { /** - * Walk outbound flows to discover the activity graph from this point. - */ - shake(): void; + * Script condition + * */ + constructor(owner: ElementBase, script: any, language: string); + type: string; + language: string; /** - * Evaluate outbound sequence flows for the given source message. - * @param fromMessage Source run message - * @param discardRestAtTake When true, take only the first matching flow and discard the rest + * Execute * */ - evaluateOutbound(fromMessage: ElementBrokerMessage, discardRestAtTake: boolean, callback: (err: Error, evaluationResult: any) => void): any; + execute(message: any, callback: CallableFunction): any; + } + /** + * Expression condition + * */ + class ExpressionCondition { /** - * Resolve an Api wrapper for the activity, preferring the running execution if any. - * - */ - getApi(message?: ElementBrokerMessage): any; + * Expression condition + * */ + constructor(owner: ElementBase, expression: string); + type: string; + expression: string; /** - * Look up another activity in the same context. + * Execute * */ - getActivityById(elementId: string): any; - - _runDiscard(discardContent: any): void; - - _discardRun(): void; - - _onShakeMessage(sourceMessage: any): any; - - _shakeOutbound(sourceMessage: any): any; - - _consumeInbound(): import("smqp").Consumer | undefined; - - _onInbound(routingKey: any, message: any): void; - - _onInboundEvent(routingKey: any, message: any): any; - - _consumeRunQ(): void; - - _pauseRunQ(): void; - - _onRunMessage(routingKey: any, message: any, messageProperties: any): any; - - _continueRunMessage(routingKey: any, message: any): any; - - _onExecutionMessage(routingKey: any, message: any): any; - - _ackRunExecuteMessage(): void; - - _doRunLeave(message: any, isDiscarded: any, onOutbound: any): any; - - _doOutbound(fromMessage: any, isDiscarded: any, callback: any): any; - - _doRunOutbound(outboundList: any, content: any, discardSequence: any): any; - - _publishRunOutbound(outboundFlow: any, content: any, discardSequence: any): void; - - _onResumeMessage(message: any): any; - - _publishEvent(state: any, content: any, properties: any): void; - - _onStop(message: any): void; - - _consumeApi(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _createMessage(override: any): any; - - _getOutboundSequenceFlowById(flowId: any): any; - - _deactivateRunConsumers(): void; - - private [K_ACTIVITY_DEF]; - - private [K_COUNTERS]; - - private [K_FLOWS]; - - private [K_FLAGS]; - - private [K_EXEC]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EVENT_DEFINITIONS]; - - private [K_EXTENSIONS]; - - private [K_CONSUMING]; - - private [K_CONSUMING_RUN_Q]; - - private [K_ACTIVATED]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; + execute(message: ElementBrokerMessage, callback: CallableFunction): any; } - const K_ACTIVITY_DEF: unique symbol; - const K_FLOWS: unique symbol; - const K_FLAGS: unique symbol; - const K_EXEC: unique symbol; - const K_EVENT_DEFINITIONS: unique symbol; - const K_CONSUMING_RUN_Q: unique symbol; - const K_ACTIVATED: unique symbol; - const K_COMPLETED: unique symbol; - const K_CONSUMING: unique symbol; - const K_COUNTERS: unique symbol; - const K_EXECUTE_MESSAGE: unique symbol; - const K_EXECUTION: unique symbol; - const K_EXTENSIONS: unique symbol; - const K_MESSAGE_HANDLERS: unique symbol; - const K_REFERENCE_ELEMENT: unique symbol; - const K_STATE_MESSAGE: unique symbol; - const K_STATUS: unique symbol; - const K_STOPPED: unique symbol; /** * Drives the execution of a single process or sub-process: activates children, routes activity * events, and rolls completion up to the owning Process or sub-process Activity. @@ -6850,31 +2440,21 @@ declare module 'bpmn-elements/tasks' { broker: import("smqp").Broker; environment: Environment; context: ContextInstance; - _exchangeName: string; executionId: string | undefined; /** * Activate children and start the process execution. Resumes if the message is redelivered. * @throws {Error} when message or executionId is missing */ - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): true | void; /** * Resume after recover. Reshakes elements when there are converging gateways or multiple * start activities, then resumes any postponed children. */ - resume(): any; + resume(): void; /** * Snapshot execution state including children, flows, message flows, and associations. - */ - getState(): { - associations?: any[] | undefined; - messageFlows?: any[] | undefined; - flows?: any; - executionId: string | undefined; - stopped: boolean; - completed: boolean; - status: any; - children: any; - }; + * */ + getState(): ProcessExecutionState; /** * Restore execution state captured by getState. * */ @@ -6896,807 +2476,840 @@ declare module 'bpmn-elements/tasks' { /** * Queue a discard message that propagates to all running children. */ - discard(): number | undefined; + discard(): any; /** * Queue a cancel message that propagates to all running children. */ - cancel(): number | undefined; + cancel(): any; /** * Get child activities in the process scope. */ - getActivities(): any[]; + getActivities(): any; getActivityById(activityId: string): any; /** * Get sequence flows in the process scope. */ - getSequenceFlows(): any[]; + getSequenceFlows(): any; /** * Get associations in the process scope. */ - getAssociations(): any[]; + getAssociations(): any; /** * Resolve a process or child Api for the given message. - * - */ - getApi(message?: ElementBrokerMessage): any; - - _start(): any; - - _activate(): void; - - _deactivate(): void; - - _shakeElements(fromId: any): { - settings: { - skipDiscard: boolean; - }; - sequences: Map; - }; - - _onDelegateEvent(message: any): boolean; - - _onMessageFlowEvent(routingKey: any, message: any): void; - - _onActivityEvent(routingKey: any, message: any): number | void; - - _onChildMessage(routingKey: any, message: any): any; - - _stateChangeMessage(message: any, postponeMessage: any): void; - - _popPostponed(byContent: any): any; - - _onChildCompleted(message: any): any; - - _stopExecution(message: any): any; - - _onDiscard(): any; - - _onCancel(): void; - - _onApiMessage(routingKey: any, message: any): any; - - _delegateApiMessage(routingKey: any, message: any, continueOnConsumed: any): boolean; - - _complete(completionType: any, content: any): any; - - _terminate(message: any): void; - - _getFlowById(flowId: any): any; - - _getAssociationById(associationId: any): any; - - _getMessageFlowById(flowId: any): any; - - _getChildById(childId: any): any; - - _getChildApi(message: any): any; - - _onShakeMessage(message: any): void; - - _debug(logMessage: any): void; - - private [K_PARENT]; - - private [K_ELEMENTS]; - - private [K_COMPLETED]; - - private [K_STOPPED]; - - private [K_ACTIVATED]; - - private [K_STATUS]; - - private [K_TRACKER]; - - private [K_MESSAGE_HANDLERS]; - - private [K_EXECUTE_MESSAGE]; - - private [K_ACTIVITY_Q]; + * */ + getApi(message?: ElementBrokerMessage): IApi; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; } - const K_PARENT: unique symbol; - const K_ELEMENTS: unique symbol; - const K_TRACKER: unique symbol; - const K_ACTIVITY_Q: unique symbol; - type signalMessage = { - /** - * Optional signal id - * - Activity id - * - Signal-, Message-, Escalation id, etc - */ - id?: string; /** - * Optional execution id - * e.g. excutionId of a parallel multi instance user task - */ - executionId?: string; - /** Any other input that will be added to completed activity output */ - [x: string]: any; - }; - - interface ElementMessageContent { - id?: string; - type?: string; - executionId?: string; - parent?: ElementParent; - [x: string]: any; - } - - interface ElementBrokerMessage extends MessageEnvelope { - content: ElementMessageContent; - } - - interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; - } - - // --- Element abstract bases --------------------------------------------------- - - class ElementBase { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - get behaviour(): SerializableElement; - get broker(): Broker; - get environment(): Environment; - get context(): ContextInstance; - get logger(): ILogger; - } - - // --- Activity behaviour & extensions ------------------------------------------ - - interface IActivityBehaviour { - id: string; - type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; - execute(executeMessage: ElementBrokerMessage): void; - } - - type Extension = (activity: any, context: any) => IExtension; - interface IExtension { - activate(message: ElementBrokerMessage): void; - deactivate(message: ElementBrokerMessage): void; - } + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; + /** + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. + * */ + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; + } + class Scripts { + getScript(): void; + register(): void; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } - interface IExpressions { - resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; - } + export {}; +} - // --- Environment -------------------------------------------------------------- +declare module 'bpmn-elements/flows' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; + import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - interface EnvironmentSettings { - /** true returns dummy service function for service task if not found */ - enableDummyService?: boolean; - /** true forces activity runs to go forward in steps, defaults to false */ - step?: boolean; - /** strict mode, see documentation, defaults to false */ - strict?: boolean; - /** positive integer to control parallel loop batch size, defaults to 50 */ - batchSize?: number; - /** - * disable tracking state between recover and resume - * true will only return state for elements that are actually running - * Defaults to falsy - */ - disableTrackState?: boolean; /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; - [x: string]: any; - } - - interface EnvironmentOptions { - settings?: EnvironmentSettings; - variables?: Record; - services?: Record; - Logger?: LoggerFactory; - timers?: ITimers; - scripts?: IScripts; - extensions?: Record; + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + export class Association { + /** + * Association connecting a source and target activity. Used to drive compensation — + * activities marked `isForCompensation` subscribe to inbound association events. + * */ + constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isAssociation: boolean; + environment: Environment; + logger: ILogger; + broker: import("smqp").Broker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + get counters(): { + take: number; + discard: number; + }; + /** + * Take the association and publish association.take. + * + */ + take(content?: Record): boolean; + /** + * Discard the association and publish association.discard. + * + */ + discard(content?: Record): boolean; + /** + * Snapshot association state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): AssociationState | undefined; + /** + * Restore association state captured by getState. + * */ + recover(state: AssociationState): void; + /** + * Resolve an association-scoped Api wrapper. + * */ + getApi(message?: ElementBrokerMessage): IApi; + /** + * Stop the association's broker. + */ + stop(): void; + } /** - * optional override expressions handler - */ - expressions?: IExpressions; - } - - // --- Filter / callback shapes ------------------------------------------------- - - type startActivityFilterOptions = { - /** Event definition id, i.e. Message, Signal, Error, etc */ - referenceId?: string; - /** Event definition type, i.e. message, signal, error, etc */ - referenceType?: string; - }; - - type filterPostponed = (elementApi: any) => boolean; - - // --- State snapshots ---------------------------------------------------------- - - interface ElementState { - id: string; - type: string; - broker?: BrokerState; - [x: string]: any; - } - - interface EnvironmentState { - settings: EnvironmentSettings; - variables: Record; - output: Record; - } - - type completedCounters = { completed: number; discarded: number }; - - interface ActivityExecutionState { - completed: boolean; - [x: string]: any; - } - - interface ActivityState extends ElementState { - status?: string; - executionId: string; - stopped: boolean; - counters: { taken: number; discarded: number }; - execution?: ActivityExecutionState; - } - - interface SequenceFlowState extends ElementState { - counters: { take: number; discard: number; looped: number }; - } - - interface MessageFlowState extends ElementState { - counters: { messages: number }; - } - - interface AssociationState extends ElementState { - counters: { take: number; discard: number }; - } - - interface ProcessExecutionState { - executionId: string; - stopped: boolean; - completed: boolean; - status: string; - children: ActivityState[]; - flows?: SequenceFlowState[]; - messageFlows?: MessageFlowState[]; - associations?: AssociationState[]; - } - - interface ProcessState extends ElementState { - status: string; - stopped: boolean; - executionId?: string; - counters: completedCounters; - environment: EnvironmentState; - execution?: ProcessExecutionState; - } - - // --- Logging ------------------------------------------------------------------ - - type LoggerFactory = (scope: string) => ILogger; - - interface ILogger { - debug(...args: any[]): void; - error(...args: any[]): void; - warn(...args: any[]): void; - [x: string]: any; - } - - // --- Timers ------------------------------------------------------------------- - - type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; - type wrappedClearTimeout = (ref: any) => void; - - interface Timer { - /** The function to call when the timer elapses */ - readonly callback: CallableFunction; - /** The number of milliseconds to wait before calling the callback */ - readonly delay: number; - /** Optional arguments to pass when the callback is called */ - readonly args?: any[]; - /** Timer owner if any */ - readonly owner?: any; - /** Timer Id */ - readonly timerId: string; - /** Timeout, return from setTimeout */ - readonly timerRef: any; - [x: string]: any; - } - - interface RegisteredTimer { - owner?: any; - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - } - - interface ITimers { - get setTimeout(): wrappedSetTimeout; - get clearTimeout(): wrappedClearTimeout; - register(owner?: any): RegisteredTimer; - [x: string]: any; - } - - // --- Scripts ------------------------------------------------------------------ - - interface IScripts { - register(activity: any): Script | undefined; - getScript(language: string, identifier: { id: string; [x: string]: any }): Script; - } - - interface Script { - execute(executionContext: any, callback: CallableFunction): void; - } - - /** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + export class MessageFlow { + /** + * Message flow connecting a source activity (or process) to a target. Subscribes to the + * source's `end` event and publishes `message.outbound` whenever the source completes, + * carrying any message payload through to the target. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + source: any; + target: any; + behaviour: Record; + environment: Environment; + context: ContextInstance; + broker: import("smqp").Broker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + emit: (eventName: string, content?: Record, props?: any) => void; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + logger: ILogger; + get counters(): { + messages: number; + }; + /** + * Snapshot message-flow state. Returns undefined when broker has no state and + * `disableTrackState` is set. + * */ + getState(): MessageFlowState | undefined; + /** + * Restore message-flow state captured by getState. + * */ + recover(state: MessageFlowState): void; + /** + * Resolve a message-scoped Api wrapper. + * */ + getApi(message?: ElementBrokerMessage): IApi; + /** + * Subscribe to the source element's message and end events to bridge the message across. + */ + activate(): void; + /** + * Cancel the source element subscriptions added by activate. + */ + deactivate(): void; + } /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. - * - */ - class Environment { + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + export class SequenceFlow { /** - * Holds global execution config: variables, injected services, timers, scripts engine, - * expressions, Logger factory, and settings such as `batchSize`. Cloned and merged per Definition. + * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped + * events; activities subscribe to drive their inbound queue. + * */ + constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + id: string | undefined; + type: string; + name: any; + parent: any; + behaviour: Record; + sourceId: any; + targetId: any; + isDefault: any; + isSequenceFlow: boolean; + environment: Environment; + logger: ILogger; + broker: import("smqp").Broker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + emitFatal: (error: Error, content?: Record) => void; + get counters(): { + take: number; + discard: number; + looped: number; + }; + /** + * Take the flow and publish flow.take. * */ - constructor(options?: EnvironmentOptions); - options: {}; - expressions: IExpressions; - extensions: Record | undefined; - output: any; - scripts: IScripts | Scripts; - timers: ITimers | Timers; - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - Logger: LoggerFactory | typeof DummyLogger; + take(content?: Record): boolean; /** - * Snapshot environment state for recover. + * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits + * flow.looped instead when the target id is already in the sequence. + * */ - getState(): { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; + discard(content?: Record): void; /** - * Restore environment state captured by getState. Merges into the existing settings, - * variables, and output rather than replacing them. + * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` + * is set. * */ - recover(state?: EnvironmentState): this; + getState(): SequenceFlowState | undefined; /** - * Clone the environment, optionally overriding options. Services are merged when - * `overrideOptions.services` is supplied. + * Restore flow state captured by getState. + * */ + recover(state: SequenceFlowState): void; + /** + * Resolve a Flow Api wrapper. + * */ + getApi(message?: ElementBrokerMessage): IApi; + /** + * Stop the flow's broker. + */ + stop(): void; + /** + * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop + * when the target was already visited, otherwise flow.shake. + * */ + shake(message: ElementBrokerMessage): any; + /** + * Resolve the flow's condition (script or expression). Returns null when no condition is set. + * Emits a fatal error when the script language is missing or unsupported. + * */ + getCondition(): ISequenceFlowCondition | null; + /** + * Build a flow event message body, optionally merging override content. * */ - clone(overrideOptions?: EnvironmentOptions): any; + createMessage(override?: Record): { + id: string | undefined; + type: string; + name: any; + sourceId: any; + targetId: any; + isSequenceFlow: boolean; + isDefault: any; + parent: any; + }; /** - * Merge variables into the environment. Non-objects are ignored. + * Evaluate the flow's condition for the source activity message. Default flows are always taken. + * @param fromMessage Source activity message + * @param callback Callback with truthy result if flow should be taken + */ + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; + } + /** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + class ProcessExecution { + /** + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. * */ - assignVariables(newVars: Record): void; + constructor(parentActivity: Process | Activity, context: ContextInstance); + id: string | undefined; + type: string; + isSubProcess: any; + isTransaction: any; + broker: import("smqp").Broker; + environment: Environment; + context: ContextInstance; + executionId: string | undefined; /** - * Merge settings into the environment. Non-objects are ignored. + * Activate children and start the process execution. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing + */ + execute(executeMessage: ElementBrokerMessage): true | void; + /** + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. + */ + resume(): void; + /** + * Snapshot execution state including children, flows, message flows, and associations. * */ - assignSettings(newSettings: EnvironmentSettings): this; + getState(): ProcessExecutionState; /** - * Resolve a registered script by language and identifier. + * Restore execution state captured by getState. * */ - getScript(...args: any[]): void | Script; + recover(state?: ProcessExecutionState): this; /** - * Register a script for an activity, delegating to the configured scripts engine. + * Walk activity graph from the given start id, or every start activity when omitted. + * + */ + shake(fromId?: string): any; + /** + * Stop the running process execution via the api. + */ + stop(): void; + /** + * List currently postponed children as Api wrappers. + * + */ + getPostponed(filterFn?: filterPostponed): any[]; + /** + * Queue a discard message that propagates to all running children. + */ + discard(): any; + /** + * Queue a cancel message that propagates to all running children. + */ + cancel(): any; + /** + * Get child activities in the process scope. + */ + getActivities(): any; + + getActivityById(activityId: string): any; + /** + * Get sequence flows in the process scope. + */ + getSequenceFlows(): any; + /** + * Get associations in the process scope. + */ + getAssociations(): any; + /** + * Resolve a process or child Api for the given message. * */ - registerScript(...args: any[]): void | Script; + getApi(message?: ElementBrokerMessage): IApi; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; + /** + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. + * */ + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; + } + class Scripts { + getScript(): void; + register(): void; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + + export {}; +} + +declare module 'bpmn-elements/gateways' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; + import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + + export function EventBasedGateway(activityDef: any, context: any): Activity; + export class EventBasedGatewayBehaviour { + constructor(activity: any, context: any); + id: any; + type: any; + activity: any; + broker: any; + context: any; + execute(executeMessage: any): any; + } + export function ExclusiveGateway(activityDef: any, context: any): Activity; + export class ExclusiveGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute({ content }: { + content: any; + }): void; + } + export function InclusiveGateway(activityDef: any, context: any): Activity; + export class InclusiveGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + broker: any; + execute({ content }: { + content: any; + }): void; + } + export class ParallelGateway { + constructor(activityDef: any, context: any); + id: string | undefined; + } + export class ParallelGatewayBehaviour { + constructor(activity: any); + id: any; + type: any; + activity: any; + broker: any; + inbound: Set; + isConverging: boolean; + get executionId(): any; + execute(executeMessage: any): any; + setup(executeMessage: any): any; + peerMonitor: PeerMonitor | undefined; + } + class PeerMonitor { + constructor(activity: any, peers: any, targets: any); + activity: any; + id: any; + broker: any; + running: Map; + index: number; + discarded: number; + watching: Map; + peers: any; + targets: any; + touched: Set; + inbound: any[]; + get isRunning(): boolean; + execute(executeMessage: any): number; + monitor(peerActivity: any): void; + stop(): void; + } + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { /** - * Lookup a registered service by name. + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. * */ - getServiceByName(serviceName: string): CallableFunction; - /** - * Resolve an expression with the environment as scope, optionally extended by an element message. - * @param message Element message merged onto the resolution scope - * - */ - resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; /** - * Register a service callable by name. + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. * */ - addService(name: string, fn: CallableFunction): void; - - private [K_SERVICES]; - - private [K_VARIABLES]; + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } - function DummyLogger(): { - debug: () => void; - error: () => void; - warn: () => void; - }; - const K_SERVICES: unique symbol; - const K_VARIABLES: unique symbol; /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - class ContextInstance { + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + class ProcessExecution { /** - * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. - * @param owner Process or sub-process activity that owns this context - */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); - id: string; - name: string; + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. + * */ + constructor(parentActivity: Process | Activity, context: ContextInstance); + id: string | undefined; type: string; - sid: string; - definitionContext: import("moddle-context-serializer").SerializableContext; + isSubProcess: any; + isTransaction: any; + broker: import("smqp").Broker; environment: Environment; - extensionsMapper: ExtensionsMapper; - refs: Map>; - get owner(): Activity | Process | undefined; + context: ContextInstance; + executionId: string | undefined; /** - * Get or create the activity instance for the given id. - * */ - getActivityById(activityId: string): any; + * Activate children and start the process execution. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing + */ + execute(executeMessage: ElementBrokerMessage): true | void; /** - * Return the cached activity instance, instantiating it the first time it is referenced. - * */ - upsertActivity(activityDef: import("moddle-context-serializer").SerializableElement): any; + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. + */ + resume(): void; /** - * Get or create the sequence flow instance for the given id. + * Snapshot execution state including children, flows, message flows, and associations. * */ - getSequenceFlowById(sequenceFlowId: string): any; - - getInboundSequenceFlows(activityId: string): any[]; - - getOutboundSequenceFlows(activityId: string): any[]; - - getInboundAssociations(activityId: string): any[]; - - getOutboundAssociations(activityId: string): any[]; + getState(): ProcessExecutionState; /** - * Get every activity in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id - */ - getActivities(scopeId?: string): any[]; + * Restore execution state captured by getState. + * */ + recover(state?: ProcessExecutionState): this; /** - * Get every sequence flow in the definition, optionally narrowed to a parent scope. - * @param scopeId Process or sub-process id + * Walk activity graph from the given start id, or every start activity when omitted. + * */ - getSequenceFlows(scopeId?: string): any[]; - /** - * Return the cached sequence flow, instantiating it the first time it is referenced. - * */ - upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + shake(fromId?: string): any; /** - * @param scopeId Process or sub-process id + * Stop the running process execution via the api. */ - getAssociations(scopeId?: string): any[]; - - upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + stop(): void; /** - * Create a new context that shares the parsed definition but optionally swaps environment and owner. + * List currently postponed children as Api wrappers. * */ - clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; - /** - * Get or create the process instance for the given id. Each process gets its own cloned environment. - * */ - getProcessById(processId: string): any; + getPostponed(filterFn?: filterPostponed): any[]; /** - * Build a fresh, uncached process instance for the given id. Used by call activities. - * */ - getNewProcessById(processId: string): any; + * Queue a discard message that propagates to all running children. + */ + discard(): any; /** - * Get every process in the definition. + * Queue a cancel message that propagates to all running children. */ - getProcesses(): any[]; + cancel(): any; /** - * Get processes flagged executable in the definition. + * Get child activities in the process scope. */ - getExecutableProcesses(): any[]; + getActivities(): any; + + getActivityById(activityId: string): any; /** - * Get message flows that originate from the given process id. - * @param sourceId Source process id + * Get sequence flows in the process scope. */ - getMessageFlows(sourceId: string): any[]; + getSequenceFlows(): any; /** - * Get or create a data object instance for the given reference id. - * */ - getDataObjectById(referenceId: string): any; + * Get associations in the process scope. + */ + getAssociations(): any; /** - * Get or create a data store instance for the given reference id. + * Resolve a process or child Api for the given message. * */ - getDataStoreById(referenceId: string): any; - /** - * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. - * @param scopeId Process or sub-process id - */ - getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): any[]; + getApi(message?: ElementBrokerMessage): IApi; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } + class Scripts { + getScript(): void; + register(): void; + } + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; + } + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; + } + + export {}; +} + +declare module 'bpmn-elements/tasks' { + import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; + import type { SerializableElement } from 'moddle-context-serializer'; + import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + + /** + * Create call activity + * @returns Call activity + */ + export function CallActivity(activityDef: import("moddle-context-serializer").MappedActivity, context: ContextInstance): Activity; + export class CallActivityBehaviour { + constructor(activity: any); + id: any; + type: any; + calledElement: any; + loopCharacteristics: any; + activity: any; + broker: any; + environment: any; + execute(executeMessage: any): any; + } + export function ReceiveTask(activityDef: any, context: any): Activity; + export class ReceiveTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + reference: any; + loopCharacteristics: any; + activity: any; + broker: any; + execute(executeMessage: any): any; + } + export function ScriptTask(activityDef: any, context: any): Activity; + export class ScriptTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + scriptFormat: any; + loopCharacteristics: any; + activity: any; + environment: any; + execute(executeMessage: any): any; + } + export function ServiceTask(activityDef: any, context: any): Activity; + export class ServiceTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + environment: any; + broker: any; + execute(executeMessage: any): any; + service: any; + getService(message: any): any; + } + export function SignalTask(activityDef: any, context: any): Activity; + export class SignalTaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + broker: any; + execute(executeMessage: any): any; + } + export function SubProcess(activityDef: any, context: any): Activity; + export class SubProcessBehaviour { + constructor(activity: any, context: any); + id: any; + type: any; + loopCharacteristics: any; + activity: any; + context: any; + environment: any; + broker: any; + executionId: any; + get execution(): any; + get executions(): any[]; + execute(executeMessage: any): any; + getState(): any; + recover(state: any): this | undefined; + getPostponed(): any[]; + getApi(apiMessage: any): any; + } + export function Task(activityDef: any, context: any): Activity; + export class TaskBehaviour { + constructor(activity: any); + id: any; + type: any; + loopCharacteristics: any; + broker: any; + execute(executeMessage: any): any; + } + export function Transaction(activityDef: any, context: any): Activity; + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { /** - * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. - * Returns undefined when the activity has no extensions to attach. + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. * */ - loadExtensions(activity: ElementBase): Extensions | undefined; + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; /** - * Resolve the parent process or sub-process activity that owns the given activity. + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. * */ - getActivityParentById(activityId: string): any; - - private [K_OWNER]; + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } - class ExtensionsMapper { - constructor(context: any); - context: any; - get(activity: any): Extensions; - - _getExtensions(): any[]; + class RegisteredTimers { + constructor(timersApi: any, owner: any); + owner: any; + setTimeout: any; + clearTimeout: any; } - class Extensions { - constructor(activity: any, context: any, extensions: any); - extensions: any[]; - get count(): number; - activate(message: any): void; - deactivate(message: any): void; - - private [K_ACTIVATED]; + class Timer_1 { + constructor(owner: any, timerId: any, callback: any, delay: any, args: any); + callback: any; + delay: any; + args: any; + owner: any; + timerId: any; + expireAt: Date; + timerRef: any; } - const K_OWNER: unique symbol; /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. * */ - class Process { + class ProcessExecution { /** - * Owns one ``. Wraps the structural definition and orchestrates flow traversal, - * joins, and parallel activation through ProcessExecution. + * Drives the execution of a single process or sub-process: activates children, routes activity + * events, and rolls completion up to the owning Process or sub-process Activity. * */ - constructor(processDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + constructor(parentActivity: Process | Activity, context: ContextInstance); id: string | undefined; type: string; - name: any; - parent: any; - behaviour: Record; - isExecutable: any; + isSubProcess: any; + isTransaction: any; + broker: import("smqp").Broker; environment: Environment; context: ContextInstance; - broker: import("smqp").Broker; - on: any; - once: any; - waitFor: any; - logger: ILogger | { - debug: () => void; - error: () => void; - warn: () => void; - }; - /** - * Allocate an executionId and emit init event without starting the run. - * @param useAsExecutionId Override for the generated execution id - */ - init(useAsExecutionId?: string): void; + executionId: string | undefined; /** - * Start running the process by publishing run.enter, run.start, and run.execute. - * @param runContent Optional content merged into the run message - * @throws {Error} when the process is already running + * Activate children and start the process execution. Resumes if the message is redelivered. + * @throws {Error} when message or executionId is missing */ - run(runContent?: Record): void; + execute(executeMessage: ElementBrokerMessage): true | void; /** - * Resume after recover by republishing the last run message. - * @throws {Error} when called on a running process + * Resume after recover. Reshakes elements when there are converging gateways or multiple + * start activities, then resumes any postponed children. */ - resume(): this; + resume(): void; /** - * Snapshot process state for recover. - */ - getState(): { - id: string | undefined; - type: string; - executionId: any; - environment: { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - status: any; - stopped: any; - counters: any; - broker: { - exchanges: { - bindings?: { - id: string; - options: { - priority: number; - }; - queueName: string; - pattern: string; - }[] | undefined; - deliveryQueue?: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - } | undefined; - name: string; - type: import("smqp").exchangeType; - options: { - [x: string]: any; - durable?: boolean; - autoDelete?: boolean; - }; - }[] | undefined; - queues: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - }[] | undefined; - } | undefined; - execution: any; - }; + * Snapshot execution state including children, flows, message flows, and associations. + * */ + getState(): ProcessExecutionState; /** - * Restore process state captured by getState. - * @throws {Error} when called on a running process - */ - recover(state?: ProcessState): this; + * Restore execution state captured by getState. + * */ + recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. * */ - shake(startId?: string): any; + shake(fromId?: string): any; /** - * Stop the process if running. + * Stop the running process execution via the api. */ stop(): void; /** - * Resolve a Process Api wrapper, preferring the running execution if any. + * List currently postponed children as Api wrappers. * */ - getApi(message?: ElementBrokerMessage): any; + getPostponed(filterFn?: filterPostponed): any[]; /** - * Send a delegated signal to the running process. - * + * Queue a discard message that propagates to all running children. */ - signal(message?: signalMessage): any; + discard(): any; /** - * Cancel a running activity inside the process by delegated api message. - * + * Queue a cancel message that propagates to all running children. */ - cancelActivity(message?: signalMessage): any; - - _activateRunConsumers(): void; - - _deactivateRunConsumers(): void; - - _onRunMessage(routingKey: any, message: any): any; - - _onResumeMessage(message: any): any; - - _onExecutionMessage(routingKey: any, message: any): void; - - _publishEvent(state: any, content: any): void; - /** - * Deliver a message to a target activity or start activity that references it. - * Starts the process if a target is found and the process is idle. - * */ - sendMessage(message: ElementBrokerMessage): void; - - getActivityById(childId: string): any; + cancel(): any; /** - * Get every activity in the process scope. + * Get child activities in the process scope. */ getActivities(): any; - /** - * Get start activities, optionally filtered by referenced event definition. - * - */ - getStartActivities(filterOptions?: startActivityFilterOptions): any[]; + + getActivityById(activityId: string): any; /** * Get sequence flows in the process scope. */ getSequenceFlows(): any; - - getLaneById(laneId: string): any; /** - * List currently postponed activities as Api wrappers. - * + * Get associations in the process scope. */ - getPostponed(...args: any[]): any; - - _onApiMessage(routingKey: any, message: any): void; - - _onStop(): void; - - _createMessage(override: any): any; - - _debug(msg: any): void; - - private [K_COUNTERS]; - - private [K_CONSUMING]; - - private [K_EXECUTION]; - - private [K_STATUS]; - - private [K_STOPPED]; - - private [K_MESSAGE_HANDLERS]; - - private [K_LANES]; - - private [K_EXTENSIONS]; - - private [K_STATE_MESSAGE]; - - private [K_EXECUTE_MESSAGE]; - } - const K_LANES: unique symbol; - class Timers { - constructor(options: any); - count: number; - options: any; - setTimeout: any; - clearTimeout: any; - get executing(): any[]; - register(owner: any): RegisteredTimers; - _setTimeout(owner: any, callback: any, delay: any, ...args: any[]): Timer_1; - _getReference(owner: any, callback: any, delay: any, args: any): Timer_1; - - private [K_EXECUTING]; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - - private [K_TIMER_API]; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; + getAssociations(): any; + /** + * Resolve a process or child Api for the given message. + * */ + getApi(message?: ElementBrokerMessage): IApi; + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; } - const K_EXECUTING: unique symbol; - const K_TIMER_API: unique symbol; class Scripts { getScript(): void; register(): void; @@ -7704,95 +3317,3 @@ declare module 'bpmn-elements/tasks' { export {}; } - -//# sourceMappingURL=index.d.ts.map -// Augmentations for the dts-buddy-generated bundle in types/index.d.ts. -// These interfaces add the prototype getters defined via Object.defineProperties -// in src/, which TypeScript cannot pick up from constructor functions. -// The build script (scripts/build-types.js) appends this file to types/index.d.ts. - -declare module 'bpmn-elements' { - interface Activity { - get counters(): { taken: number; discarded: number }; - get execution(): import('types').ActivityExecution | undefined; - get executionId(): string | undefined; - get extensions(): import('types').IExtension; - get bpmnIo(): import('types').IExtension | undefined; - get formatter(): any; - get isRunning(): boolean; - get outbound(): import('types').SequenceFlow[]; - get inbound(): import('types').SequenceFlow[]; - get isEnd(): boolean; - get isStart(): boolean; - get isSubProcess(): boolean; - get isTransaction(): boolean; - get isMultiInstance(): boolean; - get isThrowing(): boolean; - get isCatching(): boolean; - get isForCompensation(): boolean; - get isParallelJoin(): boolean; - get triggeredByEvent(): boolean; - get attachedTo(): import('types').Activity | null; - get lane(): import('types').Lane | undefined; - get eventDefinitions(): any[]; - /** Parent element process or sub process reference */ - get parentElement(): import('types').Process | import('types').Activity; - get initialized(): boolean; - } - - interface Process { - get counters(): { completed: number; discarded: number }; - get lanes(): import('types').Lane[] | undefined; - get extensions(): import('types').IExtension | undefined; - get stopped(): boolean; - get isRunning(): boolean; - get executionId(): string | undefined; - get execution(): import('types').ProcessExecution | undefined; - get status(): string | undefined; - get activityStatus(): string; - } - - interface Definition { - get counters(): { completed: number; discarded: number }; - get execution(): import('types').DefinitionExecution | undefined; - get executionId(): string | undefined; - get isRunning(): boolean; - get status(): string | undefined; - get stopped(): boolean; - get activityStatus(): string; - } - - interface Environment { - get variables(): Record; - get services(): Record; - set services(value: Record); - } - - interface ContextInstance { - /** Process or sub-process activity that owns this context */ - get owner(): import('types').Process | import('types').Activity | undefined; - } - - interface ProcessExecution { - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - - interface DefinitionExecution { - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get processes(): import('types').Process[]; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - - interface ActivityExecution { - get completed(): boolean; - } -} diff --git a/types/index.d.ts.map b/types/index.d.ts.map deleted file mode 100644 index c9c46795..00000000 --- a/types/index.d.ts.map +++ /dev/null @@ -1,266 +0,0 @@ -{ - "version": 3, - "file": "index.d.ts", - "names": [ - "Activity", - "K_ACTIVITY_DEF", - "K_FLOWS", - "K_FLAGS", - "K_EXEC", - "K_EVENT_DEFINITIONS", - "K_CONSUMING_RUN_Q", - "Context", - "ContextInstance", - "ExtensionsMapper", - "Extensions", - "K_OWNER", - "Definition", - "Environment", - "DummyLogger", - "K_SERVICES", - "K_VARIABLES", - "Escalation", - "Message", - "Lane", - "K_PROCESS", - "Process", - "K_LANES", - "Properties", - "K_PROPERTIES", - "ServiceImplementation", - "Signal", - "StandardLoopCharacteristics", - "Timers", - "RegisteredTimers", - "K_EXECUTING", - "K_TIMER_API", - "ActivityError", - "RunError", - "CallActivity", - "ReceiveTask", - "ScriptTask", - "ServiceTask", - "SignalTask", - "SubProcess", - "Task", - "Transaction", - "Association", - "MessageFlow", - "K_SOURCE_ELEMENT", - "SequenceFlow", - "signalMessage", - "ElementMessageContent", - "ElementBrokerMessage", - "ElementParent", - "ElementBase", - "ISequenceFlowCondition", - "IActivityBehaviour", - "Extension", - "IExtension", - "IExpressions", - "EnvironmentSettings", - "EnvironmentOptions", - "startActivityFilterOptions", - "runCallback", - "ElementState", - "EnvironmentState", - "completedCounters", - "ActivityExecutionState", - "ActivityState", - "SequenceFlowState", - "MessageFlowState", - "AssociationState", - "ProcessExecutionState", - "ProcessState", - "DefinitionExecutionState", - "DefinitionState", - "LoggerFactory", - "ILogger", - "wrappedSetTimeout", - "wrappedClearTimeout", - "Timer", - "RegisteredTimer", - "ITimers", - "IScripts", - "Script", - "K_ACTIVATED", - "K_COMPLETED", - "K_CONSUMING", - "K_COUNTERS", - "K_EXECUTE_MESSAGE", - "K_EXECUTION", - "K_EXTENSIONS", - "K_MESSAGE_HANDLERS", - "K_MESSAGE_Q", - "K_REFERENCE_ELEMENT", - "K_REFERENCE_INFO", - "K_STATE_MESSAGE", - "K_STATUS", - "K_STOPPED", - "BoundaryEvent", - "EndEvent", - "IntermediateCatchEvent", - "IntermediateThrowEvent", - "StartEvent", - "CancelEventDefinition", - "CompensateEventDefinition", - "K_ASSOCIATIONS", - "K_COMPENSATE_Q", - "ConditionalEventDefinition", - "ErrorEventDefinition", - "EscalationEventDefinition", - "K_REFERENCE", - "LinkEventDefinition", - "MessageEventDefinition", - "SignalEventDefinition", - "TerminateEventDefinition", - "TimerEventDefinition", - "K_TIMER", - "K_TIMER_CONTENT", - "Scripts", - "EventBasedGateway", - "ExclusiveGateway", - "InclusiveGateway", - "ParallelGateway", - "Api", - "ScriptCondition", - "ExpressionCondition", - "makeErrorFromMessage", - "BpmnError", - "BoundaryEventBehaviour", - "K_SHOVELS", - "K_ATTACHED_TAGS", - "K_COMPLETE_CONTENT", - "EndEventBehaviour", - "IntermediateCatchEventBehaviour", - "IntermediateThrowEventBehaviour", - "StartEventBehaviour", - "EventBasedGatewayBehaviour", - "ExclusiveGatewayBehaviour", - "InclusiveGatewayBehaviour", - "ParallelGatewayBehaviour", - "PeerMonitor", - "K_TARGETS", - "CallActivityBehaviour", - "ReceiveTaskBehaviour", - "ScriptTaskBehaviour", - "ServiceTaskBehaviour", - "SignalTaskBehaviour", - "SubProcessBehaviour", - "K_EXECUTIONS", - "K_ON_EXECUTION_COMPLETED", - "TaskBehaviour", - "ProcessExecution", - "K_PARENT", - "K_ELEMENTS", - "K_TRACKER", - "K_ACTIVITY_Q", - "filterPostponed" - ], - "sources": [ - "../src/activity/Activity.js", - "../src/Context.js", - "../src/definition/Definition.js", - "../src/Environment.js", - "../src/activity/Escalation.js", - "../src/activity/Message.js", - "../src/process/Lane.js", - "../src/process/Process.js", - "../src/io/Properties.js", - "../src/tasks/ServiceImplementation.js", - "../src/activity/Signal.js", - "../src/tasks/StandardLoopCharacteristics.js", - "../src/Timers.js", - "../src/error/Errors.js", - "../src/tasks/CallActivity.js", - "../src/tasks/ReceiveTask.js", - "../src/tasks/ScriptTask.js", - "../src/tasks/ServiceTask.js", - "../src/tasks/SignalTask.js", - "../src/tasks/SubProcess.js", - "../src/tasks/Task.js", - "../src/tasks/Transaction.js", - "../src/flows/Association.js", - "../src/flows/MessageFlow.js", - "../src/flows/SequenceFlow.js", - "types.d.ts", - "../src/constants.js", - "../src/events/BoundaryEvent.js", - "../src/events/EndEvent.js", - "../src/events/IntermediateCatchEvent.js", - "../src/events/IntermediateThrowEvent.js", - "../src/events/StartEvent.js", - "../src/eventDefinitions/CancelEventDefinition.js", - "../src/eventDefinitions/CompensateEventDefinition.js", - "../src/eventDefinitions/ConditionalEventDefinition.js", - "../src/eventDefinitions/ErrorEventDefinition.js", - "../src/eventDefinitions/EscalationEventDefinition.js", - "../src/eventDefinitions/LinkEventDefinition.js", - "../src/eventDefinitions/MessageEventDefinition.js", - "../src/eventDefinitions/SignalEventDefinition.js", - "../src/eventDefinitions/TerminateEventDefinition.js", - "../src/eventDefinitions/TimerEventDefinition.js", - "../src/Scripts.js", - "../src/gateways/EventBasedGateway.js", - "../src/gateways/ExclusiveGateway.js", - "../src/gateways/InclusiveGateway.js", - "../src/gateways/ParallelGateway.js", - "../src/Api.js", - "../src/condition.js", - "../src/process/ProcessExecution.js" - ], - "sourcesContent": [ - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null - ], - "mappings": ";;;;;;;;;iBAgCgBA,QAAQA;cAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;;;;;;;;;;;;;;iBCPPC,OAAOA;;;;;UAWPC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCkBGC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCTVC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;iBCLDC,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAVC,OAAOA;;;;;;;;;;;iBCQPC,IAAIA;cAAJA,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARdC,SAASA;;;;;;;;;;;;;;;;;;;;iBC0BCC,OAAOA;cAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;iBCbGC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;OAFpBC,YAAYA;iBCFFC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;iBCDrBC,MAAMA;;;;;;;iBCCNC,2BAA2BA;iBCI3BC,MAAMA;cAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;cCCJC,aAAaA;;;;;;;;;;;;;cAebC,QAAQA;;;iBCbLC,YAAYA;iBCAZC,WAAWA;iBCCXC,UAAUA;iBCDVC,WAAWA;iBCAXC,UAAUA;iBCGVC,UAAUA;iBCJVC,IAAIA;iBCFJC,WAAWA;;;;;iBCWXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OATrBC,gBAAgBA;;;;;iBCONC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCyBRC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;YAiFhBC,sBAAsBA;;;;;;;;;;;;;YAatBC,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;OAS1BC,WAAWA;;;;YAuENC,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;YASZC,wBAAwBA;;;;;;;;YAQxBC,eAAeA;;;;;;;;;;;OAmBpBC,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;YAEdC,KAAKA;;;;;;;;;;;;;;;;YAgBLC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;OCzclBC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OACfC,QAAQA;OACRC,SAASA;iBCHNC,aAAaA;iBCLbC,QAAQA;iBCARC,sBAAsBA;iBCAtBC,sBAAsBA;iBCAtBC,UAAUA;iBCFVC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,cAAcA;OADdC,cAAcA;iBCCJC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,WAAWA;iBCDDC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJ9BC,OAAOA;OADPC,eAAeA;UCLLC,OAAOA;OAAPA,OAAOA;;;;iBCIPC,iBAAiBA;iBCDjBC,gBAAgBA;iBCAhBC,gBAAgBA;iBCOhBC,eAAeA;cAAfA,eAAeA;;;;;;;;;;;UCyCfC,GAAGA;OAAHA,GAAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UC5CHC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;iBnCEnBC,oBAAoBA;cAnCvB3F,aAAaA;;;;;;;;;;;;;cAebC,QAAQA;;;cAOR2F,SAASA;;;;;;;;;;;;;;;;;;;;;iBcdN7B,aAAaA;iBAIb8B,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OANhCC,SAASA;OAFTC,eAAeA;OACfC,kBAAkBA;iBCFRhC,QAAQA;iBAIRiC,iBAAiBA;cAAjBA,iBAAiBA;;;;;;;;;iBCJjBhC,sBAAsBA;iBAItBiC,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;;iBCJ/BhC,sBAAsBA;iBAItBiC,+BAA+BA;cAA/BA,+BAA+BA;;;;;;;;;iBCJ/BhC,UAAUA;iBAIViC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;U/BuBnBpI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BnBV2E,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OACfC,QAAQA;OACRC,SAASA;ODyBFhD,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;UMqBGU,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;iBVGPf,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;iBCIrBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,cAAcA;OADdC,cAAcA;iBCCJC,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCD1BC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGpBC,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAFnCC,WAAWA;iBCDDC,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;iBCCnBC,sBAAsBA;cAAtBA,sBAAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCAtBC,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCHrBC,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;iBCQxBC,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAJ9BC,OAAOA;OADPC,eAAeA;OfLRjC,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAClBC,WAAWA;OACXC,mBAAmBA;OACnBC,gBAAgBA;OAChBC,eAAeA;OACfC,QAAQA;OACRC,SAASA;ODyBFhD,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;UuBlcfyC,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;UA4BfC,mBAAmBA;OAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;UhDHnB1H,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;UOOPe,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;;;;;;UJJGT,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;UWAGiB,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;iBpBYPzE,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCGXC,WAAWA;cAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OATrBC,gBAAgBA;;;;;iBCONC,YAAYA;cAAZA,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCyBRC,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;YAiFhBC,sBAAsBA;;;;;;;;;;;;;YAatBC,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;;;;U4C8CDwG,GAAGA;OAAHA,GAAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OrBnDNvC,WAAWA;OAEXE,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OACfC,QAAQA;OACRC,SAASA;;;;;UzBUNtF,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;;;UD2BGX,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;;;;;UOOPe,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;iBCIPC,iBAAiBA;iBAIjBiB,0BAA0BA;cAA1BA,0BAA0BA;;;;;;;;;;;;;;;;iBCL1BhB,gBAAgBA;iBAIhBiB,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCJzBhB,gBAAgBA;iBAIhBiB,yBAAyBA;cAAzBA,yBAAyBA;;;;;;;;;iBCGzBhB,eAAeA;cAAfA,eAAeA;;;;iBAoCfiB,wBAAwBA;cAAxBA,wBAAwBA;;;;;;;;;;;;;;;;;;;;UAqI/BC,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;U9CnJJzI,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BnBV2E,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAIlBI,eAAeA;OACfC,QAAQA;OACRC,SAASA;OACT4C,SAASA;ODwBF5F,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;;;YAgFrBE,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;UMqBGU,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA;;;;;;;;;;;iB5BIPjF,YAAYA;iBAIZyG,qBAAqBA;cAArBA,qBAAqBA;;;;;;;;;;;;;;iBCJrBxG,WAAWA;iBASXyG,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;iBCRpBxG,UAAUA;iBAIVyG,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;iBCLnBxG,WAAWA;iBAIXyG,oBAAoBA;cAApBA,oBAAoBA;;;;;;;;;;;;;iBCJpBxG,UAAUA;iBAIVyG,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;iBCDnBxG,UAAUA;iBAqBVyG,mBAAmBA;cAAnBA,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;;;OAxB7BC,YAAYA;OACZC,wBAAwBA;iBCFd1G,IAAIA;iBAIJ2G,aAAaA;cAAbA,aAAaA;;;;;;;;iBCNb1G,WAAWA;;;;;;;UrB+BXzC,QAAQA;OAARA,QAAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAdlBC,cAAcA;OAKdC,OAAOA;OADPC,OAAOA;OADPC,MAAMA;OADNC,mBAAmBA;OADnBC,iBAAiBA;O0BnBV2E,WAAWA;OACXC,WAAWA;OACXC,WAAWA;OACXC,UAAUA;OACVC,iBAAiBA;OACjBC,WAAWA;OACXC,YAAYA;OACZC,kBAAkBA;OAElBE,mBAAmBA;OAEnBE,eAAeA;OACfC,QAAQA;OACRC,SAASA;;;;;UuBINsD,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAT1BC,QAAQA;OADRC,UAAUA;OAEVC,SAASA;OAHTC,YAAYA;OxBgCE1G,aAAaA;;;;;;;;;;;;;;;;YAgBRC,qBAAqBA;;;;;;;;YAQrBC,oBAAoBA;;;;YAIpBC,aAAaA;;;;;;;;;QASRC,WAAWA;;;;;;;;;;;;;;YA8FhBE,kBAAkBA;;;;;;;;;OAYvBC,SAASA;YACJC,UAAUA;;;;;YAKVC,YAAYA;;;;;;YAMZC,mBAAmBA;;;;;;;;;;;;;;;;;;;;;;;YAuBnBC,kBAAkBA;;;;;;;;;;;;;;;;OAgBvBC,0BAA0BA;;;;;;;OAO1B+F,eAAeA;;;;YAyEV7F,YAAYA;;;;;;;YAOZC,gBAAgBA;;;;;;OAMrBC,iBAAiBA;;YAEZC,sBAAsBA;;;;;YAKtBC,aAAaA;;;;;;;;YAQbC,iBAAiBA;;;;YAIjBC,gBAAgBA;;;;YAIhBC,gBAAgBA;;;;YAIhBC,qBAAqBA;;;;;;;;;;;YAWrBC,YAAYA;;;;;;;;;;;OAoCjBG,aAAaA;;YAERC,OAAOA;;;;;;;;;OASZC,iBAAiBA;OACjBC,mBAAmBA;;Yb9U9BC,KAAKA;;;;;;;;;;;;;;;;YagWWC,eAAeA;;;;;;YAMfC,OAAOA;;;;;;;;;YAiBPC,QAAQA;;;;;YAKRC,MAAMA;;;;;;;;;;;;;;;UtB3bfnE,WAAWA;OAAXA,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqMlBC,WAAWA;;;;;OA/MdC,UAAUA;OACVC,WAAWA;;;;;UFkBDR,eAAeA;OAAfA,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAkUtBC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;UAehBC,UAAUA;OAAVA,UAAUA;;;;;;;;;OAnWbC,OAAOA;;;;;UMqBGU,OAAOA;OAAPA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OARjBC,OAAOA;UKbGM,MAAMA;OAANA,MAAMA;;;;;;;;;;;;;UAsDbC,gBAAgBA;OAAhBA,gBAAgBA;;;;;;;;;;;;;;;;;;;OA3DnBC,WAAWA;OACXC,WAAWA;U8BDDoF,OAAOA;OAAPA,OAAOA", - "ignoreList": [] -} \ No newline at end of file diff --git a/types/types.d.ts b/types/interfaces.d.ts similarity index 61% rename from types/types.d.ts rename to types/interfaces.d.ts index b4068946..451a1061 100644 --- a/types/types.d.ts +++ b/types/interfaces.d.ts @@ -1,42 +1,109 @@ -import { Broker, BrokerState, Consumer, MessageEnvelope, MessageFields, MessageProperties } from 'smqp'; -import { SerializableContext, SerializableElement } from 'moddle-context-serializer'; - -// Class re-exports — types follow the implementation in src/. -export { Activity } from '../src/activity/Activity.js'; -export { ActivityExecution } from '../src/activity/ActivityExecution.js'; -export { Process } from '../src/process/Process.js'; -export { ProcessExecution } from '../src/process/ProcessExecution.js'; -export { Lane } from '../src/process/Lane.js'; -export { Definition } from '../src/definition/Definition.js'; -export { DefinitionExecution } from '../src/definition/DefinitionExecution.js'; -export { Environment } from '../src/Environment.js'; -export { Context, ContextInstance } from '../src/Context.js'; -export { SequenceFlow } from '../src/flows/SequenceFlow.js'; -export { MessageFlow } from '../src/flows/MessageFlow.js'; -export { Association } from '../src/flows/Association.js'; -export { Timers } from '../src/Timers.js'; -export { Formatter as MessageFormatter } from '../src/MessageFormatter.js'; -export { ActivityError, BpmnError, RunError } from '../src/error/Errors.js'; -export { TimerEventDefinition } from '../src/eventDefinitions/TimerEventDefinition.js'; -export { ConditionalEventDefinition } from '../src/eventDefinitions/ConditionalEventDefinition.js'; - -// Re-export of supporting smqp types (kept here so JSDoc can address them via `import('types')`). -export { Consumer, MessageFields, MessageProperties }; - -import { Activity } from '../src/activity/Activity.js'; -import { Process } from '../src/process/Process.js'; -import { Definition } from '../src/definition/Definition.js'; -import { Environment } from '../src/Environment.js'; -import { ContextInstance } from '../src/Context.js'; -import { ActivityError } from '../src/error/Errors.js'; +import type { Broker, BrokerState, Consumer, MessageEnvelope, MessageFields, MessageProperties } from 'smqp'; +import type { SerializableContext, SerializableElement } from 'moddle-context-serializer'; +import type { Activity } from '../src/activity/Activity.js'; +import type { ActivityExecution } from '../src/activity/ActivityExecution.js'; +import type { ContextInstance } from '../src/Context.js'; +import type { Definition } from '../src/definition/Definition.js'; +import type { DefinitionExecution } from '../src/definition/DefinitionExecution.js'; +import type { Environment } from '../src/Environment.js'; +import type { Lane } from '../src/process/Lane.js'; +import type { Process } from '../src/process/Process.js'; +import type { ProcessExecution } from '../src/process/ProcessExecution.js'; +import type { SequenceFlow } from '../src/flows/SequenceFlow.js'; +import type { Formatter } from '../src/MessageFormatter.js'; +import type { ActivityError } from '../src/error/Errors.js'; + +export type { Activity, ActivityExecution, ContextInstance, Definition, Environment, Lane, Process, SequenceFlow }; +export type { Consumer, MessageFields, MessageProperties, SerializableContext, SerializableElement }; + +// `Object.defineProperties(.prototype, …)` is opaque to tsc inference, +// so we declare the getters here as augmentations and TS merges them with each +// class at emit time. +declare module '../src/activity/Activity.js' { + interface Activity { + get counters(): { taken: number; discarded: number }; + get execution(): ActivityExecution | undefined; + get executionId(): string | undefined; + get extensions(): IExtension; + get bpmnIo(): IExtension | undefined; + get formatter(): Formatter; + get isRunning(): boolean; + get outbound(): SequenceFlow[]; + get inbound(): SequenceFlow[]; + get isEnd(): boolean; + get isStart(): boolean; + get isSubProcess(): boolean; + get isTransaction(): boolean; + get isMultiInstance(): boolean; + get isThrowing(): boolean; + get isCatching(): boolean; + get isForCompensation(): boolean; + get isParallelJoin(): boolean; + get triggeredByEvent(): boolean; + get attachedTo(): Activity | null; + get lane(): Lane | undefined; + get eventDefinitions(): any[]; + get parentElement(): Activity | Process; + get initialized(): boolean; + } +} + +declare module '../src/definition/Definition.js' { + interface Definition { + get counters(): { completed: number; discarded: number }; + get execution(): DefinitionExecution | undefined; + get executionId(): string | undefined; + get isRunning(): boolean; + get status(): string | undefined; + get stopped(): boolean; + get activityStatus(): string; + } +} + +declare module '../src/process/Process.js' { + interface Process { + get counters(): { completed: number; discarded: number }; + get lanes(): Lane[] | undefined; + get extensions(): IExtension | undefined; + get stopped(): boolean; + get isRunning(): boolean; + get executionId(): string | undefined; + get execution(): ProcessExecution | undefined; + get status(): string | undefined; + get activityStatus(): string; + } +} + +declare module '../src/process/ProcessExecution.js' { + interface ProcessExecution { + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } +} + +declare module '../src/definition/DefinitionExecution.js' { + interface DefinitionExecution { + get stopped(): boolean; + get completed(): boolean; + get status(): string; + get processes(): Process[]; + get postponedCount(): number; + get isRunning(): boolean; + get activityStatus(): string; + } +} // --- Broker / message contracts ----------------------------------------------- -export declare interface ElementBroker extends Broker { +export interface ElementBroker extends Broker { get owner(): T; } -export declare type signalMessage = { +export type signalMessage = { /** * Optional signal id * - Activity id @@ -52,7 +119,7 @@ export declare type signalMessage = { [x: string]: any; }; -export declare interface ElementMessageContent { +export interface ElementMessageContent { id?: string; type?: string; executionId?: string; @@ -60,11 +127,11 @@ export declare interface ElementMessageContent { [x: string]: any; } -export declare interface ElementBrokerMessage extends MessageEnvelope { +export interface ElementBrokerMessage extends MessageEnvelope { content: ElementMessageContent; } -export declare interface ElementParent { +export interface ElementParent { get id(): string; get type(): string; get executionId(): string; @@ -73,7 +140,7 @@ export declare interface ElementParent { // --- Element abstract bases --------------------------------------------------- -export declare abstract class ElementBase { +export abstract class ElementBase { get id(): string; get type(): string; get name(): string; @@ -81,21 +148,22 @@ export declare abstract class ElementBase { get behaviour(): SerializableElement; get broker(): Broker; get environment(): Environment; + /** Per-execution context registry (see `Context`/`ContextInstance` from src). */ get context(): ContextInstance; get logger(): ILogger; } -export declare abstract class Element extends ElementBase { +export abstract class Element extends ElementBase { get broker(): ElementBroker; stop(): void; resume(): void; - getApi(message?: ElementBrokerMessage): Api; + getApi(message?: ElementBrokerMessage): IApi; on(eventName: string, callback: CallableFunction, options?: any): any; once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; + waitFor(eventName: string, options?: any): Promise>; } -export declare abstract class MessageElement { +export abstract class MessageElement { get id(): string; get type(): string; get name(): string; @@ -112,7 +180,7 @@ export declare abstract class MessageElement { // --- Event definitions -------------------------------------------------------- // Common ancestor for the typed event definitions; concrete types live in src/eventDefinitions. -export declare class EventDefinition { +export class EventDefinition { constructor(activity: Activity, eventDefinitionElement: SerializableElement, context?: ContextInstance, index?: number); get id(): string; get type(): string; @@ -130,13 +198,13 @@ export declare class EventDefinition { execute(executeMessage: ElementBrokerMessage): void; } -export declare const enum TimerType { +export const enum TimerType { TimeCycle = 'timeCycle', TimeDuration = 'timeDuration', TimeDate = 'timeDate', } -export declare type parsedTimer = { +export type parsedTimer = { /** Expires at date time */ expireAt?: Date; /** Repeat number of times */ @@ -147,14 +215,14 @@ export declare type parsedTimer = { // --- Conditions --------------------------------------------------------------- -export declare interface ICondition { +export interface ICondition { /** Condition type */ get type(): string; [x: string]: any; execute(message: ElementBrokerMessage, callback: CallableFunction): void; } -export declare interface ISequenceFlowCondition { +export interface ISequenceFlowCondition { /** Condition type, e.g. script or expression */ get type(): string; /** @@ -167,31 +235,31 @@ export declare interface ISequenceFlowCondition { // --- Activity behaviour & extensions ------------------------------------------ -export declare interface IActivityBehaviour { +export interface IActivityBehaviour { id: string; type: string; - activity: any; - environment: any; - new (activity: any, context: any): IActivityBehaviour; + activity: Activity; + environment: Environment; + new (activity: Activity, context: ContextInstance): IActivityBehaviour; execute(executeMessage: ElementBrokerMessage): void; } // Custom activity behaviour factory signature. -export declare function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; +export function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; -export declare type Extension = (activity: any, context: any) => IExtension; -export declare interface IExtension { +export type Extension = (activity: any, context: any) => IExtension; +export interface IExtension { activate(message: ElementBrokerMessage): void; deactivate(message: ElementBrokerMessage): void; } -export declare interface IExpressions { +export interface IExpressions { resolveExpression(templatedString: string, context?: any, expressionFnContext?: any): any; } // --- Environment -------------------------------------------------------------- -export declare interface EnvironmentSettings { +export interface EnvironmentSettings { /** true returns dummy service function for service task if not found */ enableDummyService?: boolean; /** true forces activity runs to go forward in steps, defaults to false */ @@ -214,7 +282,7 @@ export declare interface EnvironmentSettings { [x: string]: any; } -export declare interface EnvironmentOptions { +export interface EnvironmentOptions { settings?: EnvironmentSettings; variables?: Record; services?: Record; @@ -230,20 +298,20 @@ export declare interface EnvironmentOptions { // --- Filter / callback shapes ------------------------------------------------- -export declare type startActivityFilterOptions = { +export type startActivityFilterOptions = { /** Event definition id, i.e. Message, Signal, Error, etc */ referenceId?: string; /** Event definition type, i.e. message, signal, error, etc */ referenceType?: string; }; -export declare type filterPostponed = (elementApi: any) => boolean; +export type filterPostponed = (elementApi: any) => boolean; -export declare type runCallback = (err: Error, definitionApi: any) => void; +export type runCallback = (err: Error, definitionApi: any) => void; // --- Run-status enums --------------------------------------------------------- -export declare const enum DefinitionRunStatus { +export const enum DefinitionRunStatus { Entered = 'entered', Start = 'start', Executing = 'executing', @@ -251,7 +319,7 @@ export declare const enum DefinitionRunStatus { Discarded = 'discarded', } -export declare const enum ProcessRunStatus { +export const enum ProcessRunStatus { Entered = 'entered', Start = 'start', Executing = 'executing', @@ -264,7 +332,7 @@ export declare const enum ProcessRunStatus { * Activity status * Can be used to decide when to save states, Timer and Wait is recommended. */ -export declare const enum ActivityStatus { +export const enum ActivityStatus { /** Idle, not running anything */ Idle = 'idle', /** @@ -287,7 +355,7 @@ export declare const enum ActivityStatus { /** * Activity run status */ -export declare const enum ActivityRunStatus { +export const enum ActivityRunStatus { /** Run entered, triggered by taken inbound flow */ Entered = 'entered', /** Run started */ @@ -310,27 +378,27 @@ export declare const enum ActivityRunStatus { // --- State snapshots ---------------------------------------------------------- -export declare interface ElementState { +export interface ElementState { id: string; type: string; broker?: BrokerState; [x: string]: any; } -export declare interface EnvironmentState { +export interface EnvironmentState { settings: EnvironmentSettings; variables: Record; output: Record; } -export declare type completedCounters = { completed: number; discarded: number }; +export type completedCounters = { completed: number; discarded: number }; -export declare interface ActivityExecutionState { +export interface ActivityExecutionState { completed: boolean; [x: string]: any; } -export declare interface ActivityState extends ElementState { +export interface ActivityState extends ElementState { status?: string; executionId: string; stopped: boolean; @@ -338,19 +406,19 @@ export declare interface ActivityState extends ElementState { execution?: ActivityExecutionState; } -export declare interface SequenceFlowState extends ElementState { +export interface SequenceFlowState extends ElementState { counters: { take: number; discard: number; looped: number }; } -export declare interface MessageFlowState extends ElementState { +export interface MessageFlowState extends ElementState { counters: { messages: number }; } -export declare interface AssociationState extends ElementState { +export interface AssociationState extends ElementState { counters: { take: number; discard: number }; } -export declare interface ProcessExecutionState { +export interface ProcessExecutionState { executionId: string; stopped: boolean; completed: boolean; @@ -361,7 +429,7 @@ export declare interface ProcessExecutionState { associations?: AssociationState[]; } -export declare interface ProcessState extends ElementState { +export interface ProcessState extends ElementState { status: string; stopped: boolean; executionId?: string; @@ -370,7 +438,7 @@ export declare interface ProcessState extends ElementState { execution?: ProcessExecutionState; } -export declare interface DefinitionExecutionState { +export interface DefinitionExecutionState { executionId: string; stopped: boolean; completed: boolean; @@ -378,7 +446,7 @@ export declare interface DefinitionExecutionState { processes: ProcessState[]; } -export declare interface DefinitionState extends ElementState { +export interface DefinitionState extends ElementState { status: string; stopped: boolean; executionId?: string; @@ -389,7 +457,7 @@ export declare interface DefinitionState extends ElementState { // --- Flow references ---------------------------------------------------------- -export declare interface MessageFlowReference { +export interface MessageFlowReference { /** activity id */ get id(): string; get processId(): string; @@ -397,9 +465,9 @@ export declare interface MessageFlowReference { // --- Logging ------------------------------------------------------------------ -export declare type LoggerFactory = (scope: string) => ILogger; +export type LoggerFactory = (scope: string) => ILogger; -export declare interface ILogger { +export interface ILogger { debug(...args: any[]): void; error(...args: any[]): void; warn(...args: any[]): void; @@ -408,10 +476,10 @@ export declare interface ILogger { // --- Timers ------------------------------------------------------------------- -export declare type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; -export declare type wrappedClearTimeout = (ref: any) => void; +export type wrappedSetTimeout = (handler: CallableFunction, delay: number, ...args: any[]) => Timer; +export type wrappedClearTimeout = (ref: any) => void; -export declare interface Timer { +export interface Timer { /** The function to call when the timer elapses */ readonly callback: CallableFunction; /** The number of milliseconds to wait before calling the callback */ @@ -427,20 +495,20 @@ export declare interface Timer { [x: string]: any; } -export declare interface RegisteredTimer { +export interface RegisteredTimer { owner?: any; get setTimeout(): wrappedSetTimeout; get clearTimeout(): wrappedClearTimeout; } -export declare interface ITimers { +export interface ITimers { get setTimeout(): wrappedSetTimeout; get clearTimeout(): wrappedClearTimeout; register(owner?: any): RegisteredTimer; [x: string]: any; } -export declare interface TimersOptions { +export interface TimersOptions { /** Defaults to builtin setTimeout */ setTimeout?: typeof setTimeout; /** Defaults to builtin clearTimeout */ @@ -450,18 +518,18 @@ export declare interface TimersOptions { // --- Scripts ------------------------------------------------------------------ -export declare interface IScripts { +export interface IScripts { register(activity: any): Script | undefined; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; } -export declare interface Script { +export interface Script { execute(executionContext: any, callback: CallableFunction): void; } // --- Generic api shape; constructed via Activity/Process/Definition/Flow Api factories. -export declare interface Api extends ElementBrokerMessage { +export interface IApi extends ElementBrokerMessage { get id(): string; get type(): string; get name(): string; @@ -478,12 +546,12 @@ export declare interface Api extends ElementBrokerMessage { sendApiMessage(action: string, content?: signalMessage, options?: any): void; getPostponed(...args: any[]): any[]; createMessage(content?: Record): any; - getExecuting(): Api[]; + getExecuting(): IApi[]; } // --- Scope passed to user scripts/services ----------------------------------- -interface ExecutionScope { +export interface ExecutionScope { /** Calling element id */ id: string; /** Calling element type */ @@ -506,9 +574,11 @@ interface ExecutionScope { ActivityError: ActivityError; } -/** - * Evaluate flow callback - * @callback evaluateCallback - * @param {Error} err Evaluation error - * @param {boolean|object} evaluationResult If thruthy flow should be taken - */ +// --- Context -- +export interface IExtensionsMapper { + get(activity: any): IExtensions[]; +} + +export interface IExtensions extends IExtension { + readonly count: number; +} From eec7eb9a93ca5b710e652e787651e23c4d098108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Thu, 28 May 2026 06:30:30 +0200 Subject: [PATCH 14/31] annotate with types --- dist/Context.js | 16 +- dist/Environment.js | 1 + dist/activity/Activity.js | 7 +- dist/activity/ActivityExecution.js | 2 + dist/definition/Definition.js | 18 +- dist/definition/DefinitionExecution.js | 9 +- .../eventDefinitions/CancelEventDefinition.js | 6 + .../CompensateEventDefinition.js | 8 + .../ConditionalEventDefinition.js | 8 + dist/eventDefinitions/ErrorEventDefinition.js | 6 + .../EscalationEventDefinition.js | 7 + .../EventDefinitionExecution.js | 7 + dist/eventDefinitions/LinkEventDefinition.js | 6 + .../MessageEventDefinition.js | 6 + .../eventDefinitions/SignalEventDefinition.js | 6 + .../TerminateEventDefinition.js | 5 + dist/eventDefinitions/TimerEventDefinition.js | 7 + dist/flows/Association.js | 3 +- dist/flows/MessageFlow.js | 3 +- dist/flows/SequenceFlow.js | 6 +- dist/io/EnvironmentDataObject.js | 6 + dist/messageHelper.js | 41 ++ dist/process/Process.js | 17 +- dist/process/ProcessExecution.js | 6 +- dist/shared.js | 2 + dist/tasks/CallActivity.js | 2 +- package.json | 4 +- src/Context.js | 16 +- src/Environment.js | 1 + src/activity/Activity.js | 6 +- src/activity/ActivityExecution.js | 2 + src/definition/Definition.js | 17 +- src/definition/DefinitionExecution.js | 9 +- src/eventDefinitions/CancelEventDefinition.js | 6 + .../CompensateEventDefinition.js | 7 + .../ConditionalEventDefinition.js | 8 + src/eventDefinitions/ErrorEventDefinition.js | 6 + .../EscalationEventDefinition.js | 6 + .../EventDefinitionExecution.js | 7 + src/eventDefinitions/LinkEventDefinition.js | 6 + .../MessageEventDefinition.js | 6 + src/eventDefinitions/SignalEventDefinition.js | 6 + .../TerminateEventDefinition.js | 5 + src/eventDefinitions/TimerEventDefinition.js | 6 + src/eventDefinitions/index.js | 32 +- src/events/index.js | 23 +- src/flows/Association.js | 3 +- src/flows/MessageFlow.js | 3 +- src/flows/SequenceFlow.js | 6 +- src/io/EnvironmentDataObject.js | 6 + src/messageHelper.js | 35 ++ src/process/Process.js | 18 +- src/process/ProcessExecution.js | 6 +- src/shared.js | 1 + src/tasks/CallActivity.js | 2 +- test/feature/escalation-feature.js | 3 +- test/helpers/testHelpers.js | 9 +- types/index.d.ts | 486 +++++++----------- types/interfaces.d.ts | 33 +- 59 files changed, 589 insertions(+), 412 deletions(-) diff --git a/dist/Context.js b/dist/Context.js index 505d6c99..9aa75100 100644 --- a/dist/Context.js +++ b/dist/Context.js @@ -33,15 +33,16 @@ function ContextInstance(definitionContext, environment, owner) { name, type = 'context' } = definitionContext; - const sid = (0, _shared.getUniqueId)(id); this.id = id; this.name = name; this.type = type; - this.sid = sid; + /** Unique instance id */ + this.sid = (0, _shared.getUniqueId)(id); this.definitionContext = definitionContext; this.environment = environment; /** @type {import('#types').IExtensionsMapper} */ this.extensionsMapper = new ExtensionsMapper(this); + /** @private */ this.refs = new Map([['activityRefs', new Map()], ['sequenceFlowRefs', new Map()], ['processRefs', new Map()], ['messageFlows', new Set()], ['associationRefs', new Map()], ['dataObjectRefs', new Map()], ['dataStoreRefs', new Map()]]); this[K_OWNER] = owner; } @@ -138,6 +139,7 @@ ContextInstance.prototype.getSequenceFlows = function getSequenceFlows(scopeId) /** * Return the cached sequence flow, instantiating it the first time it is referenced. * @param {import('moddle-context-serializer').SerializableElement} flowDefinition + * @returns {import('./flows/SequenceFlow.js').SequenceFlow} */ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowDefinition) { const sequenceFlowRefs = this.refs.get('sequenceFlowRefs'); @@ -149,6 +151,7 @@ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowD }; /** + * Get association flows * @param {string} [scopeId] Process or sub-process id */ ContextInstance.prototype.getAssociations = function getAssociations(scopeId) { @@ -157,6 +160,7 @@ ContextInstance.prototype.getAssociations = function getAssociations(scopeId) { /** * @param {import('moddle-context-serializer').SerializableElement} associationDefinition + * @returns {import('./flows/Association.js').Association} */ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associationDefinition) { const associationRefs = this.refs.get('associationRefs'); @@ -179,7 +183,7 @@ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { /** * Get or create the process instance for the given id. Each process gets its own cloned environment. * @param {string} processId - * @returns {import('./process/Process.js').Process | null} + * @returns {import('#types').Process | null} */ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const processRefs = this.refs.get('processRefs'); @@ -197,6 +201,7 @@ ContextInstance.prototype.getProcessById = function getProcessById(processId) { /** * Build a fresh, uncached process instance for the given id. Used by call activities. * @param {string} processId + * @returns {import('#types').Process | null} */ ContextInstance.prototype.getNewProcessById = function getNewProcessById(processId) { if (!this.getProcessById(processId)) return null; @@ -209,6 +214,7 @@ ContextInstance.prototype.getNewProcessById = function getNewProcessById(process /** * Get every process in the definition. + * @returns {import('#types').Process[]} */ ContextInstance.prototype.getProcesses = function getProcesses() { return this.definitionContext.getProcesses().map(({ @@ -218,6 +224,7 @@ ContextInstance.prototype.getProcesses = function getProcesses() { /** * Get processes flagged executable in the definition. + * @returns {import('#types').Process[]} */ ContextInstance.prototype.getExecutableProcesses = function getExecutableProcesses() { return this.definitionContext.getExecutableProcesses().map(({ @@ -228,6 +235,7 @@ ContextInstance.prototype.getExecutableProcesses = function getExecutableProcess /** * Get message flows that originate from the given process id. * @param {string} sourceId Source process id + * @returns {import('./flows/MessageFlow.js').MessageFlow[]} */ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { const messageFlowRefs = this.refs.get('messageFlows'); @@ -250,6 +258,7 @@ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { /** * Get or create a data object instance for the given reference id. * @param {string} referenceId + * @return {import('#types').IIOData | undefined} */ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referenceId) { const dataObjectRefs = this.refs.get('dataObjectRefs'); @@ -265,6 +274,7 @@ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referen /** * Get or create a data store instance for the given reference id. * @param {string} referenceId + * @return {import('#types').IIOData | undefined} */ ContextInstance.prototype.getDataStoreById = function getDataStoreById(referenceId) { const dataStoreRefs = this.refs.get('dataStoreRefs'); diff --git a/dist/Environment.js b/dist/Environment.js index 1f581be7..62252afe 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -53,6 +53,7 @@ Object.defineProperty(Environment.prototype, 'services', { /** * Snapshot environment state for recover. + * @returns {import('#types').EnvironmentState} */ Environment.prototype.getState = function getState() { return { diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 9f42972d..f0e56ad1 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -24,7 +24,7 @@ const K_FORMATTER = Symbol.for('formatter'); /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param {import('#types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution - * @param {import('moddle-context-serializer').SerializableElement} activityDef Parsed BPMN element definition + * @param {import('moddle-context-serializer').Activity} activityDef Parsed BPMN element definition * @param {import('#types').ContextInstance} context Per-execution registry and factory */ function Activity(Behaviour, activityDef, context) { @@ -49,6 +49,7 @@ function Activity(Behaviour, activityDef, context) { this.Behaviour = Behaviour; /** @type {import('moddle-context-serializer').Parent} */ this.parent = activityDef.parent ? (0, _messageHelper.cloneParent)(activityDef.parent) : {}; + /** @type {import('#types').ILogger} */ this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; @@ -119,6 +120,8 @@ function Activity(Behaviour, activityDef, context) { onApiMessage: this._onApiMessage.bind(this), onExecutionMessage: this._onExecutionMessage.bind(this) }; + + /** @type {import('#types').EventDefinition[] | undefined} */ this[K_EVENT_DEFINITIONS] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); this[_constants.K_EXTENSIONS] = context.loadExtensions(this); this[_constants.K_CONSUMING] = false; @@ -409,7 +412,7 @@ Activity.prototype.discard = function discard(discardContent) { /** * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers + * @returns {number} count of subscribed triggers */ Activity.prototype.addInboundListeners = function addInboundListeners() { const triggers = this[K_FLOWS].inboundTriggers; diff --git a/dist/activity/ActivityExecution.js b/dist/activity/ActivityExecution.js index 41635bde..d939f002 100644 --- a/dist/activity/ActivityExecution.js +++ b/dist/activity/ActivityExecution.js @@ -144,6 +144,7 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { /** * Pass an execute message straight to the behaviour, executing first if no source is set up yet. * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} */ ActivityExecution.prototype.passthrough = function passthrough(executeMessage) { if (!this.source) return this.execute(executeMessage); @@ -165,6 +166,7 @@ ActivityExecution.prototype.getPostponed = function getPostponed() { /** * Snapshot execution state, merging behaviour-specific state when the source provides it. + * @returns {import('#types').ActivityExecutionState} */ ActivityExecution.prototype.getState = function getState() { const result = { diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index 627a3a02..449c3359 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -26,14 +26,17 @@ function Definition(context, options) { type = 'definition' } = context; this.id = id; + /** @type {string} */ this.type = type; this.name = name; - let environment; + + /** @type {import('../Environment.js').Environment} */ + this.environment = undefined; if (options) { - environment = this.environment = context.environment.clone(options).assignSettings(options.settings); - this.context = context.clone(environment); + this.environment = context.environment.clone(options).assignSettings(options.settings); + this.context = context.clone(this.environment); } else { - environment = this.environment = context.environment; + this.environment = context.environment; this.context = context; } this[_constants.K_COUNTERS] = { @@ -66,7 +69,7 @@ function Definition(context, options) { this.emitFatal = emitFatal; /** @type {import('#types').ILogger} */ - this.logger = environment.Logger(type.toLowerCase()); + this.logger = this.environment.Logger(type.toLowerCase()); } Object.defineProperties(Definition.prototype, { counters: { @@ -171,6 +174,7 @@ Definition.prototype.resume = function resume(callback) { /** * Snapshot definition state for recover. + * @returns {import('#types').DefinitionState} */ Definition.prototype.getState = function getState() { return this._createMessage({ @@ -311,9 +315,7 @@ Definition.prototype.getElementById = function getElementById(elementId) { * @param {import('#types').filterPostponed} [filterFn] */ Definition.prototype.getPostponed = function getPostponed(...args) { - const execution = this.execution; - if (!execution) return []; - return execution.getPostponed(...args); + return this.execution?.getPostponed(...args) || []; }; /** diff --git a/dist/definition/DefinitionExecution.js b/dist/definition/DefinitionExecution.js index 5f814fe5..167a0c29 100644 --- a/dist/definition/DefinitionExecution.js +++ b/dist/definition/DefinitionExecution.js @@ -38,13 +38,10 @@ function DefinitionExecution(definition, context) { if (bp.isExecutable) executable.add(bp); } this[K_PROCESSES] = { - /** @type {import('../process/Process.js').Process[]} */ processes, ids, executable, - /** @type {Set} */ running: new Set(), - /** @type {Set} */ postponed: new Set() }; broker.assertExchange('execution', 'topic', { @@ -226,6 +223,7 @@ DefinitionExecution.prototype.stop = function stop() { /** * Get every process in the definition (running first, then any non-running by id). + * @returns {import('../process/Process.js').Process[]} */ DefinitionExecution.prototype.getProcesses = function getProcesses() { const { @@ -256,6 +254,7 @@ DefinitionExecution.prototype.getProcessesById = function getProcessesById(proce /** * @param {string} processExecutionId + * @returns {import('../process/Process.js').Process | undefined} */ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExecutionId(processExecutionId) { for (const bp of this[K_PROCESSES].running) { @@ -265,6 +264,7 @@ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExe /** * Get processes that have an executionId, i.e. are currently running. + * @returns {import('../process/Process.js').Process[]} */ DefinitionExecution.prototype.getRunningProcesses = function getRunningProcesses() { return [...this[K_PROCESSES].running].filter(bp => bp.executionId); @@ -272,6 +272,7 @@ DefinitionExecution.prototype.getRunningProcesses = function getRunningProcesses /** * Get processes flagged executable in the definition. + * @returns {import('../process/Process.js').Process[]} */ DefinitionExecution.prototype.getExecutableProcesses = function getExecutableProcesses() { return [...this[K_PROCESSES].executable]; @@ -279,6 +280,7 @@ DefinitionExecution.prototype.getExecutableProcesses = function getExecutablePro /** * Snapshot execution state for recover. + * @returns {import('#types').DefinitionExecutionState} */ DefinitionExecution.prototype.getState = function getState() { const processes = []; @@ -324,6 +326,7 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { /** * List currently postponed activities across every running process. * @param {import('#types').filterPostponed} [filterFn] + * @returns {import('#types').IApi} */ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { let result = []; diff --git a/dist/eventDefinitions/CancelEventDefinition.js b/dist/eventDefinitions/CancelEventDefinition.js index 94569b66..a0c930ee 100644 --- a/dist/eventDefinitions/CancelEventDefinition.js +++ b/dist/eventDefinitions/CancelEventDefinition.js @@ -6,6 +6,11 @@ Object.defineProperty(exports, "__esModule", { exports.CancelEventDefinition = CancelEventDefinition; var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Cancel event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function CancelEventDefinition(activity, eventDefinition) { const { id, @@ -26,6 +31,7 @@ function CancelEventDefinition(activity, eventDefinition) { this.logger = environment.Logger(type.toLowerCase()); } Object.defineProperty(CancelEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/CompensateEventDefinition.js b/dist/eventDefinitions/CompensateEventDefinition.js index fb36ef84..6293aa14 100644 --- a/dist/eventDefinitions/CompensateEventDefinition.js +++ b/dist/eventDefinitions/CompensateEventDefinition.js @@ -9,6 +9,13 @@ var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); const K_COMPENSATE_Q = Symbol.for('compensateQ'); const K_ASSOCIATIONS = Symbol.for('associations'); + +/** + * Compensate event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + * @param {import('#types').ContextInstance} context + */ function CompensateEventDefinition(activity, eventDefinition, context) { const { id, @@ -44,6 +51,7 @@ function CompensateEventDefinition(activity, eventDefinition, context) { } } Object.defineProperty(CompensateEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/ConditionalEventDefinition.js b/dist/eventDefinitions/ConditionalEventDefinition.js index 72f25c3c..534623f7 100644 --- a/dist/eventDefinitions/ConditionalEventDefinition.js +++ b/dist/eventDefinitions/ConditionalEventDefinition.js @@ -8,6 +8,13 @@ var _messageHelper = require("../messageHelper.js"); var _Errors = require("../error/Errors.js"); var _condition = require("../condition.js"); var _constants = require("../constants.js"); +/** + * Conditional event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + * @param {import('#types').ContextInstance} _context + * @param {number} index event definition index + */ function ConditionalEventDefinition(activity, eventDefinition, _context, index) { const { id, @@ -28,6 +35,7 @@ function ConditionalEventDefinition(activity, eventDefinition, _context, index) this.condition = this.getCondition(index); } Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/ErrorEventDefinition.js b/dist/eventDefinitions/ErrorEventDefinition.js index c4f11d3e..0f6fb357 100644 --- a/dist/eventDefinitions/ErrorEventDefinition.js +++ b/dist/eventDefinitions/ErrorEventDefinition.js @@ -7,6 +7,11 @@ exports.ErrorEventDefinition = ErrorEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Error event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function ErrorEventDefinition(activity, eventDefinition) { const { id, @@ -46,6 +51,7 @@ function ErrorEventDefinition(activity, eventDefinition) { } } Object.defineProperty(ErrorEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/EscalationEventDefinition.js b/dist/eventDefinitions/EscalationEventDefinition.js index 80fe03e1..ab5c2a6c 100644 --- a/dist/eventDefinitions/EscalationEventDefinition.js +++ b/dist/eventDefinitions/EscalationEventDefinition.js @@ -9,6 +9,12 @@ var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); const K_REFERENCE = Symbol.for('reference'); + +/** + * Escalation event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function EscalationEventDefinition(activity, eventDefinition) { const { id, @@ -47,6 +53,7 @@ function EscalationEventDefinition(activity, eventDefinition) { } } Object.defineProperty(EscalationEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/EventDefinitionExecution.js b/dist/eventDefinitions/EventDefinitionExecution.js index cf7cc962..a7b049b0 100644 --- a/dist/eventDefinitions/EventDefinitionExecution.js +++ b/dist/eventDefinitions/EventDefinitionExecution.js @@ -6,6 +6,13 @@ Object.defineProperty(exports, "__esModule", { exports.EventDefinitionExecution = EventDefinitionExecution; var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Event definition execution orchestrator. Drives a sequence of event definitions for the + * activity and publishes the completed routing key when the last definition completes. + * @param {import('#types').Activity} activity + * @param {import('#types').EventDefinition[]} eventDefinitions + * @param {string} [completedRoutingKey] Routing key to publish on completion, defaults to `execute.completed` + */ function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKey = 'execute.completed') { this.id = activity.id; this.activity = activity; diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index c7427b5b..4345eabc 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -7,6 +7,11 @@ exports.LinkEventDefinition = LinkEventDefinition; var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Link event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function LinkEventDefinition(activity, eventDefinition) { const { id, @@ -65,6 +70,7 @@ function LinkEventDefinition(activity, eventDefinition) { } } Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/MessageEventDefinition.js b/dist/eventDefinitions/MessageEventDefinition.js index 4301253a..286078bf 100644 --- a/dist/eventDefinitions/MessageEventDefinition.js +++ b/dist/eventDefinitions/MessageEventDefinition.js @@ -8,6 +8,11 @@ var _getPropertyValue = require("../getPropertyValue.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Message event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function MessageEventDefinition(activity, eventDefinition) { const { id, @@ -45,6 +50,7 @@ function MessageEventDefinition(activity, eventDefinition) { } } Object.defineProperty(MessageEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/SignalEventDefinition.js b/dist/eventDefinitions/SignalEventDefinition.js index 7d239ab6..f024b3f6 100644 --- a/dist/eventDefinitions/SignalEventDefinition.js +++ b/dist/eventDefinitions/SignalEventDefinition.js @@ -8,6 +8,11 @@ var _getPropertyValue = require("../getPropertyValue.js"); var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Signal event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function SignalEventDefinition(activity, eventDefinition) { const { id, @@ -46,6 +51,7 @@ function SignalEventDefinition(activity, eventDefinition) { } } Object.defineProperty(SignalEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } diff --git a/dist/eventDefinitions/TerminateEventDefinition.js b/dist/eventDefinitions/TerminateEventDefinition.js index 3d3565c7..00c887a1 100644 --- a/dist/eventDefinitions/TerminateEventDefinition.js +++ b/dist/eventDefinitions/TerminateEventDefinition.js @@ -5,6 +5,11 @@ Object.defineProperty(exports, "__esModule", { }); exports.TerminateEventDefinition = TerminateEventDefinition; var _messageHelper = require("../messageHelper.js"); +/** + * Terminate event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function TerminateEventDefinition(activity, eventDefinition) { const { id, diff --git a/dist/eventDefinitions/TimerEventDefinition.js b/dist/eventDefinitions/TimerEventDefinition.js index e9f64471..45ecc0c5 100644 --- a/dist/eventDefinitions/TimerEventDefinition.js +++ b/dist/eventDefinitions/TimerEventDefinition.js @@ -11,6 +11,12 @@ var _constants = require("../constants.js"); const K_TIMER_CONTENT = Symbol.for('timerContent'); const K_TIMER = Symbol.for('timer'); const timerTypes = new Set(['timeDuration', 'timeDate', 'timeCycle']); + +/** + * Timer event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ function TimerEventDefinition(activity, eventDefinition) { const type = this.type = eventDefinition.type || 'TimerEventDefinition'; this.activity = activity; @@ -30,6 +36,7 @@ function TimerEventDefinition(activity, eventDefinition) { this[K_TIMER] = null; } Object.defineProperty(TimerEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_TIMER_CONTENT]?.executionId; } diff --git a/dist/flows/Association.js b/dist/flows/Association.js index d5b46c4c..ef8fe044 100644 --- a/dist/flows/Association.js +++ b/dist/flows/Association.js @@ -12,7 +12,7 @@ var _constants = require("../constants.js"); /** * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. - * @param {import('moddle-context-serializer').SerializableElement} associationDef + * @param {import('moddle-context-serializer').Association} associationDef * @param {import('#types').ContextInstance} context */ function Association(associationDef, { @@ -31,6 +31,7 @@ function Association(associationDef, { this.type = type; this.name = name; this.parent = (0, _messageHelper.cloneParent)(parent); + /** @type {Record} */ this.behaviour = behaviour; this.sourceId = sourceId; this.targetId = targetId; diff --git a/dist/flows/MessageFlow.js b/dist/flows/MessageFlow.js index 913ae87e..dd7ef8a5 100644 --- a/dist/flows/MessageFlow.js +++ b/dist/flows/MessageFlow.js @@ -15,7 +15,7 @@ const K_SOURCE_ELEMENT = Symbol.for('sourceElement'); * Message flow connecting a source activity (or process) to a target. Subscribes to the * source's `end` event and publishes `message.outbound` whenever the source completes, * carrying any message payload through to the target. - * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('moddle-context-serializer').MessageFlow} flowDef * @param {import('#types').ContextInstance} context */ function MessageFlow(flowDef, context) { @@ -34,6 +34,7 @@ function MessageFlow(flowDef, context) { this.parent = (0, _messageHelper.cloneParent)(parent); this.source = source; this.target = target; + /** @type {Record} */ this.behaviour = behaviour; this.environment = context.environment; this.context = context; diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index 8e4fd6b4..b5474c50 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -13,7 +13,7 @@ var _constants = require("../constants.js"); /** * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. - * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('moddle-context-serializer').SequenceFlow} flowDef * @param {import('#types').ContextInstance} context */ function SequenceFlow(flowDef, { @@ -33,6 +33,7 @@ function SequenceFlow(flowDef, { this.type = type; this.name = name; this.parent = (0, _messageHelper.cloneParent)(parent); + /** @type {Record} */ this.behaviour = behaviour; this.sourceId = sourceId; this.targetId = targetId; @@ -207,6 +208,7 @@ SequenceFlow.prototype.getCondition = function getCondition() { /** * Build a flow event message body, optionally merging override content. * @param {Record} [override] + * @returns {import('#types').ElementMessageContent} */ SequenceFlow.prototype.createMessage = function createMessage(override) { return { @@ -225,7 +227,7 @@ SequenceFlow.prototype.createMessage = function createMessage(override) { /** * Evaluate the flow's condition for the source activity message. Default flows are always taken. * @param {import('#types').ElementBrokerMessage} fromMessage Source activity message - * @param {(err: Error | null, result?: boolean | object) => void} callback Callback with truthy result if flow should be taken + * @param {(err: Error | null, result?: boolean | unknown) => void} callback Callback with truthy result if flow should be taken */ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { if (this.isDefault) { diff --git a/dist/io/EnvironmentDataObject.js b/dist/io/EnvironmentDataObject.js index e70576f4..e52f9226 100644 --- a/dist/io/EnvironmentDataObject.js +++ b/dist/io/EnvironmentDataObject.js @@ -4,6 +4,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.EnvironmentDataObject = EnvironmentDataObject; +/** + * Builtin data object + * @param {import('moddle-context-serializer').DataObject>} dataObjectDef + * @param {import('../Context.js').ContextInstance} context + * @satisfies {import('#types').IIOData} + */ function EnvironmentDataObject(dataObjectDef, { environment }) { diff --git a/dist/messageHelper.js b/dist/messageHelper.js index 55891969..4d441148 100644 --- a/dist/messageHelper.js +++ b/dist/messageHelper.js @@ -9,6 +9,12 @@ exports.cloneParent = cloneParent; exports.pushParent = pushParent; exports.shiftParent = shiftParent; exports.unshiftParent = unshiftParent; +/** + * Clone message content + * @param {import('#types').ElementMessageContent} content + * @param {Record} [extend] + * @returns cloned content + */ function cloneContent(content, extend) { const { discardSequence, @@ -17,6 +23,8 @@ function cloneContent(content, extend) { parent, sequence } = content; + + /** @type {import('#types').ElementMessageContent} */ const clone = { ...content, ...extend @@ -38,6 +46,13 @@ function cloneContent(content, extend) { } return clone; } + +/** + * Clone message + * @param {import('#types').ElementBrokerMessage} message + * @param {Record} [overrideContent] + * @returns {Pick} + */ function cloneMessage(message, overrideContent) { return { fields: { @@ -49,6 +64,12 @@ function cloneMessage(message, overrideContent) { } }; } + +/** + * Clone parent + * @param {import('#types').ElementParent} parent + * @returns {import('#types').ElementParent} cloned parent + */ function cloneParent(parent) { const { path @@ -64,6 +85,13 @@ function cloneParent(parent) { }); return clone; } + +/** + * Add parent to top of path + * @param {import('#types').ElementParent} parent + * @param {import('#types').ElementMessageContent} adoptingParent + * @returns {import('#types').ElementParent} + */ function unshiftParent(parent, adoptingParent) { const { id, @@ -94,6 +122,12 @@ function unshiftParent(parent, adoptingParent) { }); return clone; } + +/** + * Remove top parent from path + * @param {import('#types').ElementParent} parent + * @returns {import('#types').ElementParent} + */ function shiftParent(parent) { if (!parent) return; if (!parent.path || !parent.path.length) return; @@ -109,6 +143,13 @@ function shiftParent(parent) { clone.path = clone.path.length ? clone.path : undefined; return clone; } + +/** + * Add ancestor parent at end + * @param {import('#types').ElementParent} parent + * @param {import('#types').ElementMessageContent} ancestor + * @returns {import('#types').ElementParent} + */ function pushParent(parent, ancestor) { const { id, diff --git a/dist/process/Process.js b/dist/process/Process.js index d1197f13..bade8663 100644 --- a/dist/process/Process.js +++ b/dist/process/Process.js @@ -16,7 +16,7 @@ const K_LANES = Symbol.for('lanes'); /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. - * @param {import('moddle-context-serializer').MappedProcess} processDef + * @param {import('moddle-context-serializer').Process} processDef * @param {import('#types').ContextInstance} context */ function Process(processDef, context) { @@ -30,7 +30,9 @@ function Process(processDef, context) { this.id = id; this.type = type; this.name = name; + /** @type {import('#types').ElementParent} */ this.parent = parent ? (0, _messageHelper.cloneParent)(parent) : {}; + /** @type {import('moddle-context-serializer').Process['behaviour']} */ this.behaviour = behaviour; this.isExecutable = behaviour.isExecutable; const environment = this.environment = context.environment; @@ -170,6 +172,7 @@ Process.prototype.resume = function resume() { /** * Snapshot process state for recover. + * @returns {import('#types').ProcessState} */ Process.prototype.getState = function getState() { return { @@ -495,11 +498,10 @@ Process.prototype.getSequenceFlows = function getSequenceFlows() { /** * @param {string} laneId + * @returns {import('./Lane.js') | undefined} */ Process.prototype.getLaneById = function getLaneById(laneId) { - const lanes = this[K_LANES]; - if (!lanes) return; - return lanes.find(lane => lane.id === laneId); + return this[K_LANES]?.find(lane => lane.id === laneId); }; /** @@ -507,15 +509,12 @@ Process.prototype.getLaneById = function getLaneById(laneId) { * @param {import('#types').filterPostponed} [filterFn] */ Process.prototype.getPostponed = function getPostponed(...args) { - const execution = this.execution; - if (!execution) return []; - return execution.getPostponed(...args); + return this.execution?.getPostponed(...args) || []; }; /** @internal */ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { - const messageType = message.properties.type; - switch (messageType) { + switch (message.properties.type) { case 'stop': { if (this.execution && !this.execution.completed) return; diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 2283a589..72b2fc5e 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -317,6 +317,7 @@ ProcessExecution.prototype.cancel = function discard() { /** * Get child activities in the process scope. + * @returns {import('#types').Activity[]} */ ProcessExecution.prototype.getActivities = function getActivities() { return this[K_ELEMENTS].children.slice(); @@ -324,6 +325,7 @@ ProcessExecution.prototype.getActivities = function getActivities() { /** * @param {string} activityId + * @returns {import('#types').Activity} */ ProcessExecution.prototype.getActivityById = function getActivityById(activityId) { return this[K_ELEMENTS].children.find(child => child.id === activityId); @@ -331,6 +333,7 @@ ProcessExecution.prototype.getActivityById = function getActivityById(activityId /** * Get sequence flows in the process scope. + * @returns {import('#types').SequenceFlow} */ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() { return this[K_ELEMENTS].flows.slice(); @@ -338,6 +341,7 @@ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() { /** * Get associations in the process scope. + * @returns {import('../flows/Association.js').Association} */ ProcessExecution.prototype.getAssociations = function getAssociations() { return this[K_ELEMENTS].associations.slice(); @@ -346,7 +350,7 @@ ProcessExecution.prototype.getAssociations = function getAssociations() { /** * Resolve a process or child Api for the given message. * @param {import('#types').ElementBrokerMessage} [message] - * @returns {import('#types').IApi} + * @returns {import('#types').IApi} */ ProcessExecution.prototype.getApi = function getApi(message) { if (!message) return (0, _Api.ProcessApi)(this.broker, this[_constants.K_EXECUTE_MESSAGE]); diff --git a/dist/shared.js b/dist/shared.js index 9fe06998..e3f721c8 100644 --- a/dist/shared.js +++ b/dist/shared.js @@ -14,6 +14,8 @@ function generateId() { function brokerSafeId(id) { return id.replace(safePattern, '_'); } + +/** @param {string} prefix */ function getUniqueId(prefix) { return `${brokerSafeId(prefix)}_${generateId()}`; } diff --git a/dist/tasks/CallActivity.js b/dist/tasks/CallActivity.js index d8361b89..44a3a1f6 100644 --- a/dist/tasks/CallActivity.js +++ b/dist/tasks/CallActivity.js @@ -10,7 +10,7 @@ var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); /** * Create call activity - * @param {import('moddle-context-serializer').MappedActivity} activityDef + * @param {import('moddle-context-serializer').Activity} activityDef * @param {import('../Context.js').ContextInstance} context * @returns Call activity */ diff --git a/package.json b/package.json index 55a867b9..2937a806 100644 --- a/package.json +++ b/package.json @@ -108,12 +108,12 @@ "chai": "^6.2.1", "chronokinesis": "^8.0.0", "debug": "^4.3.4", - "dts-buddy": "^0.7.0", + "dts-buddy": "^0.8.0", "eslint": "^10.3.0", "globals": "^17.0.0", "mocha": "^11.0.1", "mocha-cakes-2": "^3.3.0", - "moddle-context-serializer": "^5.0.0", + "moddle-context-serializer": "^6.0.0", "nock": "^14.0.0", "prettier": "^3.2.5", "texample": "^1.0.1" diff --git a/src/Context.js b/src/Context.js index 835dcc72..cdc33eee 100644 --- a/src/Context.js +++ b/src/Context.js @@ -23,15 +23,16 @@ export function Context(definitionContext, environment) { */ export function ContextInstance(definitionContext, environment, owner) { const { id = 'Def', name, type = 'context' } = definitionContext; - const sid = getUniqueId(id); this.id = id; this.name = name; this.type = type; - this.sid = sid; + /** Unique instance id */ + this.sid = getUniqueId(id); this.definitionContext = definitionContext; this.environment = environment; /** @type {import('#types').IExtensionsMapper} */ this.extensionsMapper = new ExtensionsMapper(this); + /** @private */ this.refs = new Map([ ['activityRefs', new Map()], ['sequenceFlowRefs', new Map()], @@ -140,6 +141,7 @@ ContextInstance.prototype.getSequenceFlows = function getSequenceFlows(scopeId) /** * Return the cached sequence flow, instantiating it the first time it is referenced. * @param {import('moddle-context-serializer').SerializableElement} flowDefinition + * @returns {import('./flows/SequenceFlow.js').SequenceFlow} */ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowDefinition) { const sequenceFlowRefs = this.refs.get('sequenceFlowRefs'); @@ -153,6 +155,7 @@ ContextInstance.prototype.upsertSequenceFlow = function upsertSequenceFlow(flowD }; /** + * Get association flows * @param {string} [scopeId] Process or sub-process id */ ContextInstance.prototype.getAssociations = function getAssociations(scopeId) { @@ -161,6 +164,7 @@ ContextInstance.prototype.getAssociations = function getAssociations(scopeId) { /** * @param {import('moddle-context-serializer').SerializableElement} associationDefinition + * @returns {import('./flows/Association.js').Association} */ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associationDefinition) { const associationRefs = this.refs.get('associationRefs'); @@ -186,7 +190,7 @@ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { /** * Get or create the process instance for the given id. Each process gets its own cloned environment. * @param {string} processId - * @returns {import('./process/Process.js').Process | null} + * @returns {import('#types').Process | null} */ ContextInstance.prototype.getProcessById = function getProcessById(processId) { const processRefs = this.refs.get('processRefs'); @@ -207,6 +211,7 @@ ContextInstance.prototype.getProcessById = function getProcessById(processId) { /** * Build a fresh, uncached process instance for the given id. Used by call activities. * @param {string} processId + * @returns {import('#types').Process | null} */ ContextInstance.prototype.getNewProcessById = function getNewProcessById(processId) { if (!this.getProcessById(processId)) return null; @@ -221,6 +226,7 @@ ContextInstance.prototype.getNewProcessById = function getNewProcessById(process /** * Get every process in the definition. + * @returns {import('#types').Process[]} */ ContextInstance.prototype.getProcesses = function getProcesses() { return this.definitionContext.getProcesses().map(({ id: processId }) => this.getProcessById(processId)); @@ -228,6 +234,7 @@ ContextInstance.prototype.getProcesses = function getProcesses() { /** * Get processes flagged executable in the definition. + * @returns {import('#types').Process[]} */ ContextInstance.prototype.getExecutableProcesses = function getExecutableProcesses() { return this.definitionContext.getExecutableProcesses().map(({ id: processId }) => this.getProcessById(processId)); @@ -236,6 +243,7 @@ ContextInstance.prototype.getExecutableProcesses = function getExecutableProcess /** * Get message flows that originate from the given process id. * @param {string} sourceId Source process id + * @returns {import('./flows/MessageFlow.js').MessageFlow[]} */ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { const messageFlowRefs = this.refs.get('messageFlows'); @@ -261,6 +269,7 @@ ContextInstance.prototype.getMessageFlows = function getMessageFlows(sourceId) { /** * Get or create a data object instance for the given reference id. * @param {string} referenceId + * @return {import('#types').IIOData | undefined} */ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referenceId) { const dataObjectRefs = this.refs.get('dataObjectRefs'); @@ -279,6 +288,7 @@ ContextInstance.prototype.getDataObjectById = function getDataObjectById(referen /** * Get or create a data store instance for the given reference id. * @param {string} referenceId + * @return {import('#types').IIOData | undefined} */ ContextInstance.prototype.getDataStoreById = function getDataStoreById(referenceId) { const dataStoreRefs = this.refs.get('dataStoreRefs'); diff --git a/src/Environment.js b/src/Environment.js index fac3b7ee..fbd366c0 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -49,6 +49,7 @@ Object.defineProperty(Environment.prototype, 'services', { /** * Snapshot environment state for recover. + * @returns {import('#types').EnvironmentState} */ Environment.prototype.getState = function getState() { return { diff --git a/src/activity/Activity.js b/src/activity/Activity.js index de3af80b..ace4f99f 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -27,7 +27,7 @@ const K_FORMATTER = Symbol.for('formatter'); /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param {import('#types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution - * @param {import('moddle-context-serializer').SerializableElement} activityDef Parsed BPMN element definition + * @param {import('moddle-context-serializer').Activity} activityDef Parsed BPMN element definition * @param {import('#types').ContextInstance} context Per-execution registry and factory */ export function Activity(Behaviour, activityDef, context) { @@ -42,6 +42,7 @@ export function Activity(Behaviour, activityDef, context) { this.Behaviour = Behaviour; /** @type {import('moddle-context-serializer').Parent} */ this.parent = activityDef.parent ? cloneParent(activityDef.parent) : {}; + /** @type {import('#types').ILogger} */ this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; @@ -114,6 +115,7 @@ export function Activity(Behaviour, activityDef, context) { onExecutionMessage: this._onExecutionMessage.bind(this), }; + /** @type {import('#types').EventDefinition[] | undefined} */ this[K_EVENT_DEFINITIONS] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx)); this[K_EXTENSIONS] = context.loadExtensions(this); this[K_CONSUMING] = false; @@ -404,7 +406,7 @@ Activity.prototype.discard = function discard(discardContent) { /** * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). - * @returns count of subscribed triggers + * @returns {number} count of subscribed triggers */ Activity.prototype.addInboundListeners = function addInboundListeners() { const triggers = this[K_FLOWS].inboundTriggers; diff --git a/src/activity/ActivityExecution.js b/src/activity/ActivityExecution.js index 8af971bc..76faabc7 100644 --- a/src/activity/ActivityExecution.js +++ b/src/activity/ActivityExecution.js @@ -144,6 +144,7 @@ ActivityExecution.prototype.getApi = function getApi(apiMessage) { /** * Pass an execute message straight to the behaviour, executing first if no source is set up yet. * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} */ ActivityExecution.prototype.passthrough = function passthrough(executeMessage) { if (!this.source) return this.execute(executeMessage); @@ -165,6 +166,7 @@ ActivityExecution.prototype.getPostponed = function getPostponed() { /** * Snapshot execution state, merging behaviour-specific state when the source provides it. + * @returns {import('#types').ActivityExecutionState} */ ActivityExecution.prototype.getState = function getState() { const result = { completed: this[K_COMPLETED] }; diff --git a/src/definition/Definition.js b/src/definition/Definition.js index 5ceeb72a..df2128b4 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -28,15 +28,17 @@ export function Definition(context, options) { const { id, name, type = 'definition' } = context; this.id = id; + /** @type {string} */ this.type = type; this.name = name; - let environment; + /** @type {import('../Environment.js').Environment} */ + this.environment = undefined; if (options) { - environment = this.environment = context.environment.clone(options).assignSettings(options.settings); - this.context = context.clone(environment); + this.environment = context.environment.clone(options).assignSettings(options.settings); + this.context = context.clone(this.environment); } else { - environment = this.environment = context.environment; + this.environment = context.environment; this.context = context; } @@ -67,7 +69,7 @@ export function Definition(context, options) { this.emitFatal = emitFatal; /** @type {import('#types').ILogger} */ - this.logger = environment.Logger(type.toLowerCase()); + this.logger = this.environment.Logger(type.toLowerCase()); } Object.defineProperties(Definition.prototype, { @@ -177,6 +179,7 @@ Definition.prototype.resume = function resume(callback) { /** * Snapshot definition state for recover. + * @returns {import('#types').DefinitionState} */ Definition.prototype.getState = function getState() { return this._createMessage({ @@ -325,9 +328,7 @@ Definition.prototype.getElementById = function getElementById(elementId) { * @param {import('#types').filterPostponed} [filterFn] */ Definition.prototype.getPostponed = function getPostponed(...args) { - const execution = this.execution; - if (!execution) return []; - return execution.getPostponed(...args); + return this.execution?.getPostponed(...args) || []; }; /** diff --git a/src/definition/DefinitionExecution.js b/src/definition/DefinitionExecution.js index 1a79175f..d52cdb49 100644 --- a/src/definition/DefinitionExecution.js +++ b/src/definition/DefinitionExecution.js @@ -36,13 +36,10 @@ export function DefinitionExecution(definition, context) { } this[K_PROCESSES] = { - /** @type {import('../process/Process.js').Process[]} */ processes, ids, executable, - /** @type {Set} */ running: new Set(), - /** @type {Set} */ postponed: new Set(), }; @@ -235,6 +232,7 @@ DefinitionExecution.prototype.stop = function stop() { /** * Get every process in the definition (running first, then any non-running by id). + * @returns {import('../process/Process.js').Process[]} */ DefinitionExecution.prototype.getProcesses = function getProcesses() { const { running, processes } = this[K_PROCESSES]; @@ -262,6 +260,7 @@ DefinitionExecution.prototype.getProcessesById = function getProcessesById(proce /** * @param {string} processExecutionId + * @returns {import('../process/Process.js').Process | undefined} */ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExecutionId(processExecutionId) { for (const bp of this[K_PROCESSES].running) { @@ -271,6 +270,7 @@ DefinitionExecution.prototype.getProcessByExecutionId = function getProcessByExe /** * Get processes that have an executionId, i.e. are currently running. + * @returns {import('../process/Process.js').Process[]} */ DefinitionExecution.prototype.getRunningProcesses = function getRunningProcesses() { return [...this[K_PROCESSES].running].filter((bp) => bp.executionId); @@ -278,6 +278,7 @@ DefinitionExecution.prototype.getRunningProcesses = function getRunningProcesses /** * Get processes flagged executable in the definition. + * @returns {import('../process/Process.js').Process[]} */ DefinitionExecution.prototype.getExecutableProcesses = function getExecutableProcesses() { return [...this[K_PROCESSES].executable]; @@ -285,6 +286,7 @@ DefinitionExecution.prototype.getExecutableProcesses = function getExecutablePro /** * Snapshot execution state for recover. + * @returns {import('#types').DefinitionExecutionState} */ DefinitionExecution.prototype.getState = function getState() { const processes = []; @@ -333,6 +335,7 @@ DefinitionExecution.prototype.getApi = function getApi(apiMessage) { /** * List currently postponed activities across every running process. * @param {import('#types').filterPostponed} [filterFn] + * @returns {import('#types').IApi} */ DefinitionExecution.prototype.getPostponed = function getPostponed(...args) { let result = []; diff --git a/src/eventDefinitions/CancelEventDefinition.js b/src/eventDefinitions/CancelEventDefinition.js index 1bd2834c..4ca8cbc8 100644 --- a/src/eventDefinitions/CancelEventDefinition.js +++ b/src/eventDefinitions/CancelEventDefinition.js @@ -1,6 +1,11 @@ import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE } from '../constants.js'; +/** + * Cancel event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function CancelEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const type = eventDefinition.type; @@ -16,6 +21,7 @@ export function CancelEventDefinition(activity, eventDefinition) { } Object.defineProperty(CancelEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/CompensateEventDefinition.js b/src/eventDefinitions/CompensateEventDefinition.js index 098d93dc..f0f37f28 100644 --- a/src/eventDefinitions/CompensateEventDefinition.js +++ b/src/eventDefinitions/CompensateEventDefinition.js @@ -5,6 +5,12 @@ import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q } from '../constants.js'; const K_COMPENSATE_Q = Symbol.for('compensateQ'); const K_ASSOCIATIONS = Symbol.for('associations'); +/** + * Compensate event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + * @param {import('#types').ContextInstance} context + */ export function CompensateEventDefinition(activity, eventDefinition, context) { const { id, broker, environment, isThrowing } = activity; @@ -27,6 +33,7 @@ export function CompensateEventDefinition(activity, eventDefinition, context) { } Object.defineProperty(CompensateEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/ConditionalEventDefinition.js b/src/eventDefinitions/ConditionalEventDefinition.js index 717e2826..f29e2ebc 100644 --- a/src/eventDefinitions/ConditionalEventDefinition.js +++ b/src/eventDefinitions/ConditionalEventDefinition.js @@ -3,6 +3,13 @@ import { ActivityError } from '../error/Errors.js'; import { ScriptCondition, ExpressionCondition } from '../condition.js'; import { K_EXECUTE_MESSAGE } from '../constants.js'; +/** + * Conditional event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + * @param {import('#types').ContextInstance} _context + * @param {number} index event definition index + */ export function ConditionalEventDefinition(activity, eventDefinition, _context, index) { const { id, broker, environment } = activity; @@ -18,6 +25,7 @@ export function ConditionalEventDefinition(activity, eventDefinition, _context, } Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/ErrorEventDefinition.js b/src/eventDefinitions/ErrorEventDefinition.js index b45dcace..12d0ea79 100644 --- a/src/eventDefinitions/ErrorEventDefinition.js +++ b/src/eventDefinitions/ErrorEventDefinition.js @@ -2,6 +2,11 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; +/** + * Error event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function ErrorEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type = 'ErrorEventDefinition', behaviour = {} } = eventDefinition; @@ -32,6 +37,7 @@ export function ErrorEventDefinition(activity, eventDefinition) { } Object.defineProperty(ErrorEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/EscalationEventDefinition.js b/src/eventDefinitions/EscalationEventDefinition.js index fb5cbb42..43acce6d 100644 --- a/src/eventDefinitions/EscalationEventDefinition.js +++ b/src/eventDefinitions/EscalationEventDefinition.js @@ -5,6 +5,11 @@ import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT } from const K_REFERENCE = Symbol.for('reference'); +/** + * Escalation event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function EscalationEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type, behaviour = {} } = eventDefinition; @@ -34,6 +39,7 @@ export function EscalationEventDefinition(activity, eventDefinition) { } Object.defineProperty(EscalationEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/EventDefinitionExecution.js b/src/eventDefinitions/EventDefinitionExecution.js index eaecfcf7..4253972f 100644 --- a/src/eventDefinitions/EventDefinitionExecution.js +++ b/src/eventDefinitions/EventDefinitionExecution.js @@ -1,6 +1,13 @@ import { cloneContent, unshiftParent, shiftParent, cloneParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_STOPPED } from '../constants.js'; +/** + * Event definition execution orchestrator. Drives a sequence of event definitions for the + * activity and publishes the completed routing key when the last definition completes. + * @param {import('#types').Activity} activity + * @param {import('#types').EventDefinition[]} eventDefinitions + * @param {string} [completedRoutingKey] Routing key to publish on completion, defaults to `execute.completed` + */ export function EventDefinitionExecution(activity, eventDefinitions, completedRoutingKey = 'execute.completed') { this.id = activity.id; this.activity = activity; diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 149655a2..9ad5339e 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -2,6 +2,11 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_EXECUTE_MESSAGE } from '../constants.js'; +/** + * Link event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function LinkEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type = 'LinkEventDefinition', behaviour } = eventDefinition; @@ -50,6 +55,7 @@ export function LinkEventDefinition(activity, eventDefinition) { } Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/MessageEventDefinition.js b/src/eventDefinitions/MessageEventDefinition.js index dd6770c0..e0bb4639 100644 --- a/src/eventDefinitions/MessageEventDefinition.js +++ b/src/eventDefinitions/MessageEventDefinition.js @@ -3,6 +3,11 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; +/** + * Message event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function MessageEventDefinition(activity, eventDefinition) { const { id, broker, environment, isThrowing } = activity; const { type = 'MessageEventDefinition', behaviour = {} } = eventDefinition; @@ -32,6 +37,7 @@ export function MessageEventDefinition(activity, eventDefinition) { } Object.defineProperty(MessageEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/SignalEventDefinition.js b/src/eventDefinitions/SignalEventDefinition.js index 7fc50954..dd586d1c 100644 --- a/src/eventDefinitions/SignalEventDefinition.js +++ b/src/eventDefinitions/SignalEventDefinition.js @@ -3,6 +3,11 @@ import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_Q, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; +/** + * Signal event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function SignalEventDefinition(activity, eventDefinition) { const { id, broker, environment, isStart, isThrowing } = activity; const { type, behaviour = {} } = eventDefinition; @@ -32,6 +37,7 @@ export function SignalEventDefinition(activity, eventDefinition) { } Object.defineProperty(SignalEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_EXECUTE_MESSAGE]?.content.executionId; }, diff --git a/src/eventDefinitions/TerminateEventDefinition.js b/src/eventDefinitions/TerminateEventDefinition.js index 42dae166..82bbcc01 100644 --- a/src/eventDefinitions/TerminateEventDefinition.js +++ b/src/eventDefinitions/TerminateEventDefinition.js @@ -1,5 +1,10 @@ import { cloneContent, shiftParent } from '../messageHelper.js'; +/** + * Terminate event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function TerminateEventDefinition(activity, eventDefinition) { const { id, broker, environment } = activity; const { type = 'TerminateEventDefinition' } = eventDefinition; diff --git a/src/eventDefinitions/TimerEventDefinition.js b/src/eventDefinitions/TimerEventDefinition.js index 44f4b3e2..a25b0cc6 100644 --- a/src/eventDefinitions/TimerEventDefinition.js +++ b/src/eventDefinitions/TimerEventDefinition.js @@ -8,6 +8,11 @@ const K_TIMER = Symbol.for('timer'); const timerTypes = new Set(['timeDuration', 'timeDate', 'timeCycle']); +/** + * Timer event definition + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').EventDefinition} eventDefinition + */ export function TimerEventDefinition(activity, eventDefinition) { const type = (this.type = eventDefinition.type || 'TimerEventDefinition'); this.activity = activity; @@ -27,6 +32,7 @@ export function TimerEventDefinition(activity, eventDefinition) { } Object.defineProperty(TimerEventDefinition.prototype, 'executionId', { + /** @returns {string} */ get() { return this[K_TIMER_CONTENT]?.executionId; }, diff --git a/src/eventDefinitions/index.js b/src/eventDefinitions/index.js index 76581636..8b474295 100644 --- a/src/eventDefinitions/index.js +++ b/src/eventDefinitions/index.js @@ -1,22 +1,10 @@ -import { CancelEventDefinition } from './CancelEventDefinition.js'; -import { CompensateEventDefinition } from './CompensateEventDefinition.js'; -import { ConditionalEventDefinition } from './ConditionalEventDefinition.js'; -import { ErrorEventDefinition } from './ErrorEventDefinition.js'; -import { EscalationEventDefinition } from './EscalationEventDefinition.js'; -import { LinkEventDefinition } from './LinkEventDefinition.js'; -import { MessageEventDefinition } from './MessageEventDefinition.js'; -import { SignalEventDefinition } from './SignalEventDefinition.js'; -import { TerminateEventDefinition } from './TerminateEventDefinition.js'; -import { TimerEventDefinition } from './TimerEventDefinition.js'; -export { - CancelEventDefinition, - CompensateEventDefinition, - ConditionalEventDefinition, - ErrorEventDefinition, - EscalationEventDefinition, - LinkEventDefinition, - MessageEventDefinition, - SignalEventDefinition, - TerminateEventDefinition, - TimerEventDefinition, -}; +export { CancelEventDefinition } from './CancelEventDefinition.js'; +export { CompensateEventDefinition } from './CompensateEventDefinition.js'; +export { ConditionalEventDefinition } from './ConditionalEventDefinition.js'; +export { ErrorEventDefinition } from './ErrorEventDefinition.js'; +export { EscalationEventDefinition } from './EscalationEventDefinition.js'; +export { LinkEventDefinition } from './LinkEventDefinition.js'; +export { MessageEventDefinition } from './MessageEventDefinition.js'; +export { SignalEventDefinition } from './SignalEventDefinition.js'; +export { TerminateEventDefinition } from './TerminateEventDefinition.js'; +export { TimerEventDefinition } from './TimerEventDefinition.js'; diff --git a/src/events/index.js b/src/events/index.js index e3b9b309..ca874326 100644 --- a/src/events/index.js +++ b/src/events/index.js @@ -1,18 +1,5 @@ -import { BoundaryEvent, BoundaryEventBehaviour } from './BoundaryEvent.js'; -import { EndEvent, EndEventBehaviour } from './EndEvent.js'; -import { IntermediateCatchEvent, IntermediateCatchEventBehaviour } from './IntermediateCatchEvent.js'; -import { IntermediateThrowEvent, IntermediateThrowEventBehaviour } from './IntermediateThrowEvent.js'; -import { StartEvent, StartEventBehaviour } from './StartEvent.js'; - -export { - BoundaryEvent, - BoundaryEventBehaviour, - EndEvent, - EndEventBehaviour, - IntermediateCatchEvent, - IntermediateCatchEventBehaviour, - IntermediateThrowEvent, - IntermediateThrowEventBehaviour, - StartEvent, - StartEventBehaviour, -}; +export { BoundaryEvent, BoundaryEventBehaviour } from './BoundaryEvent.js'; +export { EndEvent, EndEventBehaviour } from './EndEvent.js'; +export { IntermediateCatchEvent, IntermediateCatchEventBehaviour } from './IntermediateCatchEvent.js'; +export { IntermediateThrowEvent, IntermediateThrowEventBehaviour } from './IntermediateThrowEvent.js'; +export { StartEvent, StartEventBehaviour } from './StartEvent.js'; diff --git a/src/flows/Association.js b/src/flows/Association.js index c058350d..b7ffd0ea 100644 --- a/src/flows/Association.js +++ b/src/flows/Association.js @@ -7,7 +7,7 @@ import { K_COUNTERS } from '../constants.js'; /** * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. - * @param {import('moddle-context-serializer').SerializableElement} associationDef + * @param {import('moddle-context-serializer').Association} associationDef * @param {import('#types').ContextInstance} context */ export function Association(associationDef, { environment }) { @@ -17,6 +17,7 @@ export function Association(associationDef, { environment }) { this.type = type; this.name = name; this.parent = cloneParent(parent); + /** @type {Record} */ this.behaviour = behaviour; this.sourceId = sourceId; this.targetId = targetId; diff --git a/src/flows/MessageFlow.js b/src/flows/MessageFlow.js index dca3a38b..7782199f 100644 --- a/src/flows/MessageFlow.js +++ b/src/flows/MessageFlow.js @@ -10,7 +10,7 @@ const K_SOURCE_ELEMENT = Symbol.for('sourceElement'); * Message flow connecting a source activity (or process) to a target. Subscribes to the * source's `end` event and publishes `message.outbound` whenever the source completes, * carrying any message payload through to the target. - * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('moddle-context-serializer').MessageFlow} flowDef * @param {import('#types').ContextInstance} context */ export function MessageFlow(flowDef, context) { @@ -22,6 +22,7 @@ export function MessageFlow(flowDef, context) { this.parent = cloneParent(parent); this.source = source; this.target = target; + /** @type {Record} */ this.behaviour = behaviour; this.environment = context.environment; this.context = context; diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index fa7251f8..38b5687e 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -8,7 +8,7 @@ import { K_COUNTERS } from '../constants.js'; /** * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. - * @param {import('moddle-context-serializer').SerializableElement} flowDef + * @param {import('moddle-context-serializer').SequenceFlow} flowDef * @param {import('#types').ContextInstance} context */ export function SequenceFlow(flowDef, { environment }) { @@ -18,6 +18,7 @@ export function SequenceFlow(flowDef, { environment }) { this.type = type; this.name = name; this.parent = cloneParent(parent); + /** @type {Record} */ this.behaviour = behaviour; this.sourceId = sourceId; this.targetId = targetId; @@ -186,6 +187,7 @@ SequenceFlow.prototype.getCondition = function getCondition() { /** * Build a flow event message body, optionally merging override content. * @param {Record} [override] + * @returns {import('#types').ElementMessageContent} */ SequenceFlow.prototype.createMessage = function createMessage(override) { return { @@ -204,7 +206,7 @@ SequenceFlow.prototype.createMessage = function createMessage(override) { /** * Evaluate the flow's condition for the source activity message. Default flows are always taken. * @param {import('#types').ElementBrokerMessage} fromMessage Source activity message - * @param {(err: Error | null, result?: boolean | object) => void} callback Callback with truthy result if flow should be taken + * @param {(err: Error | null, result?: boolean | unknown) => void} callback Callback with truthy result if flow should be taken */ SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) { if (this.isDefault) { diff --git a/src/io/EnvironmentDataObject.js b/src/io/EnvironmentDataObject.js index f8538f8c..fcd4a332 100644 --- a/src/io/EnvironmentDataObject.js +++ b/src/io/EnvironmentDataObject.js @@ -1,3 +1,9 @@ +/** + * Builtin data object + * @param {import('moddle-context-serializer').DataObject>} dataObjectDef + * @param {import('../Context.js').ContextInstance} context + * @satisfies {import('#types').IIOData} + */ export function EnvironmentDataObject(dataObjectDef, { environment }) { const { id, type, name, behaviour, parent } = dataObjectDef; this.id = id; diff --git a/src/messageHelper.js b/src/messageHelper.js index af1ea341..dcf81196 100644 --- a/src/messageHelper.js +++ b/src/messageHelper.js @@ -1,6 +1,13 @@ +/** + * Clone message content + * @param {import('#types').ElementMessageContent} content + * @param {Record} [extend] + * @returns cloned content + */ export function cloneContent(content, extend) { const { discardSequence, inbound, outbound, parent, sequence } = content; + /** @type {import('#types').ElementMessageContent} */ const clone = { ...content, ...extend, @@ -25,6 +32,12 @@ export function cloneContent(content, extend) { return clone; } +/** + * Clone message + * @param {import('#types').ElementBrokerMessage} message + * @param {Record} [overrideContent] + * @returns {Pick} + */ export function cloneMessage(message, overrideContent) { return { fields: { ...message.fields }, @@ -33,6 +46,11 @@ export function cloneMessage(message, overrideContent) { }; } +/** + * Clone parent + * @param {import('#types').ElementParent} parent + * @returns {import('#types').ElementParent} cloned parent + */ export function cloneParent(parent) { const { path } = parent; const clone = { ...parent }; @@ -45,6 +63,12 @@ export function cloneParent(parent) { return clone; } +/** + * Add parent to top of path + * @param {import('#types').ElementParent} parent + * @param {import('#types').ElementMessageContent} adoptingParent + * @returns {import('#types').ElementParent} + */ export function unshiftParent(parent, adoptingParent) { const { id, type, executionId } = adoptingParent; if (!parent) { @@ -67,6 +91,11 @@ export function unshiftParent(parent, adoptingParent) { return clone; } +/** + * Remove top parent from path + * @param {import('#types').ElementParent} parent + * @returns {import('#types').ElementParent} + */ export function shiftParent(parent) { if (!parent) return; if (!parent.path || !parent.path.length) return; @@ -80,6 +109,12 @@ export function shiftParent(parent) { return clone; } +/** + * Add ancestor parent at end + * @param {import('#types').ElementParent} parent + * @param {import('#types').ElementMessageContent} ancestor + * @returns {import('#types').ElementParent} + */ export function pushParent(parent, ancestor) { const { id, type, executionId } = ancestor; if (!parent) return { id, type, executionId }; diff --git a/src/process/Process.js b/src/process/Process.js index 2d272234..744c53c1 100644 --- a/src/process/Process.js +++ b/src/process/Process.js @@ -21,7 +21,7 @@ const K_LANES = Symbol.for('lanes'); /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. - * @param {import('moddle-context-serializer').MappedProcess} processDef + * @param {import('moddle-context-serializer').Process} processDef * @param {import('#types').ContextInstance} context */ export function Process(processDef, context) { @@ -29,7 +29,9 @@ export function Process(processDef, context) { this.id = id; this.type = type; this.name = name; + /** @type {import('#types').ElementParent} */ this.parent = parent ? cloneParent(parent) : {}; + /** @type {import('moddle-context-serializer').Process['behaviour']} */ this.behaviour = behaviour; this.isExecutable = behaviour.isExecutable; @@ -169,6 +171,7 @@ Process.prototype.resume = function resume() { /** * Snapshot process state for recover. + * @returns {import('#types').ProcessState} */ Process.prototype.getState = function getState() { return { @@ -484,11 +487,10 @@ Process.prototype.getSequenceFlows = function getSequenceFlows() { /** * @param {string} laneId + * @returns {import('./Lane.js') | undefined} */ Process.prototype.getLaneById = function getLaneById(laneId) { - const lanes = this[K_LANES]; - if (!lanes) return; - return lanes.find((lane) => lane.id === laneId); + return this[K_LANES]?.find((lane) => lane.id === laneId); }; /** @@ -496,16 +498,12 @@ Process.prototype.getLaneById = function getLaneById(laneId) { * @param {import('#types').filterPostponed} [filterFn] */ Process.prototype.getPostponed = function getPostponed(...args) { - const execution = this.execution; - if (!execution) return []; - return execution.getPostponed(...args); + return this.execution?.getPostponed(...args) || []; }; /** @internal */ Process.prototype._onApiMessage = function onApiMessage(routingKey, message) { - const messageType = message.properties.type; - - switch (messageType) { + switch (message.properties.type) { case 'stop': { if (this.execution && !this.execution.completed) return; this._onStop(); diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 8ca93be2..df177bf5 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -321,6 +321,7 @@ ProcessExecution.prototype.cancel = function discard() { /** * Get child activities in the process scope. + * @returns {import('#types').Activity[]} */ ProcessExecution.prototype.getActivities = function getActivities() { return this[K_ELEMENTS].children.slice(); @@ -328,6 +329,7 @@ ProcessExecution.prototype.getActivities = function getActivities() { /** * @param {string} activityId + * @returns {import('#types').Activity} */ ProcessExecution.prototype.getActivityById = function getActivityById(activityId) { return this[K_ELEMENTS].children.find((child) => child.id === activityId); @@ -335,6 +337,7 @@ ProcessExecution.prototype.getActivityById = function getActivityById(activityId /** * Get sequence flows in the process scope. + * @returns {import('#types').SequenceFlow} */ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() { return this[K_ELEMENTS].flows.slice(); @@ -342,6 +345,7 @@ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() { /** * Get associations in the process scope. + * @returns {import('../flows/Association.js').Association} */ ProcessExecution.prototype.getAssociations = function getAssociations() { return this[K_ELEMENTS].associations.slice(); @@ -350,7 +354,7 @@ ProcessExecution.prototype.getAssociations = function getAssociations() { /** * Resolve a process or child Api for the given message. * @param {import('#types').ElementBrokerMessage} [message] - * @returns {import('#types').IApi} + * @returns {import('#types').IApi} */ ProcessExecution.prototype.getApi = function getApi(message) { if (!message) return ProcessApi(this.broker, this[K_EXECUTE_MESSAGE]); diff --git a/src/shared.js b/src/shared.js index 06b49fb0..ee9ad453 100644 --- a/src/shared.js +++ b/src/shared.js @@ -8,6 +8,7 @@ export function brokerSafeId(id) { return id.replace(safePattern, '_'); } +/** @param {string} prefix */ export function getUniqueId(prefix) { return `${brokerSafeId(prefix)}_${generateId()}`; } diff --git a/src/tasks/CallActivity.js b/src/tasks/CallActivity.js index 581751af..c519dc41 100644 --- a/src/tasks/CallActivity.js +++ b/src/tasks/CallActivity.js @@ -4,7 +4,7 @@ import { cloneContent } from '../messageHelper.js'; /** * Create call activity - * @param {import('moddle-context-serializer').MappedActivity} activityDef + * @param {import('moddle-context-serializer').Activity} activityDef * @param {import('../Context.js').ContextInstance} context * @returns Call activity */ diff --git a/test/feature/escalation-feature.js b/test/feature/escalation-feature.js index 1e8bac2e..24e5c86d 100644 --- a/test/feature/escalation-feature.js +++ b/test/feature/escalation-feature.js @@ -1,5 +1,6 @@ -import CamundaExtension from '../resources/extensions/CamundaExtension.js'; import { Definition } from 'bpmn-elements'; + +import CamundaExtension from '../resources/extensions/CamundaExtension.js'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; diff --git a/test/helpers/testHelpers.js b/test/helpers/testHelpers.js index 779f7423..463b1ce2 100644 --- a/test/helpers/testHelpers.js +++ b/test/helpers/testHelpers.js @@ -1,9 +1,9 @@ -import fs from 'fs'; +import fs from 'node:fs'; import Debug from 'debug'; -import * as types from 'bpmn-elements'; import BpmnModdle from 'bpmn-moddle'; -import { Context } from '../../src/Context.js'; -import { Environment } from '../../src/Environment.js'; +import * as types from 'bpmn-elements'; + +import { Context, Environment } from 'bpmn-elements'; import { Serializer, TypeResolver } from 'moddle-context-serializer'; import { Scripts } from './JavaScripts.js'; @@ -81,6 +81,7 @@ function moddleContext(source, options = {}) { return bpmnModdle.fromXML(Buffer.isBuffer(source) ? source.toString() : source.trim()); } +/** @type {import('bpmn-elements').LoggerFactory} */ export function Logger(scope) { return { debug: Debug('bpmn-elements:' + scope), diff --git a/types/index.d.ts b/types/index.d.ts index 3d7c4f70..5ef2b19f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -24,8 +24,11 @@ declare module 'bpmn-elements' { }; export interface ElementMessageContent { + /** Element id */ id?: string; + /** Element type */ type?: string; + /** Element execution id */ executionId?: string; parent?: ElementParent; [x: string]: any; @@ -36,10 +39,10 @@ declare module 'bpmn-elements' { } export interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; + id: string; + type: string; + executionId: string; + path?: Omit[]; } // --- Element abstract bases --------------------------------------------------- @@ -423,12 +426,12 @@ declare module 'bpmn-elements' { // --- Scripts ------------------------------------------------------------------ export interface IScripts { - register(activity: any): Script | undefined; + register(activity: Activity): Script | undefined; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; } export interface Script { - execute(executionContext: any, callback: CallableFunction): void; + execute(executionContext: ExecutionScope, callback: CallableFunction): void; } // --- Generic api shape; constructed via Activity/Process/Definition/Flow Api factories. @@ -455,17 +458,11 @@ declare module 'bpmn-elements' { // --- Scope passed to user scripts/services ----------------------------------- - export interface ExecutionScope { + export interface ExecutionScope extends ElementBrokerMessage { /** Calling element id */ id: string; /** Calling element type */ type: string; - /** Execution message fields */ - fields: any; - /** Execution message content */ - content: ElementMessageContent; - /** Execution message properties */ - properties: any; environment: Environment; /** Calling element logger instance */ logger?: ILogger; @@ -486,6 +483,14 @@ declare module 'bpmn-elements' { export interface IExtensions extends IExtension { readonly count: number; } + + // --- IO --- + + export interface IIOData { + [x: string]: any; + read(broker: Broker, exchange: string, routingKeyPrefix: string, messageProperties?: Record): void; + write(broker: Broker, exchange: string, routingKeyPrefix: string, value: any, messageProperties?: Record): void; + } /** * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker. * @param Behaviour Element-specific behaviour constructor invoked per execution @@ -499,16 +504,15 @@ declare module 'bpmn-elements' { * @param activityDef Parsed BPMN element definition * @param context Per-execution registry and factory */ - constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); - id: string | undefined; - type: string; + constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").Activity, context: ContextInstance); + id: any; + type: any; name: any; - behaviour: { - eventDefinitions: any; - }; + behaviour: any; Behaviour: IActivityBehaviour; parent: import("moddle-context-serializer").Parent; + logger: ILogger; environment: Environment; context: ContextInstance; @@ -569,7 +573,7 @@ declare module 'bpmn-elements' { * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). * @returns count of subscribed triggers */ - addInboundListeners(): any; + addInboundListeners(): number; /** * Cancel inbound trigger subscriptions added by addInboundListeners. */ @@ -624,7 +628,7 @@ declare module 'bpmn-elements' { get triggeredByEvent(): boolean; get attachedTo(): Activity | null; get lane(): Lane | undefined; - get eventDefinitions(): any[]; + get eventDefinitions(): EventDefinition[] | undefined; get parentElement(): Activity | Process; get initialized(): boolean; } @@ -640,7 +644,7 @@ declare module 'bpmn-elements' { constructor(activity: Activity, context: ContextInstance); activity: Activity; context: ContextInstance; - id: string | undefined; + id: any; broker: import("smqp").Broker; get completed(): boolean; /** @@ -669,15 +673,15 @@ declare module 'bpmn-elements' { /** * Pass an execute message straight to the behaviour, executing first if no source is set up yet. * */ - passthrough(executeMessage: ElementBrokerMessage): any; + passthrough(executeMessage: ElementBrokerMessage): void; /** * List currently postponed executions as Api wrappers, including those from sub-process behaviours. */ getPostponed(): IApi[]; /** * Snapshot execution state, merging behaviour-specific state when the source provides it. - */ - getState(): any; + * */ + getState(): ActivityExecutionState; /** * Restore execution state captured by getState. * */ @@ -718,12 +722,12 @@ declare module 'bpmn-elements' { id: string; name: string; type: string; + /** Unique instance id */ sid: string; definitionContext: import("moddle-context-serializer").SerializableContext; environment: Environment; extensionsMapper: IExtensionsMapper; - refs: Map>; get owner(): Activity | Process | undefined; /** * Get or create the activity instance for the given id. @@ -738,13 +742,13 @@ declare module 'bpmn-elements' { * */ getSequenceFlowById(sequenceFlowId: string): SequenceFlow | null; - getInboundSequenceFlows(activityId: string): any[]; + getInboundSequenceFlows(activityId: string): SequenceFlow[]; - getOutboundSequenceFlows(activityId: string): any[]; + getOutboundSequenceFlows(activityId: string): SequenceFlow[]; - getInboundAssociations(activityId: string): any[]; + getInboundAssociations(activityId: string): Association[]; - getOutboundAssociations(activityId: string): any[]; + getOutboundAssociations(activityId: string): Association[]; /** * Get every activity in the definition, optionally narrowed to a parent scope. * @param scopeId Process or sub-process id @@ -754,17 +758,18 @@ declare module 'bpmn-elements' { * Get every sequence flow in the definition, optionally narrowed to a parent scope. * @param scopeId Process or sub-process id */ - getSequenceFlows(scopeId?: string): any[]; + getSequenceFlows(scopeId?: string): SequenceFlow[]; /** * Return the cached sequence flow, instantiating it the first time it is referenced. * */ - upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): any; + upsertSequenceFlow(flowDefinition: import("moddle-context-serializer").SerializableElement): SequenceFlow; /** + * Get association flows * @param scopeId Process or sub-process id */ - getAssociations(scopeId?: string): any[]; + getAssociations(scopeId?: string): Association[]; - upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): any; + upsertAssociation(associationDefinition: import("moddle-context-serializer").SerializableElement): Association; /** * Create a new context that shares the parsed definition but optionally swaps environment and owner. * @@ -777,28 +782,28 @@ declare module 'bpmn-elements' { /** * Build a fresh, uncached process instance for the given id. Used by call activities. * */ - getNewProcessById(processId: string): any; + getNewProcessById(processId: string): Process | null; /** * Get every process in the definition. - */ - getProcesses(): (Process | null)[]; + * */ + getProcesses(): Process[]; /** * Get processes flagged executable in the definition. - */ - getExecutableProcesses(): (Process | null)[]; + * */ + getExecutableProcesses(): Process[]; /** * Get message flows that originate from the given process id. * @param sourceId Source process id - */ - getMessageFlows(sourceId: string): any[]; + * */ + getMessageFlows(sourceId: string): MessageFlow[]; /** * Get or create a data object instance for the given reference id. * */ - getDataObjectById(referenceId: string): any; + getDataObjectById(referenceId: string): IIOData | undefined; /** * Get or create a data store instance for the given reference id. * */ - getDataStoreById(referenceId: string): any; + getDataStoreById(referenceId: string): IIOData | undefined; /** * Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. * @param scopeId Process or sub-process id @@ -827,9 +832,11 @@ declare module 'bpmn-elements' { */ constructor(context: ContextInstance, options?: EnvironmentOptions); id: string | undefined; - type: string | undefined; + + type: string; name: string | undefined; - environment: any; + + environment: Environment; context: ContextInstance | undefined; broker: import("smqp").Broker; @@ -858,8 +865,8 @@ declare module 'bpmn-elements' { resume(callback?: runCallback): this; /** * Snapshot definition state for recover. - */ - getState(): any; + * */ + getState(): DefinitionState; /** * Restore definition state captured by getState. * @throws {Error} when called on a running definition @@ -874,21 +881,21 @@ declare module 'bpmn-elements' { /** * Get every process in the definition. */ - getProcesses(): any[]; + getProcesses(): Process[]; /** * Get processes flagged executable in the definition. */ - getExecutableProcesses(): any[]; + getExecutableProcesses(): Process[]; /** * Get processes that are currently running. */ - getRunningProcesses(): any[]; + getRunningProcesses(): Process[]; - getProcessById(processId: string): any; + getProcessById(processId: string): Process | undefined; /** * Find an activity by id across all processes in the definition. * */ - getActivityById(childId: string): any; + getActivityById(childId: string): Activity | null; /** * Lookup any element (activity, flow, etc.) in the parsed definition by id. * */ @@ -947,9 +954,9 @@ declare module 'bpmn-elements' { * */ constructor(definition: Definition, context: ContextInstance); id: string | undefined; - type: string | undefined; + type: string; broker: import("smqp").Broker; - environment: any; + environment: Environment; context: ContextInstance; executionId: string | undefined; /** @@ -972,34 +979,28 @@ declare module 'bpmn-elements' { stop(): void; /** * Get every process in the definition (running first, then any non-running by id). - */ - getProcesses(): any[]; + * */ + getProcesses(): Process[]; - getProcessById(processId: string): any; + getProcessById(processId: string): Process | undefined; /** * Get every process matching the given id (call activities can spawn duplicates). * */ - getProcessesById(processId: string): any[]; + getProcessesById(processId: string): Process[]; - getProcessByExecutionId(processExecutionId: string): any; + getProcessByExecutionId(processExecutionId: string): Process | undefined; /** * Get processes that have an executionId, i.e. are currently running. - */ - getRunningProcesses(): any[]; + * */ + getRunningProcesses(): Process[]; /** * Get processes flagged executable in the definition. - */ - getExecutableProcesses(): any[]; + * */ + getExecutableProcesses(): Process[]; /** * Snapshot execution state for recover. - */ - getState(): { - executionId: string | undefined; - stopped: any; - completed: any; - status: any; - processes: any[]; - }; + * */ + getState(): DefinitionExecutionState; /** * Resolve a Definition Api or, when the message belongs to a child process, its process Api. * */ @@ -1022,7 +1023,7 @@ declare module 'bpmn-elements' { type: any; name: any; behaviour: any; - parent: any; + parent: ElementParent; placeholder: boolean; }; /** @@ -1057,21 +1058,8 @@ declare module 'bpmn-elements' { get services(): Record; /** * Snapshot environment state for recover. - */ - getState(): { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; + * */ + getState(): EnvironmentState; /** * Restore environment state captured by getState. Merges into the existing settings, * variables, and output rather than replacing them. @@ -1114,16 +1102,22 @@ declare module 'bpmn-elements' { * */ addService(name: string, fn: CallableFunction): void; } + /** + * Builtin data object + * @param >} dataObjectDef + * */ export class DataObject { - constructor(dataObjectDef: any, { environment }: { - environment: any; - }); + /** + * Builtin data object + * @param >} dataObjectDef + * */ + constructor(dataObjectDef: any, { environment }: ContextInstance); id: any; type: any; name: any; behaviour: any; parent: any; - environment: any; + environment: Environment; read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; } @@ -1191,8 +1185,8 @@ declare module 'bpmn-elements' { type: string | undefined; name: any; parent: { - id: string | undefined; - type: string; + id: any; + type: any; }; behaviour: { [x: string]: any; @@ -1233,12 +1227,14 @@ declare module 'bpmn-elements' { * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. * */ - constructor(processDef: import("moddle-context-serializer").MappedProcess, context: ContextInstance); - id: string | undefined; - type: string; + constructor(processDef: import("moddle-context-serializer").Process, context: ContextInstance); + id: any; + type: any; name: any; - parent: any; - behaviour: {}; + + parent: ElementParent; + + behaviour: import("moddle-context-serializer").Process["behaviour"]; isExecutable: any; environment: Environment; context: ContextInstance; @@ -1270,62 +1266,8 @@ declare module 'bpmn-elements' { resume(): this; /** * Snapshot process state for recover. - */ - getState(): { - id: string | undefined; - type: string; - executionId: string | undefined; - environment: { - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; - variables: { - [x: string]: any; - }; - output: any; - }; - status: string | undefined; - stopped: boolean; - counters: { - completed: number; - discarded: number; - }; - broker: { - exchanges: { - bindings?: { - id: string; - options: { - priority: number; - }; - queueName: string; - pattern: string; - }[] | undefined; - deliveryQueue?: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - } | undefined; - name: string; - type: import("smqp").exchangeType; - options: { - [x: string]: any; - durable?: boolean; - autoDelete?: boolean; - }; - }[] | undefined; - queues: { - name: string; - options: import("smqp").QueueOptions; - messages?: import("smqp").MessageEnvelope[]; - }[] | undefined; - } | undefined; - execution: ProcessExecutionState | undefined; - }; + * */ + getState(): ProcessState; /** * Restore process state captured by getState. * @throws {Error} when called on a running process @@ -1360,11 +1302,11 @@ declare module 'bpmn-elements' { * */ sendMessage(message: ElementBrokerMessage): void; - getActivityById(childId: string): any; + getActivityById(childId: string): Activity | null; /** * Get every activity in the process scope. */ - getActivities(): any; + getActivities(): Activity[]; /** * Get start activities, optionally filtered by referenced event definition. * @@ -1373,14 +1315,14 @@ declare module 'bpmn-elements' { /** * Get sequence flows in the process scope. */ - getSequenceFlows(): any; + getSequenceFlows(): SequenceFlow | SequenceFlow[]; getLaneById(laneId: string): any; /** * List currently postponed activities as Api wrappers. * */ - getPostponed(...args: any[]): any[]; + getPostponed(...args: any[]): IApi[]; get counters(): { completed: number; discarded: number; @@ -1446,11 +1388,7 @@ declare module 'bpmn-elements' { type: string; name: any; description: any; - source: { - fields: any; - content: any; - properties: any; - } | undefined; + source: any; inner: any; code: any; } @@ -1467,8 +1405,8 @@ declare module 'bpmn-elements' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; + id: any; + type: any; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -1506,7 +1444,7 @@ declare module 'bpmn-elements' { * List currently postponed children as Api wrappers. * */ - getPostponed(filterFn?: filterPostponed): any[]; + getPostponed(filterFn?: filterPostponed): IApi[]; /** * Queue a discard message that propagates to all running children. */ @@ -1517,18 +1455,18 @@ declare module 'bpmn-elements' { cancel(): any; /** * Get child activities in the process scope. - */ - getActivities(): any; + * */ + getActivities(): Activity[]; - getActivityById(activityId: string): any; + getActivityById(activityId: string): Activity; /** * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; + * */ + getSequenceFlows(): SequenceFlow; /** * Get associations in the process scope. - */ - getAssociations(): any; + * */ + getAssociations(): Association; /** * Resolve a process or child Api for the given message. * */ @@ -1549,12 +1487,12 @@ declare module 'bpmn-elements' { * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); - id: string | undefined; - type: string; + constructor(flowDef: import("moddle-context-serializer").SequenceFlow, { environment }: ContextInstance); + id: any; + type: any; name: any; - parent: any; - behaviour: Record; + parent: ElementParent; + behaviour: any; sourceId: any; targetId: any; isDefault: any; @@ -1616,24 +1554,14 @@ declare module 'bpmn-elements' { getCondition(): ISequenceFlowCondition | null; /** * Build a flow event message body, optionally merging override content. - * - */ - createMessage(override?: Record): { - id: string | undefined; - type: string; - name: any; - sourceId: any; - targetId: any; - isSequenceFlow: boolean; - isDefault: any; - parent: any; - }; + * */ + createMessage(override?: Record): ElementMessageContent; /** * Evaluate the flow's condition for the source activity message. Default flows are always taken. * @param fromMessage Source activity message * @param callback Callback with truthy result if flow should be taken */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | unknown) => void): void; } /** * Enriches an element run message via async format start/end messages on the `format` exchange @@ -1655,10 +1583,6 @@ declare module 'bpmn-elements' { * formatting completes; `formatted` is true when content was actually enriched. * */ format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; - } - class Scripts { - getScript(): void; - register(): void; } /** * Association connecting a source and target activity. Used to drive compensation — @@ -1673,7 +1597,7 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; name: any; - parent: any; + parent: ElementParent; behaviour: Record; sourceId: any; targetId: any; @@ -1736,7 +1660,7 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; name: any; - parent: any; + parent: ElementParent; source: any; target: any; behaviour: Record; @@ -1777,6 +1701,10 @@ declare module 'bpmn-elements' { * Cancel the source element subscriptions added by activate. */ deactivate(): void; + } + class Scripts { + getScript(): void; + register(): void; } export function BoundaryEvent(activityDef: any, context: any): Activity; export function EndEvent(activityDef: any, context: any): Activity; @@ -1788,13 +1716,13 @@ declare module 'bpmn-elements' { export function InclusiveGateway(activityDef: any, context: any): Activity; export class ParallelGateway { constructor(activityDef: any, context: any); - id: string | undefined; + id: any; } /** * Create call activity * @returns Call activity */ - export function CallActivity(activityDef: import("moddle-context-serializer").MappedActivity, context: ContextInstance): Activity; + export function CallActivity(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; export function ReceiveTask(activityDef: any, context: any): Activity; export function ScriptTask(activityDef: any, context: any): Activity; export function SendTask(activityDef: any, context: any): Activity; @@ -1958,7 +1886,7 @@ declare module 'bpmn-elements' { timeDate: any; broker: any; logger: any; - get executionId(): any; + get executionId(): string | undefined; get stopped(): boolean; get timer(): any; execute(executeMessage: any): void; @@ -2011,11 +1939,7 @@ declare module 'bpmn-elements/errors' { type: string; name: any; description: any; - source: { - fields: any; - content: any; - properties: any; - } | undefined; + source: any; inner: any; code: any; } @@ -2029,11 +1953,7 @@ declare module 'bpmn-elements/errors' { description: any; code: any; id: any; - source: { - fields: any; - content: any; - properties: any; - } | undefined; + source: any; inner: any; } @@ -2043,7 +1963,7 @@ declare module 'bpmn-elements/errors' { declare module 'bpmn-elements/events' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; export function BoundaryEvent(activityDef: any, context: any): Activity; export class BoundaryEventBehaviour { @@ -2123,8 +2043,8 @@ declare module 'bpmn-elements/events' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; + id: any; + type: any; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -2162,7 +2082,7 @@ declare module 'bpmn-elements/events' { * List currently postponed children as Api wrappers. * */ - getPostponed(filterFn?: filterPostponed): any[]; + getPostponed(filterFn?: filterPostponed): IApi[]; /** * Queue a discard message that propagates to all running children. */ @@ -2173,18 +2093,18 @@ declare module 'bpmn-elements/events' { cancel(): any; /** * Get child activities in the process scope. - */ - getActivities(): any; + * */ + getActivities(): Activity[]; - getActivityById(activityId: string): any; + getActivityById(activityId: string): Activity; /** * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; + * */ + getSequenceFlows(): SequenceFlow; /** * Get associations in the process scope. - */ - getAssociations(): any; + * */ + getAssociations(): Association; /** * Resolve a process or child Api for the given message. * */ @@ -2223,7 +2143,7 @@ declare module 'bpmn-elements/events' { declare module 'bpmn-elements/eventDefinitions' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; export class CancelEventDefinition { constructor(activity: any, eventDefinition: any); @@ -2381,7 +2301,7 @@ declare module 'bpmn-elements/eventDefinitions' { timeDate: any; broker: any; logger: any; - get executionId(): any; + get executionId(): string | undefined; get stopped(): boolean; get timer(): any; execute(executeMessage: any): void; @@ -2433,8 +2353,8 @@ declare module 'bpmn-elements/eventDefinitions' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; + id: any; + type: any; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -2472,7 +2392,7 @@ declare module 'bpmn-elements/eventDefinitions' { * List currently postponed children as Api wrappers. * */ - getPostponed(filterFn?: filterPostponed): any[]; + getPostponed(filterFn?: filterPostponed): IApi[]; /** * Queue a discard message that propagates to all running children. */ @@ -2483,18 +2403,18 @@ declare module 'bpmn-elements/eventDefinitions' { cancel(): any; /** * Get child activities in the process scope. - */ - getActivities(): any; + * */ + getActivities(): Activity[]; - getActivityById(activityId: string): any; + getActivityById(activityId: string): Activity; /** * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; + * */ + getSequenceFlows(): SequenceFlow; /** * Get associations in the process scope. - */ - getAssociations(): any; + * */ + getAssociations(): Association; /** * Resolve a process or child Api for the given message. * */ @@ -2554,7 +2474,7 @@ declare module 'bpmn-elements/eventDefinitions' { declare module 'bpmn-elements/flows' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; /** * Association connecting a source and target activity. Used to drive compensation — @@ -2569,7 +2489,7 @@ declare module 'bpmn-elements/flows' { id: string | undefined; type: string; name: any; - parent: any; + parent: ElementParent; behaviour: Record; sourceId: any; targetId: any; @@ -2632,7 +2552,7 @@ declare module 'bpmn-elements/flows' { id: string | undefined; type: string; name: any; - parent: any; + parent: ElementParent; source: any; target: any; behaviour: Record; @@ -2683,12 +2603,12 @@ declare module 'bpmn-elements/flows' { * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped * events; activities subscribe to drive their inbound queue. * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); - id: string | undefined; - type: string; + constructor(flowDef: import("moddle-context-serializer").SequenceFlow, { environment }: ContextInstance); + id: any; + type: any; name: any; - parent: any; - behaviour: Record; + parent: ElementParent; + behaviour: any; sourceId: any; targetId: any; isDefault: any; @@ -2750,24 +2670,14 @@ declare module 'bpmn-elements/flows' { getCondition(): ISequenceFlowCondition | null; /** * Build a flow event message body, optionally merging override content. - * - */ - createMessage(override?: Record): { - id: string | undefined; - type: string; - name: any; - sourceId: any; - targetId: any; - isSequenceFlow: boolean; - isDefault: any; - parent: any; - }; + * */ + createMessage(override?: Record): ElementMessageContent; /** * Evaluate the flow's condition for the source activity message. Default flows are always taken. * @param fromMessage Source activity message * @param callback Callback with truthy result if flow should be taken */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | object) => void): void; + evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | unknown) => void): void; } /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -2779,8 +2689,8 @@ declare module 'bpmn-elements/flows' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; + id: any; + type: any; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -2818,7 +2728,7 @@ declare module 'bpmn-elements/flows' { * List currently postponed children as Api wrappers. * */ - getPostponed(filterFn?: filterPostponed): any[]; + getPostponed(filterFn?: filterPostponed): IApi[]; /** * Queue a discard message that propagates to all running children. */ @@ -2829,18 +2739,18 @@ declare module 'bpmn-elements/flows' { cancel(): any; /** * Get child activities in the process scope. - */ - getActivities(): any; + * */ + getActivities(): Activity[]; - getActivityById(activityId: string): any; + getActivityById(activityId: string): Activity; /** * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; + * */ + getSequenceFlows(): SequenceFlow; /** * Get associations in the process scope. - */ - getAssociations(): any; + * */ + getAssociations(): Association; /** * Resolve a process or child Api for the given message. * */ @@ -2900,7 +2810,7 @@ declare module 'bpmn-elements/flows' { declare module 'bpmn-elements/gateways' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; export function EventBasedGateway(activityDef: any, context: any): Activity; export class EventBasedGatewayBehaviour { @@ -2934,7 +2844,7 @@ declare module 'bpmn-elements/gateways' { } export class ParallelGateway { constructor(activityDef: any, context: any); - id: string | undefined; + id: any; } export class ParallelGatewayBehaviour { constructor(activity: any); @@ -2998,8 +2908,8 @@ declare module 'bpmn-elements/gateways' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; + id: any; + type: any; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -3037,7 +2947,7 @@ declare module 'bpmn-elements/gateways' { * List currently postponed children as Api wrappers. * */ - getPostponed(filterFn?: filterPostponed): any[]; + getPostponed(filterFn?: filterPostponed): IApi[]; /** * Queue a discard message that propagates to all running children. */ @@ -3048,18 +2958,18 @@ declare module 'bpmn-elements/gateways' { cancel(): any; /** * Get child activities in the process scope. - */ - getActivities(): any; + * */ + getActivities(): Activity[]; - getActivityById(activityId: string): any; + getActivityById(activityId: string): Activity; /** * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; + * */ + getSequenceFlows(): SequenceFlow; /** * Get associations in the process scope. - */ - getAssociations(): any; + * */ + getAssociations(): Association; /** * Resolve a process or child Api for the given message. * */ @@ -3098,13 +3008,13 @@ declare module 'bpmn-elements/gateways' { declare module 'bpmn-elements/tasks' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; /** * Create call activity * @returns Call activity */ - export function CallActivity(activityDef: import("moddle-context-serializer").MappedActivity, context: ContextInstance): Activity; + export function CallActivity(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; export class CallActivityBehaviour { constructor(activity: any); id: any; @@ -3237,8 +3147,8 @@ declare module 'bpmn-elements/tasks' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; + id: any; + type: any; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -3276,7 +3186,7 @@ declare module 'bpmn-elements/tasks' { * List currently postponed children as Api wrappers. * */ - getPostponed(filterFn?: filterPostponed): any[]; + getPostponed(filterFn?: filterPostponed): IApi[]; /** * Queue a discard message that propagates to all running children. */ @@ -3287,18 +3197,18 @@ declare module 'bpmn-elements/tasks' { cancel(): any; /** * Get child activities in the process scope. - */ - getActivities(): any; + * */ + getActivities(): Activity[]; - getActivityById(activityId: string): any; + getActivityById(activityId: string): Activity; /** * Get sequence flows in the process scope. - */ - getSequenceFlows(): any; + * */ + getSequenceFlows(): SequenceFlow; /** * Get associations in the process scope. - */ - getAssociations(): any; + * */ + getAssociations(): Association; /** * Resolve a process or child Api for the given message. * */ diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index 451a1061..a7385139 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -42,7 +42,7 @@ declare module '../src/activity/Activity.js' { get triggeredByEvent(): boolean; get attachedTo(): Activity | null; get lane(): Lane | undefined; - get eventDefinitions(): any[]; + get eventDefinitions(): EventDefinition[] | undefined; get parentElement(): Activity | Process; get initialized(): boolean; } @@ -120,8 +120,11 @@ export type signalMessage = { }; export interface ElementMessageContent { + /** Element id */ id?: string; + /** Element type */ type?: string; + /** Element execution id */ executionId?: string; parent?: ElementParent; [x: string]: any; @@ -132,10 +135,10 @@ export interface ElementBrokerMessage extends MessageEnvelope { } export interface ElementParent { - get id(): string; - get type(): string; - get executionId(): string; - get path(): ElementParent[]; + id: string; + type: string; + executionId: string; + path?: Omit[]; } // --- Element abstract bases --------------------------------------------------- @@ -519,12 +522,12 @@ export interface TimersOptions { // --- Scripts ------------------------------------------------------------------ export interface IScripts { - register(activity: any): Script | undefined; + register(activity: Activity): Script | undefined; getScript(language: string, identifier: { id: string; [x: string]: any }): Script; } export interface Script { - execute(executionContext: any, callback: CallableFunction): void; + execute(executionContext: ExecutionScope, callback: CallableFunction): void; } // --- Generic api shape; constructed via Activity/Process/Definition/Flow Api factories. @@ -551,17 +554,11 @@ export interface IApi extends ElementBrokerMessage { // --- Scope passed to user scripts/services ----------------------------------- -export interface ExecutionScope { +export interface ExecutionScope extends ElementBrokerMessage { /** Calling element id */ id: string; /** Calling element type */ type: string; - /** Execution message fields */ - fields: any; - /** Execution message content */ - content: ElementMessageContent; - /** Execution message properties */ - properties: any; environment: Environment; /** Calling element logger instance */ logger?: ILogger; @@ -582,3 +579,11 @@ export interface IExtensionsMapper { export interface IExtensions extends IExtension { readonly count: number; } + +// --- IO --- + +export interface IIOData { + [x: string]: any; + read(broker: Broker, exchange: string, routingKeyPrefix: string, messageProperties?: Record): void; + write(broker: Broker, exchange: string, routingKeyPrefix: string, value: any, messageProperties?: Record): void; +} From 270fc9c9265d1738902bac1be77fdd8b431ce114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 30 May 2026 06:45:55 +0200 Subject: [PATCH 15/31] type annotate activities --- dist/Environment.js | 16 +- dist/Timers.js | 5 + dist/activity/Dummy.js | 5 + dist/definition/Definition.js | 2 + dist/error/BpmnError.js | 11 + dist/error/Errors.js | 59 +- .../eventDefinitions/CancelEventDefinition.js | 15 +- .../CompensateEventDefinition.js | 22 +- .../ConditionalEventDefinition.js | 4 + dist/eventDefinitions/ErrorEventDefinition.js | 22 +- .../EscalationEventDefinition.js | 22 +- .../EventDefinitionExecution.js | 4 + dist/eventDefinitions/LinkEventDefinition.js | 14 + .../MessageEventDefinition.js | 22 +- .../eventDefinitions/SignalEventDefinition.js | 22 +- .../TerminateEventDefinition.js | 4 + dist/eventDefinitions/TimerEventDefinition.js | 20 +- dist/events/BoundaryEvent.js | 16 + dist/events/EndEvent.js | 15 + dist/events/IntermediateCatchEvent.js | 15 + dist/events/IntermediateThrowEvent.js | 15 + dist/events/StartEvent.js | 15 + dist/gateways/EventBasedGateway.js | 16 + dist/gateways/ExclusiveGateway.js | 15 + dist/gateways/InclusiveGateway.js | 15 + dist/gateways/ParallelGateway.js | 16 + dist/io/BpmnIO.js | 14 + dist/io/EnvironmentDataObject.js | 23 +- dist/io/EnvironmentDataStore.js | 23 + dist/io/EnvironmentDataStoreReference.js | 23 + dist/io/InputOutputSpecification.js | 11 + dist/io/Properties.js | 12 + dist/process/Lane.js | 3 + dist/process/Process.js | 3 +- dist/process/ProcessExecution.js | 5 +- dist/tasks/CallActivity.js | 16 +- dist/tasks/LoopCharacteristics.js | 101 +- dist/tasks/ReceiveTask.js | 15 + dist/tasks/ScriptTask.js | 15 + dist/tasks/ServiceImplementation.js | 4 + dist/tasks/ServiceTask.js | 15 + dist/tasks/SignalTask.js | 15 + dist/tasks/StandardLoopCharacteristics.js | 5 + dist/tasks/SubProcess.js | 17 + dist/tasks/Task.js | 15 + dist/tasks/Transaction.js | 5 + docs/Examples.md | 2 +- docs/Extend.md | 4 +- docs/Extension.md | 2 +- docs/SignalTask.md | 2 +- docs/StartEvent.md | 2 +- package.json | 4 +- src/Environment.js | 14 +- src/Timers.js | 4 + src/activity/Dummy.js | 5 + src/definition/Definition.js | 2 + src/error/BpmnError.js | 10 + src/error/Errors.js | 49 +- src/eventDefinitions/CancelEventDefinition.js | 12 +- .../CompensateEventDefinition.js | 17 +- .../ConditionalEventDefinition.js | 3 + src/eventDefinitions/ErrorEventDefinition.js | 20 +- .../EscalationEventDefinition.js | 20 +- .../EventDefinitionExecution.js | 3 + src/eventDefinitions/LinkEventDefinition.js | 10 + .../MessageEventDefinition.js | 20 +- src/eventDefinitions/SignalEventDefinition.js | 20 +- .../TerminateEventDefinition.js | 3 + src/eventDefinitions/TimerEventDefinition.js | 17 +- src/events/BoundaryEvent.js | 13 + src/events/EndEvent.js | 13 + src/events/IntermediateCatchEvent.js | 13 + src/events/IntermediateThrowEvent.js | 13 + src/events/StartEvent.js | 13 + src/gateways/EventBasedGateway.js | 14 + src/gateways/ExclusiveGateway.js | 13 + src/gateways/InclusiveGateway.js | 13 + src/gateways/ParallelGateway.js | 13 + src/io/BpmnIO.js | 12 + src/io/EnvironmentDataObject.js | 21 +- src/io/EnvironmentDataStore.js | 21 + src/io/EnvironmentDataStoreReference.js | 21 + src/io/InputOutputSpecification.js | 10 + src/io/Properties.js | 10 + src/process/Lane.js | 3 + src/process/Process.js | 3 +- src/process/ProcessExecution.js | 6 +- src/tasks/CallActivity.js | 14 +- src/tasks/LoopCharacteristics.js | 86 +- src/tasks/ReceiveTask.js | 13 + src/tasks/ScriptTask.js | 13 + src/tasks/ServiceImplementation.js | 4 + src/tasks/ServiceTask.js | 13 + src/tasks/SignalTask.js | 13 + src/tasks/StandardLoopCharacteristics.js | 5 + src/tasks/SubProcess.js | 14 + src/tasks/Task.js | 13 + src/tasks/Transaction.js | 5 + test/activities-test.js | 2 +- test/error/BpmnError-test.js | 1 + test/feature/errors-feature.js | 67 + test/helpers/testHelpers.js | 2 +- types/bundle.d.ts | 1 - types/index.d.ts | 2132 ++++++++++------- types/interfaces.d.ts | 35 +- 105 files changed, 2726 insertions(+), 924 deletions(-) diff --git a/dist/Environment.js b/dist/Environment.js index 62252afe..a681a299 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -18,15 +18,21 @@ const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', */ function Environment(options = {}) { this.options = validateOptions(options); + + /** @type {import('#types').IExpressions} */ this.expressions = options.expressions || (0, _Expressions.Expressions)(); this.extensions = options.extensions; this.output = options.output || {}; + /** @type {import('#types').IScripts} */ this.scripts = options.scripts || new _Scripts.Scripts(); + /** @type {import('#types').ITimers} */ this.timers = options.timers || new _Timers.Timers(); + /** @type {import('#types').EnvironmentSettings} */ this.settings = { skipDiscard: true, ...options.settings }; + /** @type {import('#types').LoggerFactory} */ this.Logger = options.Logger || DummyLogger; this[K_SERVICES] = options.services || {}; this[K_VARIABLES] = options.variables || {}; @@ -87,6 +93,7 @@ Environment.prototype.recover = function recover(state) { * Clone the environment, optionally overriding options. Services are merged when * `overrideOptions.services` is supplied. * @param {import('#types').EnvironmentOptions} [overrideOptions] + * @returns {Environment} */ Environment.prototype.clone = function clone(overrideOptions) { const services = this[K_SERVICES]; @@ -180,12 +187,17 @@ Environment.prototype.resolveExpression = function resolveExpression(expression, /** * Register a service callable by name. - * @param {string} name - * @param {CallableFunction} fn + * @param {string} name service function name + * @param {CallableFunction} fn service function */ Environment.prototype.addService = function addService(name, fn) { this[K_SERVICES][name] = fn; }; + +/** + * @param {import('#types').EnvironmentOptions} input + * @returns {import('#types').EnvironmentOptions} validated options + */ function validateOptions(input) { const options = {}; for (const key in input) { diff --git a/dist/Timers.js b/dist/Timers.js index de4a9669..227f3e8c 100644 --- a/dist/Timers.js +++ b/dist/Timers.js @@ -7,6 +7,11 @@ exports.Timers = Timers; const K_EXECUTING = Symbol.for('executing'); const K_TIMER_API = Symbol.for('timers api'); const MAX_DELAY = 2147483647; + +/** + * + * @param {*} options + */ function Timers(options) { this.count = 0; this.options = { diff --git a/dist/activity/Dummy.js b/dist/activity/Dummy.js index dff7325c..bcce8510 100644 --- a/dist/activity/Dummy.js +++ b/dist/activity/Dummy.js @@ -5,6 +5,11 @@ Object.defineProperty(exports, "__esModule", { }); exports.DummyActivity = DummyActivity; var _messageHelper = require("../messageHelper.js"); +/** + * Placeholder activity for non-executable elements (text annotations, groups, categories). + * @param {import('moddle-context-serializer').Activity} activityDef + * @returns {{ id: string, type: string, name: string | undefined, behaviour: Record, parent: import('#types').ElementParent, placeholder: true }} + */ function DummyActivity(activityDef) { const { id, diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index 449c3359..53f952db 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -218,8 +218,10 @@ Definition.prototype.recover = function recover(state) { * Walk activity graphs to discover sequences. Limited to the activity's owning process * when startId is given, otherwise all processes are shaken. * @param {string} [startId] + * @returns {import('#types').ShakeResult | undefined} */ Definition.prototype.shake = function shake(startId) { + /** @type {import('#types').ShakeResult} */ let result = {}; let bps; if (startId) { diff --git a/dist/error/BpmnError.js b/dist/error/BpmnError.js index d0e64aed..8d7d5b68 100644 --- a/dist/error/BpmnError.js +++ b/dist/error/BpmnError.js @@ -4,6 +4,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.BpmnErrorActivity = BpmnErrorActivity; +/** + * BPMN error. + * @param {import('moddle-context-serializer').SerializableElement} errorDef + * @param {import('#types').ContextInstance} context + */ function BpmnErrorActivity(errorDef, context) { const { id, @@ -21,11 +26,17 @@ function BpmnErrorActivity(errorDef, context) { errorCode: behaviour.errorCode, resolve }; + + /** + * @param {import('#types').ElementBrokerMessage} executionMessage + * @param {Error} [error] + */ function resolve(executionMessage, error) { const resolveCtx = { ...executionMessage, error }; + /** @type {{ id?: string; type?: string; messageType: string; name: string; code: string | undefined; inner?: Error }} */ const result = { id, type, diff --git a/dist/error/Errors.js b/dist/error/Errors.js index b27bf294..d0b55d93 100644 --- a/dist/error/Errors.js +++ b/dist/error/Errors.js @@ -7,23 +7,41 @@ exports.RunError = exports.BpmnError = exports.ActivityError = void 0; exports.makeErrorFromMessage = makeErrorFromMessage; var _messageHelper = require("../messageHelper.js"); class ActivityError extends Error { + /** + * @param {string} description + * @param {import('#types').ElementBrokerMessage} [sourceMessage] + * @param {Error | { name?: string; code?: string | number }} [inner] + */ constructor(description, sourceMessage, inner) { super(description); + /** @type {string} */ this.type = 'ActivityError'; + /** @type {string} */ this.name = this.constructor.name; + /** @type {string} */ this.description = description; - if (sourceMessage) this.source = (0, _messageHelper.cloneMessage)(sourceMessage, sourceMessage.content?.error && { - error: undefined - }); + if (sourceMessage) { + /** @type {Pick | undefined} */ + this.source = (0, _messageHelper.cloneMessage)(sourceMessage, sourceMessage.content?.error && { + error: undefined + }); + } if (inner) { + /** @type {Error | { name?: string; code?: string | number } | undefined} */ this.inner = inner; if (inner.name) this.name = inner.name; - if (inner.code) this.code = inner.code; + if ('code' in inner && inner.code) { + /** @type {string | number | undefined} */ + this.code = inner.code; + } } } } exports.ActivityError = ActivityError; class RunError extends ActivityError { + /** + * @param {ConstructorParameters} args + */ constructor(...args) { super(...args); this.type = 'RunError'; @@ -31,19 +49,37 @@ class RunError extends ActivityError { } exports.RunError = RunError; class BpmnError extends Error { - constructor(description, behaviour, sourceMessage, inner) { + /** + * @param {string} description + * @param {{ id?: string; name?: string; errorCode?: string | number; code?: string }} [behaviour] + * @param {import('#types').ElementBrokerMessage} [sourceMessage] + */ + constructor(description, behaviour, sourceMessage) { super(description); + /** @type {string} */ this.type = 'BpmnError'; + /** @type {string} */ this.name = behaviour?.name ?? this.constructor.name; + /** @type {string} */ this.description = description; + /** @type {string | undefined} */ this.code = behaviour?.errorCode?.toString() ?? behaviour?.code; + /** @type {string | undefined} */ this.id = behaviour?.id; - if (sourceMessage) this.source = (0, _messageHelper.cloneMessage)(sourceMessage, sourceMessage.content?.error && { - error: undefined - }); - if (inner) this.inner = inner; + if (sourceMessage) { + /** @type {Pick | undefined} */ + this.source = (0, _messageHelper.cloneMessage)(sourceMessage, sourceMessage.content?.error && { + error: undefined + }); + } } } + +/** + * Get an Error from an error message. + * @param {import('#types').ElementBrokerMessage} errorMessage + * @returns {Error | ActivityError | RunError | BpmnError} + */ exports.BpmnError = BpmnError; function makeErrorFromMessage(errorMessage) { const { @@ -71,6 +107,11 @@ function makeErrorFromMessage(errorMessage) { } return error; } + +/** + * @param {any} test + * @returns {Error | undefined} + */ function isKnownError(test) { if (test instanceof ActivityError) return test; if (test instanceof BpmnError) return test; diff --git a/dist/eventDefinitions/CancelEventDefinition.js b/dist/eventDefinitions/CancelEventDefinition.js index a0c930ee..c16d6c25 100644 --- a/dist/eventDefinitions/CancelEventDefinition.js +++ b/dist/eventDefinitions/CancelEventDefinition.js @@ -21,6 +21,7 @@ function CancelEventDefinition(activity, eventDefinition) { const type = eventDefinition.type; this.id = id; this.type = type; + /** @type {import('#types').EventDefinitionReference} */ this.reference = { referenceType: 'cancel' }; @@ -36,9 +37,17 @@ Object.defineProperty(CancelEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CancelEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; this[_constants.K_COMPLETED] = false; @@ -71,6 +80,10 @@ CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMess waitContent.parent = (0, _messageHelper.shiftParent)(parent); broker.publish('event', 'activity.wait', waitContent); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CancelEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { @@ -87,7 +100,7 @@ CancelEventDefinition.prototype.executeThrow = function executeThrow(executeMess broker.publish('event', 'activity.cancel', cancelContent, { type: 'cancel' }); - return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); + broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); }; CancelEventDefinition.prototype._onCatchMessage = function onCatchMessage(_, message) { const content = message.content; diff --git a/dist/eventDefinitions/CompensateEventDefinition.js b/dist/eventDefinitions/CompensateEventDefinition.js index 6293aa14..27780c61 100644 --- a/dist/eventDefinitions/CompensateEventDefinition.js +++ b/dist/eventDefinitions/CompensateEventDefinition.js @@ -25,8 +25,10 @@ function CompensateEventDefinition(activity, eventDefinition, context) { } = activity; this.id = id; const type = this.type = eventDefinition.type; - const reference = this.reference = { - referenceType: 'compensate' + const referenceType = 'compensate'; + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { + referenceType }; this.isThrowing = isThrowing; this.activity = activity; @@ -35,7 +37,7 @@ function CompensateEventDefinition(activity, eventDefinition, context) { if (!isThrowing) { this[_constants.K_COMPLETED] = false; this[K_ASSOCIATIONS] = context.getOutboundAssociations(id); - const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-q`; + const messageQueueName = `${referenceType}-${(0, _shared.brokerSafeId)(id)}-q`; this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true @@ -44,7 +46,7 @@ function CompensateEventDefinition(activity, eventDefinition, context) { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { + broker.bindQueue(messageQueueName, 'api', `*.${referenceType}.#`, { durable: true, priority: 400 }); @@ -56,9 +58,17 @@ Object.defineProperty(CompensateEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CompensateEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CompensateEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; this[_constants.K_COMPLETED] = false; @@ -95,6 +105,10 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute expect: 'compensate' })); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CompensateEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { diff --git a/dist/eventDefinitions/ConditionalEventDefinition.js b/dist/eventDefinitions/ConditionalEventDefinition.js index 534623f7..05ba2945 100644 --- a/dist/eventDefinitions/ConditionalEventDefinition.js +++ b/dist/eventDefinitions/ConditionalEventDefinition.js @@ -40,6 +40,10 @@ Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ConditionalEventDefinition.prototype.execute = function execute(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; if (!this.condition) return this._setup(executeMessage); diff --git a/dist/eventDefinitions/ErrorEventDefinition.js b/dist/eventDefinitions/ErrorEventDefinition.js index 0f6fb357..8b875422 100644 --- a/dist/eventDefinitions/ErrorEventDefinition.js +++ b/dist/eventDefinitions/ErrorEventDefinition.js @@ -25,7 +25,9 @@ function ErrorEventDefinition(activity, eventDefinition) { } = eventDefinition; this.id = id; this.type = type; - const reference = this.reference = { + + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.errorRef, referenceType: 'throw' @@ -35,16 +37,16 @@ function ErrorEventDefinition(activity, eventDefinition) { this.environment = environment; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id); if (!isThrowing) { this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true, priority: 300 }); @@ -56,9 +58,17 @@ Object.defineProperty(ErrorEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ErrorEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; this[_constants.K_COMPLETED] = false; @@ -105,6 +115,10 @@ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessa waitContent.parent = (0, _messageHelper.shiftParent)(parent); broker.publish('event', 'activity.wait', waitContent); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ErrorEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { diff --git a/dist/eventDefinitions/EscalationEventDefinition.js b/dist/eventDefinitions/EscalationEventDefinition.js index ab5c2a6c..9b95815e 100644 --- a/dist/eventDefinitions/EscalationEventDefinition.js +++ b/dist/eventDefinitions/EscalationEventDefinition.js @@ -28,7 +28,9 @@ function EscalationEventDefinition(activity, eventDefinition) { } = eventDefinition; this.id = id; this.type = type; - const reference = this.reference = { + + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.escalationRef, referenceType: 'escalate' @@ -37,16 +39,16 @@ function EscalationEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id); if (!isThrowing) { this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true, priority: 400 }); @@ -58,9 +60,17 @@ Object.defineProperty(EscalationEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EscalationEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EscalationEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; this[_constants.K_COMPLETED] = false; @@ -91,6 +101,10 @@ EscalationEventDefinition.prototype.executeCatch = function executeCatch(execute waitContent.parent = (0, _messageHelper.shiftParent)(parent); broker.publish('event', 'activity.wait', waitContent); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EscalationEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { diff --git a/dist/eventDefinitions/EventDefinitionExecution.js b/dist/eventDefinitions/EventDefinitionExecution.js index a7b049b0..ec3cb9c5 100644 --- a/dist/eventDefinitions/EventDefinitionExecution.js +++ b/dist/eventDefinitions/EventDefinitionExecution.js @@ -33,6 +33,10 @@ Object.defineProperty(EventDefinitionExecution.prototype, 'stopped', { return this[_constants.K_STOPPED]; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { const content = executeMessage.content; if (content.isDefinitionScope) return this._executeDefinition(executeMessage); diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index 4345eabc..dae51678 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -25,6 +25,8 @@ function LinkEventDefinition(activity, eventDefinition) { } = eventDefinition; this.id = id; this.type = type; + + /** @type {import('#types').EventDefinitionReference} */ this.reference = { id: behaviour.name, linkName: behaviour.name, @@ -75,9 +77,17 @@ Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ LinkEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; const executeContent = executeMessage.content; @@ -109,6 +119,10 @@ LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessag state: 'catch' })); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { diff --git a/dist/eventDefinitions/MessageEventDefinition.js b/dist/eventDefinitions/MessageEventDefinition.js index 286078bf..632e937f 100644 --- a/dist/eventDefinitions/MessageEventDefinition.js +++ b/dist/eventDefinitions/MessageEventDefinition.js @@ -26,7 +26,9 @@ function MessageEventDefinition(activity, eventDefinition) { } = eventDefinition; this.id = id; this.type = type; - const reference = this.reference = { + + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.messageRef, referenceType: 'message' @@ -35,16 +37,16 @@ function MessageEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id); if (!isThrowing) { this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true }); } @@ -55,9 +57,17 @@ Object.defineProperty(MessageEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ MessageEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; this[_constants.K_COMPLETED] = false; @@ -100,6 +110,10 @@ MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMes waitContent.parent = (0, _messageHelper.shiftParent)(parent); broker.publish('event', 'activity.wait', waitContent); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ MessageEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { diff --git a/dist/eventDefinitions/SignalEventDefinition.js b/dist/eventDefinitions/SignalEventDefinition.js index f024b3f6..b5ab00a4 100644 --- a/dist/eventDefinitions/SignalEventDefinition.js +++ b/dist/eventDefinitions/SignalEventDefinition.js @@ -27,7 +27,9 @@ function SignalEventDefinition(activity, eventDefinition) { } = eventDefinition; this.id = id; this.type = type; - const reference = this.reference = { + + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.signalRef, referenceType: 'signal' @@ -36,16 +38,16 @@ function SignalEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); + const referenceElement = this[_constants.K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id); if (!isThrowing && isStart) { this[_constants.K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(referenceId)}-q`; this[_constants.K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true }); } @@ -56,9 +58,17 @@ Object.defineProperty(SignalEventDefinition.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ SignalEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[_constants.K_EXECUTE_MESSAGE] = executeMessage; this[_constants.K_COMPLETED] = false; @@ -101,6 +111,10 @@ SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMess waitContent.parent = (0, _messageHelper.shiftParent)(parent); broker.publish('event', 'activity.wait', waitContent); }; + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ SignalEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { diff --git a/dist/eventDefinitions/TerminateEventDefinition.js b/dist/eventDefinitions/TerminateEventDefinition.js index 00c887a1..f7f0ca04 100644 --- a/dist/eventDefinitions/TerminateEventDefinition.js +++ b/dist/eventDefinitions/TerminateEventDefinition.js @@ -25,6 +25,10 @@ function TerminateEventDefinition(activity, eventDefinition) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ TerminateEventDefinition.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const throwContent = (0, _messageHelper.cloneContent)(executeContent, { diff --git a/dist/eventDefinitions/TimerEventDefinition.js b/dist/eventDefinitions/TimerEventDefinition.js index 45ecc0c5..4af169f5 100644 --- a/dist/eventDefinitions/TimerEventDefinition.js +++ b/dist/eventDefinitions/TimerEventDefinition.js @@ -27,9 +27,9 @@ function TimerEventDefinition(activity, eventDefinition) { timeCycle, timeDate } = eventDefinition.behaviour || {}; - if (timeDuration) this.timeDuration = timeDuration; - if (timeCycle) this.timeCycle = timeCycle; - if (timeDate) this.timeDate = timeDate; + if (timeDuration) this.timeDuration = /** @type {string} */timeDuration; + if (timeCycle) this.timeCycle = /** @type {string} */timeCycle; + if (timeDate) this.timeDate = /** @type {string} */timeDate; this.broker = activity.broker; this.logger = environment.Logger(type.toLowerCase()); this[_constants.K_STOPPED] = false; @@ -42,15 +42,21 @@ Object.defineProperty(TimerEventDefinition.prototype, 'executionId', { } }); Object.defineProperty(TimerEventDefinition.prototype, 'stopped', { + /** @returns {boolean} */ get() { return this[_constants.K_STOPPED]; } }); Object.defineProperty(TimerEventDefinition.prototype, 'timer', { + /** @returns {import('#types').Timer | null} */ get() { return this[K_TIMER]; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ TimerEventDefinition.prototype.execute = function execute(executeMessage) { const { routingKey: executeKey, @@ -194,6 +200,8 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, } } }; + +/** @private */ TimerEventDefinition.prototype._stop = function stop() { this[_constants.K_STOPPED] = true; const timer = this[K_TIMER]; @@ -202,6 +210,12 @@ TimerEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-${this.executionId}`); broker.cancel(`_api-delegated-${this.executionId}`); }; + +/** + * Parse timer + * @param {string} timerType + * @param {string} value + */ TimerEventDefinition.prototype.parse = function parse(timerType, value) { let repeat, delay, expireAt; const now = new Date(); diff --git a/dist/events/BoundaryEvent.js b/dist/events/BoundaryEvent.js index 4050c861..2e96fb82 100644 --- a/dist/events/BoundaryEvent.js +++ b/dist/events/BoundaryEvent.js @@ -13,9 +13,20 @@ var _constants = require("../constants.js"); const K_ATTACHED_TAGS = Symbol.for('attachedConsumers'); const K_COMPLETE_CONTENT = Symbol.for('completeContent'); const K_SHOVELS = Symbol.for('shovels'); + +/** + * Boundary event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function BoundaryEvent(activityDef, context) { return new _Activity.Activity(BoundaryEventBehaviour, activityDef, context); } + +/** + * Boundary event behaviour + * @param {import('#types').Activity} activity + */ function BoundaryEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -38,6 +49,11 @@ Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', { return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { const { isRootScope, diff --git a/dist/events/EndEvent.js b/dist/events/EndEvent.js index 54cf944e..218b02ed 100644 --- a/dist/events/EndEvent.js +++ b/dist/events/EndEvent.js @@ -9,18 +9,33 @@ var _Activity = require("../activity/Activity.js"); var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * End event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function EndEvent(activityDef, context) { return new _Activity.Activity(EndEventBehaviour, { ...activityDef, isThrowing: true }, context); } + +/** + * End event behaviour + * @param {import('#types').Activity} activity + */ function EndEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ EndEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[_constants.K_EXECUTION]; if (execution) { diff --git a/dist/events/IntermediateCatchEvent.js b/dist/events/IntermediateCatchEvent.js index fb742a79..0a34cf10 100644 --- a/dist/events/IntermediateCatchEvent.js +++ b/dist/events/IntermediateCatchEvent.js @@ -9,18 +9,33 @@ var _Activity = require("../activity/Activity.js"); var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Intermediate catch event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function IntermediateCatchEvent(activityDef, context) { return new _Activity.Activity(IntermediateCatchEventBehaviour, { ...activityDef, isCatching: true }, context); } + +/** + * Intermediate catch event behaviour + * @param {import('#types').Activity} activity + */ function IntermediateCatchEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ IntermediateCatchEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[_constants.K_EXECUTION]; if (execution) { diff --git a/dist/events/IntermediateThrowEvent.js b/dist/events/IntermediateThrowEvent.js index 553d0a51..f7bae9ef 100644 --- a/dist/events/IntermediateThrowEvent.js +++ b/dist/events/IntermediateThrowEvent.js @@ -9,18 +9,33 @@ var _Activity = require("../activity/Activity.js"); var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Intermediate throw event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function IntermediateThrowEvent(activityDef, context) { return new _Activity.Activity(IntermediateThrowEventBehaviour, { ...activityDef, isThrowing: true }, context); } + +/** + * Intermediate throw event behaviour + * @param {import('#types').Activity} activity + */ function IntermediateThrowEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; this.broker = activity.broker; this[_constants.K_EXECUTION] = activity.eventDefinitions && new _EventDefinitionExecution.EventDefinitionExecution(activity, activity.eventDefinitions); } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ IntermediateThrowEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[_constants.K_EXECUTION]; if (execution) { diff --git a/dist/events/StartEvent.js b/dist/events/StartEvent.js index 393b6154..14dc9793 100644 --- a/dist/events/StartEvent.js +++ b/dist/events/StartEvent.js @@ -9,9 +9,19 @@ var _Activity = require("../activity/Activity.js"); var _EventDefinitionExecution = require("../eventDefinitions/EventDefinitionExecution.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Start event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function StartEvent(activityDef, context) { return new _Activity.Activity(StartEventBehaviour, activityDef, context); } + +/** + * Start event behaviour + * @param {import('#types').Activity} activity + */ function StartEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -24,6 +34,11 @@ Object.defineProperty(StartEventBehaviour.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ StartEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[_constants.K_EXECUTION]; if (execution) { diff --git a/dist/gateways/EventBasedGateway.js b/dist/gateways/EventBasedGateway.js index c8b5bfa8..6024050a 100644 --- a/dist/gateways/EventBasedGateway.js +++ b/dist/gateways/EventBasedGateway.js @@ -8,9 +8,20 @@ exports.EventBasedGatewayBehaviour = EventBasedGatewayBehaviour; var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Event based gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function EventBasedGateway(activityDef, context) { return new _Activity.Activity(EventBasedGatewayBehaviour, activityDef, context); } + +/** + * Event based gateway behaviour + * @param {import('#types').Activity} activity + * @param {import('#types').ContextInstance} context + */ function EventBasedGatewayBehaviour(activity, context) { this.id = activity.id; this.type = activity.type; @@ -19,6 +30,11 @@ function EventBasedGatewayBehaviour(activity, context) { this.context = context; this[_constants.K_TARGETS] = new Set(activity.outbound.map(flow => context.getActivityById(flow.targetId))); } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const { diff --git a/dist/gateways/ExclusiveGateway.js b/dist/gateways/ExclusiveGateway.js index e0f7a023..8a532ea4 100644 --- a/dist/gateways/ExclusiveGateway.js +++ b/dist/gateways/ExclusiveGateway.js @@ -7,9 +7,19 @@ exports.ExclusiveGateway = ExclusiveGateway; exports.ExclusiveGatewayBehaviour = ExclusiveGatewayBehaviour; var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Exclusive gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function ExclusiveGateway(activityDef, context) { return new _Activity.Activity(ExclusiveGatewayBehaviour, activityDef, context); } + +/** + * Exclusive gateway behaviour + * @param {import('#types').Activity} activity + */ function ExclusiveGatewayBehaviour(activity) { const { id, @@ -20,6 +30,11 @@ function ExclusiveGatewayBehaviour(activity) { this.type = type; this.broker = broker; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ExclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { diff --git a/dist/gateways/InclusiveGateway.js b/dist/gateways/InclusiveGateway.js index c057f5a0..ef12f4c6 100644 --- a/dist/gateways/InclusiveGateway.js +++ b/dist/gateways/InclusiveGateway.js @@ -7,9 +7,19 @@ exports.InclusiveGateway = InclusiveGateway; exports.InclusiveGatewayBehaviour = InclusiveGatewayBehaviour; var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Inclusive gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function InclusiveGateway(activityDef, context) { return new _Activity.Activity(InclusiveGatewayBehaviour, activityDef, context); } + +/** + * Inclusive gateway behaviour + * @param {import('#types').Activity} activity + */ function InclusiveGatewayBehaviour(activity) { const { id, @@ -20,6 +30,11 @@ function InclusiveGatewayBehaviour(activity) { this.type = type; this.broker = broker; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ InclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 69791d21..25c9dcce 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -12,6 +12,12 @@ const STATE_MONTITORING = 'monitoring'; const STATE_SETUP = 'setup'; const K_PEERS = Symbol.for('peers'); const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); + +/** + * Parallel gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function ParallelGateway(activityDef, context) { const activity = new _Activity.Activity(ParallelGatewayBehaviour, { ...activityDef, @@ -49,6 +55,11 @@ function ParallelGateway(activityDef, context) { activity.shake(message); } } + +/** + * Parallel gateway behaviour + * @param {import('#types').Activity} activity + */ function ParallelGatewayBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -65,6 +76,11 @@ Object.defineProperty(ParallelGatewayBehaviour.prototype, 'executionId', { return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { const routingKey = executeMessage.fields.routingKey; const isRedelivered = executeMessage.fields.redelivered; diff --git a/dist/io/BpmnIO.js b/dist/io/BpmnIO.js index 9e034ece..e66ea5c9 100644 --- a/dist/io/BpmnIO.js +++ b/dist/io/BpmnIO.js @@ -4,6 +4,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.BpmnIO = BpmnIO; +/** + * Built-in IO extension. Composes the activity's ioSpecification and properties behaviours. + * @param {import('#types').Activity} activity + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IExtension} + */ function BpmnIO(activity, context) { this.activity = activity; this.context = context; @@ -20,12 +26,20 @@ Object.defineProperty(BpmnIO.prototype, 'hasIo', { return this.specification || this.properties; } }); + +/** + * @param {import('#types').ElementBrokerMessage} message + */ BpmnIO.prototype.activate = function activate(message) { const properties = this.properties, specification = this.specification; if (properties) properties.activate(message); if (specification) specification.activate(message); }; + +/** + * @param {import('#types').ElementBrokerMessage} message + */ BpmnIO.prototype.deactivate = function deactivate(message) { const properties = this.properties, specification = this.specification; diff --git a/dist/io/EnvironmentDataObject.js b/dist/io/EnvironmentDataObject.js index e52f9226..bb761615 100644 --- a/dist/io/EnvironmentDataObject.js +++ b/dist/io/EnvironmentDataObject.js @@ -5,9 +5,9 @@ Object.defineProperty(exports, "__esModule", { }); exports.EnvironmentDataObject = EnvironmentDataObject; /** - * Builtin data object - * @param {import('moddle-context-serializer').DataObject>} dataObjectDef - * @param {import('../Context.js').ContextInstance} context + * Builtin data object. Reads from / writes to `environment.variables._data`. + * @param {import('moddle-context-serializer').DataObject} dataObjectDef + * @param {import('#types').ContextInstance} context * @satisfies {import('#types').IIOData} */ function EnvironmentDataObject(dataObjectDef, { @@ -23,16 +23,33 @@ function EnvironmentDataObject(dataObjectDef, { this.id = id; this.type = type; this.name = name; + /** @type {Record} */ this.behaviour = behaviour; + /** @type {import('moddle-context-serializer').Parent | undefined} */ this.parent = parent; this.environment = environment; } + +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {Record} [messageProperties] + */ EnvironmentDataObject.prototype.read = function read(broker, exchange, routingKeyPrefix, messageProperties) { const environment = this.environment; const value = environment.variables._data?.[this.id]; const content = this._createContent(value); return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; + +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {any} value + * @param {Record} [messageProperties] + */ EnvironmentDataObject.prototype.write = function write(broker, exchange, routingKeyPrefix, value, messageProperties) { const environment = this.environment; environment.variables._data = environment.variables._data || {}; diff --git a/dist/io/EnvironmentDataStore.js b/dist/io/EnvironmentDataStore.js index 9ba645b0..08c87ee8 100644 --- a/dist/io/EnvironmentDataStore.js +++ b/dist/io/EnvironmentDataStore.js @@ -4,6 +4,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.EnvironmentDataStore = EnvironmentDataStore; +/** + * Builtin data store. Reads from / writes to `environment.variables._data`. + * @param {import('moddle-context-serializer').DataStore} dataStoreDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IIOData} + */ function EnvironmentDataStore(dataStoreDef, { environment }) { @@ -17,16 +23,33 @@ function EnvironmentDataStore(dataStoreDef, { this.id = id; this.type = type; this.name = name; + /** @type {Record} */ this.behaviour = behaviour; + /** @type {import('moddle-context-serializer').Parent | undefined} */ this.parent = parent; this.environment = environment; } + +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {Record} [messageProperties] + */ EnvironmentDataStore.prototype.read = function read(broker, exchange, routingKeyPrefix, messageProperties) { const environment = this.environment; const value = environment.variables._data?.[this.id]; const content = this._createContent(value); return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; + +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {any} value + * @param {Record} [messageProperties] + */ EnvironmentDataStore.prototype.write = function write(broker, exchange, routingKeyPrefix, value, messageProperties) { const environment = this.environment; environment.variables._data = environment.variables._data || {}; diff --git a/dist/io/EnvironmentDataStoreReference.js b/dist/io/EnvironmentDataStoreReference.js index f97f1fcb..84d7f530 100644 --- a/dist/io/EnvironmentDataStoreReference.js +++ b/dist/io/EnvironmentDataStoreReference.js @@ -4,6 +4,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.EnvironmentDataStoreReference = EnvironmentDataStoreReference; +/** + * Builtin data store reference. Reads from / writes to `environment.variables._data`. + * @param {import('moddle-context-serializer').DataStore} dataObjectDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IIOData} + */ function EnvironmentDataStoreReference(dataObjectDef, { environment }) { @@ -17,16 +23,33 @@ function EnvironmentDataStoreReference(dataObjectDef, { this.id = id; this.type = type; this.name = name; + /** @type {Record} */ this.behaviour = behaviour; + /** @type {import('moddle-context-serializer').Parent | undefined} */ this.parent = parent; this.environment = environment; } + +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {Record} [messageProperties] + */ EnvironmentDataStoreReference.prototype.read = function read(broker, exchange, routingKeyPrefix, messageProperties) { const environment = this.environment; const value = environment.variables._data?.[this.id]; const content = this._createContent(value); return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; + +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {any} value + * @param {Record} [messageProperties] + */ EnvironmentDataStoreReference.prototype.write = function write(broker, exchange, routingKeyPrefix, value, messageProperties) { const environment = this.environment; environment.variables._data = environment.variables._data || {}; diff --git a/dist/io/InputOutputSpecification.js b/dist/io/InputOutputSpecification.js index f11f58d3..064187b3 100644 --- a/dist/io/InputOutputSpecification.js +++ b/dist/io/InputOutputSpecification.js @@ -7,6 +7,13 @@ exports.IoSpecification = IoSpecification; var _getPropertyValue = require("../getPropertyValue.js"); var _shared = require("../shared.js"); var _constants = require("../constants.js"); +/** + * Activity ioSpecification behaviour. Reads bound data objects on enter and writes them on completion. + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').IoSpecification} ioSpecificationDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IExtension} + */ function IoSpecification(activity, ioSpecificationDef, context) { const { id, @@ -20,6 +27,10 @@ function IoSpecification(activity, ioSpecificationDef, context) { this.broker = activity.broker; this.context = context; } + +/** + * @param {import('#types').ElementBrokerMessage} [message] + */ IoSpecification.prototype.activate = function activate(message) { if (this[_constants.K_CONSUMING]) return; if (message?.fields.redelivered && message.fields.routingKey === 'run.start') { diff --git a/dist/io/Properties.js b/dist/io/Properties.js index dafc8326..215d0c18 100644 --- a/dist/io/Properties.js +++ b/dist/io/Properties.js @@ -7,6 +7,14 @@ exports.Properties = Properties; var _getPropertyValue = require("../getPropertyValue.js"); var _constants = require("../constants.js"); const K_PROPERTIES = Symbol.for('properties'); + +/** + * Activity properties behaviour. Resolves bound data input/output references during the run. + * @param {import('#types').Activity} activity + * @param {{ type: 'properties', values: import('moddle-context-serializer').IElement[] }} propertiesDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IExtension} + */ function Properties(activity, propertiesDef, context) { this.activity = activity; this.broker = activity.broker; @@ -71,6 +79,10 @@ function Properties(activity, propertiesDef, context) { } } } + +/** + * @param {import('#types').ElementBrokerMessage} message + */ Properties.prototype.activate = function activate(message) { if (this[_constants.K_CONSUMING]) return; if (message.fields.redelivered && message.fields.routingKey === 'run.start') { diff --git a/dist/process/Lane.js b/dist/process/Lane.js index 6fc8fb25..8a125293 100644 --- a/dist/process/Lane.js +++ b/dist/process/Lane.js @@ -25,11 +25,14 @@ function Lane(process, laneDefinition) { this[K_PROCESS] = process; this.id = id; this.type = type; + /** @type {string} */ this.name = behaviour.name; + /** @type {import('moddle-context-serializer').Parent} */ this.parent = { id: process.id, type: process.type }; + /** @type {Record} */ this.behaviour = { ...behaviour }; diff --git a/dist/process/Process.js b/dist/process/Process.js index bade8663..2646f918 100644 --- a/dist/process/Process.js +++ b/dist/process/Process.js @@ -216,6 +216,7 @@ Process.prototype.recover = function recover(state) { /** * Walk activity graph from the given start id, or every start activity when omitted. * @param {string} [startId] + * @returns {import('#types').ShakeResult} */ Process.prototype.shake = function shake(startId) { if (this.isRunning) return this.execution.shake(startId); @@ -498,7 +499,7 @@ Process.prototype.getSequenceFlows = function getSequenceFlows() { /** * @param {string} laneId - * @returns {import('./Lane.js') | undefined} + * @returns {import('./Lane.js').Lane | undefined} */ Process.prototype.getLaneById = function getLaneById(laneId) { return this[K_LANES]?.find(lane => lane.id === laneId); diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 72b2fc5e..280f8d8e 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -257,6 +257,7 @@ ProcessExecution.prototype.recover = function recover(state) { /** * Walk activity graph from the given start id, or every start activity when omitted. * @param {string} [fromId] + * @returns {import('#types').ShakeResult} */ ProcessExecution.prototype.shake = function shake(fromId) { return Object.fromEntries(this._shakeElements(fromId).sequences); @@ -289,7 +290,7 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { */ ProcessExecution.prototype.discard = function discard() { this[_constants.K_STATUS] = 'discard'; - return this[K_ACTIVITY_Q].queueMessage({ + this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.discard' }, { id: this.id, @@ -304,7 +305,7 @@ ProcessExecution.prototype.discard = function discard() { * Queue a cancel message that propagates to all running children. */ ProcessExecution.prototype.cancel = function discard() { - return this[K_ACTIVITY_Q].queueMessage({ + this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.cancel' }, { id: this.id, diff --git a/dist/tasks/CallActivity.js b/dist/tasks/CallActivity.js index 44a3a1f6..def42ad7 100644 --- a/dist/tasks/CallActivity.js +++ b/dist/tasks/CallActivity.js @@ -9,14 +9,18 @@ var _Activity = require("../activity/Activity.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); /** - * Create call activity + * Call activity * @param {import('moddle-context-serializer').Activity} activityDef - * @param {import('../Context.js').ContextInstance} context - * @returns Call activity + * @param {import('#types').ContextInstance} context */ function CallActivity(activityDef, context) { return new _Activity.Activity(CallActivityBehaviour, activityDef, context); } + +/** + * Call activity behaviour + * @param {import('#types').Activity} activity + */ function CallActivityBehaviour(activity) { const { id, @@ -26,11 +30,17 @@ function CallActivityBehaviour(activity) { this.id = id; this.type = type; this.calledElement = behaviour.calledElement; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.broker = activity.broker; this.environment = activity.environment; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ CallActivityBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/dist/tasks/LoopCharacteristics.js b/dist/tasks/LoopCharacteristics.js index 90592878..af5f5b79 100644 --- a/dist/tasks/LoopCharacteristics.js +++ b/dist/tasks/LoopCharacteristics.js @@ -6,6 +6,11 @@ Object.defineProperty(exports, "__esModule", { exports.LoopCharacteristics = LoopCharacteristics; var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Loop characteristics + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').SerializableElement} loopCharacteristics + */ function LoopCharacteristics(activity, loopCharacteristics) { this.activity = activity; this.loopCharacteristics = loopCharacteristics; @@ -18,10 +23,13 @@ function LoopCharacteristics(activity, loopCharacteristics) { isSequential = false, collection } = behaviour; + /** @type {boolean} */ this.isSequential = isSequential; + /** @type {string | undefined} */ this.collection = collection; let completionCondition, startCondition, loopCardinality; if ('loopCardinality' in behaviour) loopCardinality = behaviour.loopCardinality;else if ('loopMaximum' in behaviour) loopCardinality = behaviour.loopMaximum; + /** @type {number | undefined} */ this.loopCardinality = loopCardinality; if (behaviour.loopCondition) { if (behaviour.testBefore) startCondition = behaviour.loopCondition;else completionCondition = behaviour.loopCondition; @@ -31,11 +39,19 @@ function LoopCharacteristics(activity, loopCharacteristics) { } if (collection) { this.loopType = 'collection'; + /** @type {string | undefined} */ this.elementVariable = behaviour.elementVariable || 'item'; } else if (completionCondition) this.loopType = 'complete condition';else if (startCondition) this.loopType = 'start condition';else if (loopCardinality) this.loopType = 'cardinality'; + + /** @type {Characteristics} */ this.characteristics = null; this.execution = null; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ LoopCharacteristics.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new TypeError('LoopCharacteristics execution requires message'); const chr = this.characteristics = this.characteristics || new Characteristics(this.activity, this.loopCharacteristics, executeMessage); @@ -43,11 +59,21 @@ LoopCharacteristics.prototype.execute = function execute(executeMessage) { const execution = this.isSequential ? new SequentialLoopCharacteristics(this.activity, chr) : new ParallelLoopCharacteristics(this.activity, chr); return execution.execute(executeMessage); }; + +/** + * @param {import('#types').Activity} activity + * @param {Characteristics} characteristics + */ function SequentialLoopCharacteristics(activity, characteristics) { this.activity = activity; this.id = activity.id; this.characteristics = characteristics; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ SequentialLoopCharacteristics.prototype.execute = function execute(executeMessage) { const { routingKey: executeRoutingKey, @@ -71,10 +97,10 @@ SequentialLoopCharacteristics.prototype._startNext = function startNext(index, i if (chr.isStartConditionMet({ content })) { - chr.debug('start condition met'); + chr._debug('start condition met'); return; } - chr.debug(`${ignoreIfExecuting ? 'resume' : 'start'} sequential iteration index ${content.index}`); + chr._debug(`${ignoreIfExecuting ? 'resume' : 'start'} sequential iteration index ${content.index}`); const broker = this.activity.broker; broker.publish('execution', 'execute.iteration.next', { ...content, @@ -105,11 +131,16 @@ SequentialLoopCharacteristics.prototype._onCompleteMessage = function onComplete state: 'iteration.completed' }); if (chr.isCompletionConditionMet(message, loopOutput)) { - chr.debug('complete condition met'); + chr._debug('complete condition met'); } else if (this._startNext(content.index + 1)) return; - chr.debug('sequential loop completed'); + chr._debug('sequential loop completed'); return chr.complete(content); }; + +/** + * @param {import('#types').Activity} activity + * @param {Characteristics} characteristics + */ function ParallelLoopCharacteristics(activity, characteristics) { this.activity = activity; this.id = activity.id; @@ -118,6 +149,11 @@ function ParallelLoopCharacteristics(activity, characteristics) { this.index = 0; this.discarded = 0; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ParallelLoopCharacteristics.prototype.execute = function execute(executeMessage) { const chr = this.characteristics; if (!chr.cardinality) throw new _Errors.RunError(`<${this.id}> cardinality or collection is required in parallel loops`, executeMessage); @@ -142,7 +178,7 @@ ParallelLoopCharacteristics.prototype._startBatch = function startBatch() { const batch = new Set(); let startContent = chr.next(this.index); do { - chr.debug(`start parallel iteration index ${this.index}`); + chr._debug(`start parallel iteration index ${this.index}`); batch.add(startContent); this.running++; this.index++; @@ -194,6 +230,13 @@ ParallelLoopCharacteristics.prototype._onCompleteMessage = function onCompleteMe this._startBatch(); } }; + +/** + * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').SerializableElement} loopCharacteristics + * @param {import('#types').ElementBrokerMessage} executeMessage + */ function Characteristics(activity, loopCharacteristics, executeMessage) { this.activity = activity; const behaviour = this.behaviour = loopCharacteristics.behaviour || {}; @@ -202,26 +245,34 @@ function Characteristics(activity, loopCharacteristics, executeMessage) { this.id = activity.id; this.broker = activity.broker; this.parentExecutionId = executeMessage.content.executionId; + + /** @type {boolean} */ this.isSequential = behaviour.isSequential || false; this.output = executeMessage.content.output || []; this.parent = (0, _messageHelper.unshiftParent)(executeMessage.content.parent, executeMessage.content); - if ('loopCardinality' in behaviour) this.loopCardinality = behaviour.loopCardinality;else if ('loopMaximum' in behaviour) this.loopCardinality = behaviour.loopMaximum; + if ('loopCardinality' in behaviour) this.loopCardinality = /** @type {number} */behaviour.loopCardinality;else if ('loopMaximum' in behaviour) this.loopCardinality = /** @type {number} */behaviour.loopMaximum; if (behaviour.loopCondition) { - if (behaviour.testBefore) this.startCondition = behaviour.loopCondition;else this.completionCondition = behaviour.loopCondition; + if (behaviour.testBefore) this.startCondition = /** @type {string} */behaviour.loopCondition;else this.completionCondition = /** @type {string} */behaviour.loopCondition; } if (behaviour.completionCondition) { + /** @type {string} */ this.completionCondition = behaviour.completionCondition; } const collection = this.collection = this.getCollection(); if (collection) { + /** @type {string} */ this.elementVariable = behaviour.elementVariable || 'item'; } this.cardinality = this.getCardinality(collection); + + /** @private */ this.onApiMessage = this.onApiMessage.bind(this); const environment = activity.environment; this.logger = environment.Logger(type.toLowerCase()); this.batchSize = environment.settings.batchSize || 50; } + +/** @returns {import('#types').ElementMessageContent} */ Characteristics.prototype.getContent = function getContent() { return { ...(0, _messageHelper.cloneContent)(this.message.content), @@ -230,6 +281,11 @@ Characteristics.prototype.getContent = function getContent() { output: undefined }; }; + +/** + * @param {number} index + * @returns {import('#types').ElementMessageContent} + */ Characteristics.prototype.next = function next(index) { const cardinality = this.cardinality; if (cardinality > 0 && index >= cardinality) return; @@ -248,6 +304,11 @@ Characteristics.prototype.next = function next(index) { } return content; }; + +/** + * @param {any} [collection] + * @returns {number | undefined} cardinality + */ Characteristics.prototype.getCardinality = function getCardinality(collection) { const collectionLen = this.collection && Array.isArray(collection) ? collection.length : undefined; if (!this.loopCardinality) { @@ -260,21 +321,37 @@ Characteristics.prototype.getCardinality = function getCardinality(collection) { if (value === undefined) return collectionLen; return Number(value); }; + +/** @returns {Array | undefined} */ Characteristics.prototype.getCollection = function getCollection() { const collectionExpression = this.behaviour.collection; if (!collectionExpression) return; return this.activity.environment.resolveExpression(collectionExpression, this.message); }; + +/** + * @param {import('#types').ElementBrokerMessage} message + */ Characteristics.prototype.isStartConditionMet = function isStartConditionMet(message) { if (!this.startCondition) return false; return this.activity.environment.resolveExpression(this.startCondition, (0, _messageHelper.cloneMessage)(message)); }; + +/** + * @param {import('#types').ElementBrokerMessage} message + */ Characteristics.prototype.isCompletionConditionMet = function isCompletionConditionMet(message) { if (!this.completionCondition) return false; return this.activity.environment.resolveExpression(this.completionCondition, (0, _messageHelper.cloneMessage)(message, { loopOutput: this.output })); }; + +/** + * @param {import('#types').ElementMessageContent} content + * @param {boolean} [allDiscarded] + * @returns {void} + */ Characteristics.prototype.complete = function complete(content, allDiscarded) { this.stop(); return this.broker.publish('execution', 'execute.' + (allDiscarded ? 'discard' : 'completed'), { @@ -283,6 +360,10 @@ Characteristics.prototype.complete = function complete(content, allDiscarded) { output: this.output }); }; + +/** + * @param {import('#types').ElementBrokerMessage} onIterationCompleteMessage + */ Characteristics.prototype.subscribe = function subscribe(onIterationCompleteMessage) { this.broker.subscribeTmp('api', `activity.*.${this.parentExecutionId}`, this.onApiMessage, { noAck: true, @@ -305,6 +386,8 @@ Characteristics.prototype.subscribe = function subscribe(onIterationCompleteMess } } }; + +/** @internal */ Characteristics.prototype.onApiMessage = function onApiMessage(_, message) { switch (message.properties.type) { case 'stop': @@ -317,6 +400,8 @@ Characteristics.prototype.stop = function stop() { this.broker.cancel('_execute-q-multi-instance-tag'); this.broker.cancel('_api-multi-instance-tag'); }; -Characteristics.prototype.debug = function debug(msg) { + +/** @internal */ +Characteristics.prototype._debug = function debug(msg) { this.logger.debug(`<${this.parentExecutionId} (${this.id})> ${msg}`); }; \ No newline at end of file diff --git a/dist/tasks/ReceiveTask.js b/dist/tasks/ReceiveTask.js index 6d9c997d..f17abc46 100644 --- a/dist/tasks/ReceiveTask.js +++ b/dist/tasks/ReceiveTask.js @@ -8,6 +8,11 @@ exports.ReceiveTaskBehaviour = ReceiveTaskBehaviour; var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); +/** + * Receive task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function ReceiveTask(activityDef, context) { const task = new _Activity.Activity(ReceiveTaskBehaviour, activityDef, context); task.broker.assertQueue('message', { @@ -19,6 +24,11 @@ function ReceiveTask(activityDef, context) { }); return task; } + +/** + * Receive task behaviour + * @param {import('#types').Activity} activity + */ function ReceiveTaskBehaviour(activity) { const { id, @@ -37,6 +47,11 @@ function ReceiveTaskBehaviour(activity) { this.broker = activity.broker; this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ReceiveTaskBehaviour.prototype.execute = function execute(executeMessage) { return new ReceiveTaskExecution(this).execute(executeMessage); }; diff --git a/dist/tasks/ScriptTask.js b/dist/tasks/ScriptTask.js index 990d570a..d19b16dd 100644 --- a/dist/tasks/ScriptTask.js +++ b/dist/tasks/ScriptTask.js @@ -9,9 +9,19 @@ var _Activity = require("../activity/Activity.js"); var _ExecutionScope = require("../activity/ExecutionScope.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Script task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function ScriptTask(activityDef, context) { return new _Activity.Activity(ScriptTaskBehaviour, activityDef, context); } + +/** + * Script task behaviour + * @param {import('#types').Activity} activity + */ function ScriptTaskBehaviour(activity) { const { id, @@ -26,6 +36,11 @@ function ScriptTaskBehaviour(activity) { const environment = this.environment = activity.environment; environment.registerScript(activity); } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ScriptTaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/dist/tasks/ServiceImplementation.js b/dist/tasks/ServiceImplementation.js index b7bcb44d..04888c48 100644 --- a/dist/tasks/ServiceImplementation.js +++ b/dist/tasks/ServiceImplementation.js @@ -5,6 +5,10 @@ Object.defineProperty(exports, "__esModule", { }); exports.ServiceImplementation = ServiceImplementation; var _ExecutionScope = require("../activity/ExecutionScope.js"); +/** + * Service implementation + * @param {import('#types').Activity} activity + */ function ServiceImplementation(activity) { this.type = `${activity.type}:implementation`; this.implementation = activity.behaviour.implementation; diff --git a/dist/tasks/ServiceTask.js b/dist/tasks/ServiceTask.js index d2d6686e..441fbaa5 100644 --- a/dist/tasks/ServiceTask.js +++ b/dist/tasks/ServiceTask.js @@ -8,9 +8,19 @@ exports.ServiceTaskBehaviour = ServiceTaskBehaviour; var _Activity = require("../activity/Activity.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Service task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function ServiceTask(activityDef, context) { return new _Activity.Activity(ServiceTaskBehaviour, activityDef, context); } + +/** + * Service task behaviour + * @param {import('#types').Activity} activity + */ function ServiceTaskBehaviour(activity) { const { id, @@ -24,6 +34,11 @@ function ServiceTaskBehaviour(activity) { this.environment = activity.environment; this.broker = activity.broker; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ServiceTaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/dist/tasks/SignalTask.js b/dist/tasks/SignalTask.js index f359fc60..da5ff9d3 100644 --- a/dist/tasks/SignalTask.js +++ b/dist/tasks/SignalTask.js @@ -8,9 +8,19 @@ exports.SignalTaskBehaviour = SignalTaskBehaviour; var _Activity = require("../activity/Activity.js"); var _Errors = require("../error/Errors.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Signal task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function SignalTask(activityDef, context) { return new _Activity.Activity(SignalTaskBehaviour, activityDef, context); } + +/** + * Signal task behaviour + * @param {import('#types').Activity} activity + */ function SignalTaskBehaviour(activity) { const { id, @@ -23,6 +33,11 @@ function SignalTaskBehaviour(activity) { this.activity = activity; this.broker = activity.broker; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ SignalTaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/dist/tasks/StandardLoopCharacteristics.js b/dist/tasks/StandardLoopCharacteristics.js index bcca0ac7..6d5ea921 100644 --- a/dist/tasks/StandardLoopCharacteristics.js +++ b/dist/tasks/StandardLoopCharacteristics.js @@ -5,6 +5,11 @@ Object.defineProperty(exports, "__esModule", { }); exports.StandardLoopCharacteristics = StandardLoopCharacteristics; var _LoopCharacteristics = require("./LoopCharacteristics.js"); +/** + * Standard loop characteristics + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').SerializableElement} loopCharacteristics + */ function StandardLoopCharacteristics(activity, loopCharacteristics) { let { behaviour diff --git a/dist/tasks/SubProcess.js b/dist/tasks/SubProcess.js index aebaa143..d6da2896 100644 --- a/dist/tasks/SubProcess.js +++ b/dist/tasks/SubProcess.js @@ -10,6 +10,12 @@ var _ProcessExecution = require("../process/ProcessExecution.js"); var _messageHelper = require("../messageHelper.js"); const K_EXECUTIONS = Symbol.for('executions'); const K_ON_EXECUTION_COMPLETED = Symbol.for('execution completed handler'); + +/** + * Sub process + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function SubProcess(activityDef, context) { const triggeredByEvent = activityDef.behaviour && activityDef.behaviour.triggeredByEvent; const subProcess = new _Activity.Activity(SubProcessBehaviour, { @@ -39,6 +45,12 @@ function SubProcess(activityDef, context) { }); } } + +/** + * Sub process behaviour + * @param {import('#types').Activity} activity + * @param {import('#types').ContextInstance} context + */ function SubProcessBehaviour(activity, context) { const { id, @@ -66,6 +78,11 @@ Object.defineProperty(SubProcessBehaviour.prototype, 'executions', { return [...this[K_EXECUTIONS]]; } }); + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ SubProcessBehaviour.prototype.execute = function execute(executeMessage) { const { isRootScope, diff --git a/dist/tasks/Task.js b/dist/tasks/Task.js index 682b1720..83eec443 100644 --- a/dist/tasks/Task.js +++ b/dist/tasks/Task.js @@ -7,9 +7,19 @@ exports.Task = Task; exports.TaskBehaviour = TaskBehaviour; var _Activity = require("../activity/Activity.js"); var _messageHelper = require("../messageHelper.js"); +/** + * Task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function Task(activityDef, context) { return new _Activity.Activity(TaskBehaviour, activityDef, context); } + +/** + * Task behaviour + * @param {import('#types').Activity} activity + */ function TaskBehaviour(activity) { const { id, @@ -22,6 +32,11 @@ function TaskBehaviour(activity) { this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.broker = broker; } + +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ TaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/dist/tasks/Transaction.js b/dist/tasks/Transaction.js index 0d4800ec..377bea8f 100644 --- a/dist/tasks/Transaction.js +++ b/dist/tasks/Transaction.js @@ -5,6 +5,11 @@ Object.defineProperty(exports, "__esModule", { }); exports.Transaction = Transaction; var _SubProcess = require("./SubProcess.js"); +/** + * Transaction + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ function Transaction(activityDef, context) { const transaction = { type: 'transaction', diff --git a/docs/Examples.md b/docs/Examples.md index 75754c5f..f4941b2d 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -5,7 +5,7 @@ ```javascript import * as elements from 'bpmn-elements'; -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import { default as serialize, TypeResolver } from 'moddle-context-serializer'; diff --git a/docs/Extend.md b/docs/Extend.md index 784486c0..3a22f674 100644 --- a/docs/Extend.md +++ b/docs/Extend.md @@ -38,7 +38,7 @@ Example with bpmn-moddle: ```js import * as elements from 'bpmn-elements'; -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import MyStartEvent from './extend/MyStartEvent'; import { default as serialize, TypeResolver } from 'moddle-context-serializer'; @@ -127,7 +127,7 @@ import Escalation from './extend/Escalation.js'; import IntermediateThrowEvent from './extend/IntermediateThrowEvent'; import * as elements from 'bpmn-elements'; -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import { default as serialize, TypeResolver } from 'moddle-context-serializer'; diff --git a/docs/Extension.md b/docs/Extension.md index ee086720..c1002540 100644 --- a/docs/Extension.md +++ b/docs/Extension.md @@ -35,7 +35,7 @@ The basic flow is to publish a formatting message on the activity format queue. ```javascript import * as elements from 'bpmn-elements'; -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import { default as serialize, TypeResolver } from 'moddle-context-serializer'; diff --git a/docs/SignalTask.md b/docs/SignalTask.md index aba34752..7057d313 100644 --- a/docs/SignalTask.md +++ b/docs/SignalTask.md @@ -5,7 +5,7 @@ Signal-/User-/Manual task behaviour. ```javascript import * as elements from 'bpmn-elements'; -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import { default as serialize, TypeResolver } from 'moddle-context-serializer'; diff --git a/docs/StartEvent.md b/docs/StartEvent.md index 62c74766..8dcf38af 100644 --- a/docs/StartEvent.md +++ b/docs/StartEvent.md @@ -8,7 +8,7 @@ If a form property is available when start event is executed, the event will wai ```javascript import * as elements from 'bpmn-elements'; -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import { default as serialize, TypeResolver } from 'moddle-context-serializer'; diff --git a/package.json b/package.json index 2937a806..ec8b1eb1 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "@eslint/js": "^10.0.1", "@types/bpmn-moddle": "^10.0.0", "@types/node": "^20.19.40", - "bpmn-moddle": "^9.0.1", + "bpmn-moddle": "^10.0.0", "c8": "^11.0.0", "camunda-bpmn-moddle": "^7.0.1", "chai": "^6.2.1", @@ -113,7 +113,7 @@ "globals": "^17.0.0", "mocha": "^11.0.1", "mocha-cakes-2": "^3.3.0", - "moddle-context-serializer": "^6.0.0", + "moddle-context-serializer": "^5.0.0", "nock": "^14.0.0", "prettier": "^3.2.5", "texample": "^1.0.1" diff --git a/src/Environment.js b/src/Environment.js index fbd366c0..cdb4553a 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -15,12 +15,17 @@ const defaultOptions = new Set(['expressions', 'extensions', 'Logger', 'output', export function Environment(options = {}) { this.options = validateOptions(options); + /** @type {import('#types').IExpressions} */ this.expressions = options.expressions || Expressions(); this.extensions = options.extensions; this.output = options.output || {}; + /** @type {import('#types').IScripts} */ this.scripts = options.scripts || new Scripts(); + /** @type {import('#types').ITimers} */ this.timers = options.timers || new Timers(); + /** @type {import('#types').EnvironmentSettings} */ this.settings = { skipDiscard: true, ...options.settings }; + /** @type {import('#types').LoggerFactory} */ this.Logger = options.Logger || DummyLogger; this[K_SERVICES] = options.services || {}; this[K_VARIABLES] = options.variables || {}; @@ -79,6 +84,7 @@ Environment.prototype.recover = function recover(state) { * Clone the environment, optionally overriding options. Services are merged when * `overrideOptions.services` is supplied. * @param {import('#types').EnvironmentOptions} [overrideOptions] + * @returns {Environment} */ Environment.prototype.clone = function clone(overrideOptions) { const services = this[K_SERVICES]; @@ -171,13 +177,17 @@ Environment.prototype.resolveExpression = function resolveExpression(expression, /** * Register a service callable by name. - * @param {string} name - * @param {CallableFunction} fn + * @param {string} name service function name + * @param {CallableFunction} fn service function */ Environment.prototype.addService = function addService(name, fn) { this[K_SERVICES][name] = fn; }; +/** + * @param {import('#types').EnvironmentOptions} input + * @returns {import('#types').EnvironmentOptions} validated options + */ function validateOptions(input) { const options = {}; for (const key in input) { diff --git a/src/Timers.js b/src/Timers.js index 81ec0cc5..5131c438 100644 --- a/src/Timers.js +++ b/src/Timers.js @@ -3,6 +3,10 @@ const K_TIMER_API = Symbol.for('timers api'); const MAX_DELAY = 2147483647; +/** + * + * @param {*} options + */ export function Timers(options) { this.count = 0; this.options = { diff --git a/src/activity/Dummy.js b/src/activity/Dummy.js index 6a1512a6..90b40309 100644 --- a/src/activity/Dummy.js +++ b/src/activity/Dummy.js @@ -1,5 +1,10 @@ import { cloneParent } from '../messageHelper.js'; +/** + * Placeholder activity for non-executable elements (text annotations, groups, categories). + * @param {import('moddle-context-serializer').Activity} activityDef + * @returns {{ id: string, type: string, name: string | undefined, behaviour: Record, parent: import('#types').ElementParent, placeholder: true }} + */ export function DummyActivity(activityDef) { const { id, type = 'dummy', name, parent, behaviour } = activityDef; return { diff --git a/src/definition/Definition.js b/src/definition/Definition.js index df2128b4..036d0f01 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -226,8 +226,10 @@ Definition.prototype.recover = function recover(state) { * Walk activity graphs to discover sequences. Limited to the activity's owning process * when startId is given, otherwise all processes are shaken. * @param {string} [startId] + * @returns {import('#types').ShakeResult | undefined} */ Definition.prototype.shake = function shake(startId) { + /** @type {import('#types').ShakeResult} */ let result = {}; let bps; if (startId) { diff --git a/src/error/BpmnError.js b/src/error/BpmnError.js index dc843879..b33a63ce 100644 --- a/src/error/BpmnError.js +++ b/src/error/BpmnError.js @@ -1,3 +1,8 @@ +/** + * BPMN error. + * @param {import('moddle-context-serializer').SerializableElement} errorDef + * @param {import('#types').ContextInstance} context + */ export function BpmnErrorActivity(errorDef, context) { const { id, type, name = 'BpmnError', behaviour = {} } = errorDef; const { environment } = context; @@ -10,8 +15,13 @@ export function BpmnErrorActivity(errorDef, context) { resolve, }; + /** + * @param {import('#types').ElementBrokerMessage} executionMessage + * @param {Error} [error] + */ function resolve(executionMessage, error) { const resolveCtx = { ...executionMessage, error }; + /** @type {{ id?: string; type?: string; messageType: string; name: string; code: string | undefined; inner?: Error }} */ const result = { id, type, diff --git a/src/error/Errors.js b/src/error/Errors.js index a6cf62da..32cac5e6 100644 --- a/src/error/Errors.js +++ b/src/error/Errors.js @@ -1,21 +1,39 @@ import { cloneMessage } from '../messageHelper.js'; export class ActivityError extends Error { + /** + * @param {string} description + * @param {import('#types').ElementBrokerMessage} [sourceMessage] + * @param {Error | { name?: string; code?: string | number }} [inner] + */ constructor(description, sourceMessage, inner) { super(description); + /** @type {string} */ this.type = 'ActivityError'; + /** @type {string} */ this.name = this.constructor.name; + /** @type {string} */ this.description = description; - if (sourceMessage) this.source = cloneMessage(sourceMessage, sourceMessage.content?.error && { error: undefined }); + if (sourceMessage) { + /** @type {Pick | undefined} */ + this.source = cloneMessage(sourceMessage, sourceMessage.content?.error && { error: undefined }); + } if (inner) { + /** @type {Error | { name?: string; code?: string | number } | undefined} */ this.inner = inner; if (inner.name) this.name = inner.name; - if (inner.code) this.code = inner.code; + if ('code' in inner && inner.code) { + /** @type {string | number | undefined} */ + this.code = inner.code; + } } } } export class RunError extends ActivityError { + /** + * @param {ConstructorParameters} args + */ constructor(...args) { super(...args); this.type = 'RunError'; @@ -23,18 +41,35 @@ export class RunError extends ActivityError { } export class BpmnError extends Error { - constructor(description, behaviour, sourceMessage, inner) { + /** + * @param {string} description + * @param {{ id?: string; name?: string; errorCode?: string | number; code?: string }} [behaviour] + * @param {import('#types').ElementBrokerMessage} [sourceMessage] + */ + constructor(description, behaviour, sourceMessage) { super(description); + /** @type {string} */ this.type = 'BpmnError'; + /** @type {string} */ this.name = behaviour?.name ?? this.constructor.name; + /** @type {string} */ this.description = description; + /** @type {string | undefined} */ this.code = behaviour?.errorCode?.toString() ?? behaviour?.code; + /** @type {string | undefined} */ this.id = behaviour?.id; - if (sourceMessage) this.source = cloneMessage(sourceMessage, sourceMessage.content?.error && { error: undefined }); - if (inner) this.inner = inner; + if (sourceMessage) { + /** @type {Pick | undefined} */ + this.source = cloneMessage(sourceMessage, sourceMessage.content?.error && { error: undefined }); + } } } +/** + * Get an Error from an error message. + * @param {import('#types').ElementBrokerMessage} errorMessage + * @returns {Error | ActivityError | RunError | BpmnError} + */ export function makeErrorFromMessage(errorMessage) { const { content } = errorMessage; @@ -65,6 +100,10 @@ export function makeErrorFromMessage(errorMessage) { return error; } +/** + * @param {any} test + * @returns {Error | undefined} + */ function isKnownError(test) { if (test instanceof ActivityError) return test; if (test instanceof BpmnError) return test; diff --git a/src/eventDefinitions/CancelEventDefinition.js b/src/eventDefinitions/CancelEventDefinition.js index 4ca8cbc8..8cd6c511 100644 --- a/src/eventDefinitions/CancelEventDefinition.js +++ b/src/eventDefinitions/CancelEventDefinition.js @@ -12,6 +12,7 @@ export function CancelEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; + /** @type {import('#types').EventDefinitionReference} */ this.reference = { referenceType: 'cancel' }; this.isThrowing = isThrowing; this.activity = activity; @@ -27,10 +28,16 @@ Object.defineProperty(CancelEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CancelEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; this[K_COMPLETED] = false; @@ -73,6 +80,9 @@ CancelEventDefinition.prototype.executeCatch = function executeCatch(executeMess broker.publish('event', 'activity.wait', waitContent); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CancelEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { executionId, parent } = executeContent; @@ -88,7 +98,7 @@ CancelEventDefinition.prototype.executeThrow = function executeThrow(executeMess broker.publish('event', 'activity.cancel', cancelContent, { type: 'cancel' }); - return broker.publish('execution', 'execute.completed', cloneContent(executeContent)); + broker.publish('execution', 'execute.completed', cloneContent(executeContent)); }; CancelEventDefinition.prototype._onCatchMessage = function onCatchMessage(_, message) { diff --git a/src/eventDefinitions/CompensateEventDefinition.js b/src/eventDefinitions/CompensateEventDefinition.js index f0f37f28..a6fadf08 100644 --- a/src/eventDefinitions/CompensateEventDefinition.js +++ b/src/eventDefinitions/CompensateEventDefinition.js @@ -16,7 +16,9 @@ export function CompensateEventDefinition(activity, eventDefinition, context) { this.id = id; const type = (this.type = eventDefinition.type); - const reference = (this.reference = { referenceType: 'compensate' }); + const referenceType = 'compensate'; + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { referenceType }; this.isThrowing = isThrowing; this.activity = activity; this.broker = broker; @@ -25,10 +27,10 @@ export function CompensateEventDefinition(activity, eventDefinition, context) { if (!isThrowing) { this[K_COMPLETED] = false; this[K_ASSOCIATIONS] = context.getOutboundAssociations(id); - const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-q`; + const messageQueueName = `${referenceType}-${brokerSafeId(id)}-q`; this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); this[K_COMPENSATE_Q] = broker.assertQueue('compensate-q', { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 400 }); + broker.bindQueue(messageQueueName, 'api', `*.${referenceType}.#`, { durable: true, priority: 400 }); } } @@ -39,10 +41,16 @@ Object.defineProperty(CompensateEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CompensateEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CompensateEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; this[K_COMPLETED] = false; @@ -88,6 +96,9 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute ); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ CompensateEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { parent } = executeContent; diff --git a/src/eventDefinitions/ConditionalEventDefinition.js b/src/eventDefinitions/ConditionalEventDefinition.js index f29e2ebc..770e588f 100644 --- a/src/eventDefinitions/ConditionalEventDefinition.js +++ b/src/eventDefinitions/ConditionalEventDefinition.js @@ -31,6 +31,9 @@ Object.defineProperty(ConditionalEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ConditionalEventDefinition.prototype.execute = function execute(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; diff --git a/src/eventDefinitions/ErrorEventDefinition.js b/src/eventDefinitions/ErrorEventDefinition.js index 12d0ea79..a7031a34 100644 --- a/src/eventDefinitions/ErrorEventDefinition.js +++ b/src/eventDefinitions/ErrorEventDefinition.js @@ -14,11 +14,12 @@ export function ErrorEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - const reference = (this.reference = { + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.errorRef, referenceType: 'throw', - }); + }; this.isThrowing = isThrowing; this.activity = activity; @@ -26,13 +27,13 @@ export function ErrorEventDefinition(activity, eventDefinition) { this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id)); if (!isThrowing) { this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 300 }); + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true, priority: 300 }); } } @@ -43,10 +44,16 @@ Object.defineProperty(ErrorEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ErrorEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; this[K_COMPLETED] = false; @@ -101,6 +108,9 @@ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessa broker.publish('event', 'activity.wait', waitContent); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ ErrorEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { executionId, parent } = executeContent; diff --git a/src/eventDefinitions/EscalationEventDefinition.js b/src/eventDefinitions/EscalationEventDefinition.js index 43acce6d..b47b2728 100644 --- a/src/eventDefinitions/EscalationEventDefinition.js +++ b/src/eventDefinitions/EscalationEventDefinition.js @@ -17,24 +17,25 @@ export function EscalationEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - const reference = (this.reference = { + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.escalationRef, referenceType: 'escalate', - }); + }; this.isThrowing = isThrowing; this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id)); if (!isThrowing) { this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true, priority: 400 }); + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true, priority: 400 }); } } @@ -45,10 +46,16 @@ Object.defineProperty(EscalationEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EscalationEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EscalationEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; this[K_COMPLETED] = false; @@ -82,6 +89,9 @@ EscalationEventDefinition.prototype.executeCatch = function executeCatch(execute broker.publish('event', 'activity.wait', waitContent); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EscalationEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { executionId, parent } = executeContent; diff --git a/src/eventDefinitions/EventDefinitionExecution.js b/src/eventDefinitions/EventDefinitionExecution.js index 4253972f..642f9586 100644 --- a/src/eventDefinitions/EventDefinitionExecution.js +++ b/src/eventDefinitions/EventDefinitionExecution.js @@ -31,6 +31,9 @@ Object.defineProperty(EventDefinitionExecution.prototype, 'stopped', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ EventDefinitionExecution.prototype.execute = function execute(executeMessage) { const content = executeMessage.content; diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 9ad5339e..29df0bee 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -14,6 +14,7 @@ export function LinkEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; + /** @type {import('#types').EventDefinitionReference} */ this.reference = { id: behaviour.name, linkName: behaviour.name, @@ -61,10 +62,16 @@ Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ LinkEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; @@ -89,6 +96,9 @@ LinkEventDefinition.prototype.executeCatch = function executeCatch(executeMessag return broker.publish('execution', 'execute.completed', cloneContent(executeContent, { output: linkMessage, state: 'catch' })); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { executionId, parent } = executeContent; diff --git a/src/eventDefinitions/MessageEventDefinition.js b/src/eventDefinitions/MessageEventDefinition.js index e0bb4639..8d83bc2f 100644 --- a/src/eventDefinitions/MessageEventDefinition.js +++ b/src/eventDefinitions/MessageEventDefinition.js @@ -15,24 +15,25 @@ export function MessageEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - const reference = (this.reference = { + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.messageRef, referenceType: 'message', - }); + }; this.isThrowing = isThrowing; this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id)); if (!isThrowing) { this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true }); } } @@ -43,10 +44,16 @@ Object.defineProperty(MessageEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ MessageEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; this[K_COMPLETED] = false; @@ -92,6 +99,9 @@ MessageEventDefinition.prototype.executeCatch = function executeCatch(executeMes broker.publish('event', 'activity.wait', waitContent); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ MessageEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { executionId, parent } = executeContent; diff --git a/src/eventDefinitions/SignalEventDefinition.js b/src/eventDefinitions/SignalEventDefinition.js index dd586d1c..e098cd7c 100644 --- a/src/eventDefinitions/SignalEventDefinition.js +++ b/src/eventDefinitions/SignalEventDefinition.js @@ -15,24 +15,25 @@ export function SignalEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - const reference = (this.reference = { + /** @type {import('#types').EventDefinitionReference} */ + this.reference = { name: 'anonymous', ...behaviour.signalRef, referenceType: 'signal', - }); + }; this.isThrowing = isThrowing; this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - const referenceElement = (this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id)); + const referenceElement = (this[K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id)); if (!isThrowing && isStart) { this[K_COMPLETED] = false; const referenceId = referenceElement ? referenceElement.id : 'anonymous'; - const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; + const messageQueueName = `${this.reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`; this[K_MESSAGE_Q] = broker.assertQueue(messageQueueName, { autoDelete: false, durable: true }); - broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, { durable: true }); + broker.bindQueue(messageQueueName, 'api', `*.${this.reference.referenceType}.#`, { durable: true }); } } @@ -43,10 +44,16 @@ Object.defineProperty(SignalEventDefinition.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ SignalEventDefinition.prototype.execute = function execute(executeMessage) { return this.isThrowing ? this.executeThrow(executeMessage) : this.executeCatch(executeMessage); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) { this[K_EXECUTE_MESSAGE] = executeMessage; this[K_COMPLETED] = false; @@ -92,6 +99,9 @@ SignalEventDefinition.prototype.executeCatch = function executeCatch(executeMess broker.publish('event', 'activity.wait', waitContent); }; +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ SignalEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) { const executeContent = executeMessage.content; const { executionId, parent } = executeContent; diff --git a/src/eventDefinitions/TerminateEventDefinition.js b/src/eventDefinitions/TerminateEventDefinition.js index 82bbcc01..8a377edd 100644 --- a/src/eventDefinitions/TerminateEventDefinition.js +++ b/src/eventDefinitions/TerminateEventDefinition.js @@ -16,6 +16,9 @@ export function TerminateEventDefinition(activity, eventDefinition) { this.logger = environment.Logger(type.toLowerCase()); } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ TerminateEventDefinition.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; diff --git a/src/eventDefinitions/TimerEventDefinition.js b/src/eventDefinitions/TimerEventDefinition.js index a25b0cc6..2132af63 100644 --- a/src/eventDefinitions/TimerEventDefinition.js +++ b/src/eventDefinitions/TimerEventDefinition.js @@ -20,9 +20,9 @@ export function TimerEventDefinition(activity, eventDefinition) { this.eventDefinition = eventDefinition; const { timeDuration, timeCycle, timeDate } = eventDefinition.behaviour || {}; - if (timeDuration) this.timeDuration = timeDuration; - if (timeCycle) this.timeCycle = timeCycle; - if (timeDate) this.timeDate = timeDate; + if (timeDuration) this.timeDuration = /** @type {string} */ (timeDuration); + if (timeCycle) this.timeCycle = /** @type {string} */ (timeCycle); + if (timeDate) this.timeDate = /** @type {string} */ (timeDate); this.broker = activity.broker; this.logger = environment.Logger(type.toLowerCase()); @@ -39,17 +39,22 @@ Object.defineProperty(TimerEventDefinition.prototype, 'executionId', { }); Object.defineProperty(TimerEventDefinition.prototype, 'stopped', { + /** @returns {boolean} */ get() { return this[K_STOPPED]; }, }); Object.defineProperty(TimerEventDefinition.prototype, 'timer', { + /** @returns {import('#types').Timer | null} */ get() { return this[K_TIMER]; }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + */ TimerEventDefinition.prototype.execute = function execute(executeMessage) { const { routingKey: executeKey, redelivered: isResumed } = executeMessage.fields; const timer = this[K_TIMER]; @@ -193,6 +198,7 @@ TimerEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, } }; +/** @private */ TimerEventDefinition.prototype._stop = function stop() { this[K_STOPPED] = true; const timer = this[K_TIMER]; @@ -202,6 +208,11 @@ TimerEventDefinition.prototype._stop = function stop() { broker.cancel(`_api-delegated-${this.executionId}`); }; +/** + * Parse timer + * @param {string} timerType + * @param {string} value + */ TimerEventDefinition.prototype.parse = function parse(timerType, value) { let repeat, delay, expireAt; const now = new Date(); diff --git a/src/events/BoundaryEvent.js b/src/events/BoundaryEvent.js index 83737172..dae9f6e6 100644 --- a/src/events/BoundaryEvent.js +++ b/src/events/BoundaryEvent.js @@ -8,10 +8,19 @@ const K_ATTACHED_TAGS = Symbol.for('attachedConsumers'); const K_COMPLETE_CONTENT = Symbol.for('completeContent'); const K_SHOVELS = Symbol.for('shovels'); +/** + * Boundary event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function BoundaryEvent(activityDef, context) { return new Activity(BoundaryEventBehaviour, activityDef, context); } +/** + * Boundary event behaviour + * @param {import('#types').Activity} activity + */ export function BoundaryEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -38,6 +47,10 @@ Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ BoundaryEventBehaviour.prototype.execute = function execute(executeMessage) { const { isRootScope, executionId } = executeMessage.content; diff --git a/src/events/EndEvent.js b/src/events/EndEvent.js index a91c9f4d..c88d9f8c 100644 --- a/src/events/EndEvent.js +++ b/src/events/EndEvent.js @@ -3,10 +3,19 @@ import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExe import { cloneContent } from '../messageHelper.js'; import { K_EXECUTION } from '../constants.js'; +/** + * End event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function EndEvent(activityDef, context) { return new Activity(EndEventBehaviour, { ...activityDef, isThrowing: true }, context); } +/** + * End event behaviour + * @param {import('#types').Activity} activity + */ export function EndEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -14,6 +23,10 @@ export function EndEventBehaviour(activity) { this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ EndEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[K_EXECUTION]; if (execution) { diff --git a/src/events/IntermediateCatchEvent.js b/src/events/IntermediateCatchEvent.js index 6f2237f3..b6f8f19b 100644 --- a/src/events/IntermediateCatchEvent.js +++ b/src/events/IntermediateCatchEvent.js @@ -3,10 +3,19 @@ import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExe import { cloneContent } from '../messageHelper.js'; import { K_EXECUTION } from '../constants.js'; +/** + * Intermediate catch event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function IntermediateCatchEvent(activityDef, context) { return new Activity(IntermediateCatchEventBehaviour, { ...activityDef, isCatching: true }, context); } +/** + * Intermediate catch event behaviour + * @param {import('#types').Activity} activity + */ export function IntermediateCatchEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -14,6 +23,10 @@ export function IntermediateCatchEventBehaviour(activity) { this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ IntermediateCatchEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[K_EXECUTION]; if (execution) { diff --git a/src/events/IntermediateThrowEvent.js b/src/events/IntermediateThrowEvent.js index 5edb2156..b02857ce 100644 --- a/src/events/IntermediateThrowEvent.js +++ b/src/events/IntermediateThrowEvent.js @@ -3,10 +3,19 @@ import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExe import { cloneContent } from '../messageHelper.js'; import { K_EXECUTION } from '../constants.js'; +/** + * Intermediate throw event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function IntermediateThrowEvent(activityDef, context) { return new Activity(IntermediateThrowEventBehaviour, { ...activityDef, isThrowing: true }, context); } +/** + * Intermediate throw event behaviour + * @param {import('#types').Activity} activity + */ export function IntermediateThrowEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -14,6 +23,10 @@ export function IntermediateThrowEventBehaviour(activity) { this[K_EXECUTION] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions); } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ IntermediateThrowEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[K_EXECUTION]; if (execution) { diff --git a/src/events/StartEvent.js b/src/events/StartEvent.js index 0ca790a7..bd3da4f9 100644 --- a/src/events/StartEvent.js +++ b/src/events/StartEvent.js @@ -3,10 +3,19 @@ import { EventDefinitionExecution } from '../eventDefinitions/EventDefinitionExe import { cloneContent } from '../messageHelper.js'; import { K_EXECUTE_MESSAGE, K_EXECUTION } from '../constants.js'; +/** + * Start event + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function StartEvent(activityDef, context) { return new Activity(StartEventBehaviour, activityDef, context); } +/** + * Start event behaviour + * @param {import('#types').Activity} activity + */ export function StartEventBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -21,6 +30,10 @@ Object.defineProperty(StartEventBehaviour.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ StartEventBehaviour.prototype.execute = function execute(executeMessage) { const execution = this[K_EXECUTION]; if (execution) { diff --git a/src/gateways/EventBasedGateway.js b/src/gateways/EventBasedGateway.js index c7caac96..cac72543 100644 --- a/src/gateways/EventBasedGateway.js +++ b/src/gateways/EventBasedGateway.js @@ -2,10 +2,20 @@ import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; import { K_COMPLETED, K_TARGETS } from '../constants.js'; +/** + * Event based gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function EventBasedGateway(activityDef, context) { return new Activity(EventBasedGatewayBehaviour, activityDef, context); } +/** + * Event based gateway behaviour + * @param {import('#types').Activity} activity + * @param {import('#types').ContextInstance} context + */ export function EventBasedGatewayBehaviour(activity, context) { this.id = activity.id; this.type = activity.type; @@ -15,6 +25,10 @@ export function EventBasedGatewayBehaviour(activity, context) { this[K_TARGETS] = new Set(activity.outbound.map((flow) => context.getActivityById(flow.targetId))); } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const { executionId, outbound = [], outboundTaken } = executeContent; diff --git a/src/gateways/ExclusiveGateway.js b/src/gateways/ExclusiveGateway.js index 3a57b71a..70623ef5 100644 --- a/src/gateways/ExclusiveGateway.js +++ b/src/gateways/ExclusiveGateway.js @@ -1,10 +1,19 @@ import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; +/** + * Exclusive gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function ExclusiveGateway(activityDef, context) { return new Activity(ExclusiveGatewayBehaviour, activityDef, context); } +/** + * Exclusive gateway behaviour + * @param {import('#types').Activity} activity + */ export function ExclusiveGatewayBehaviour(activity) { const { id, type, broker } = activity; this.id = id; @@ -12,6 +21,10 @@ export function ExclusiveGatewayBehaviour(activity) { this.broker = broker; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ExclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { this.broker.publish('execution', 'execute.completed', cloneContent(content, { outboundTakeOne: true })); }; diff --git a/src/gateways/InclusiveGateway.js b/src/gateways/InclusiveGateway.js index 26ff692c..a42538e8 100644 --- a/src/gateways/InclusiveGateway.js +++ b/src/gateways/InclusiveGateway.js @@ -1,10 +1,19 @@ import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; +/** + * Inclusive gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function InclusiveGateway(activityDef, context) { return new Activity(InclusiveGatewayBehaviour, activityDef, context); } +/** + * Inclusive gateway behaviour + * @param {import('#types').Activity} activity + */ export function InclusiveGatewayBehaviour(activity) { const { id, type, broker } = activity; this.id = id; @@ -12,6 +21,10 @@ export function InclusiveGatewayBehaviour(activity) { this.broker = broker; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ InclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { this.broker.publish('execution', 'execute.completed', cloneContent(content)); }; diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index eb4dfa55..56b64209 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -8,6 +8,11 @@ const STATE_SETUP = 'setup'; const K_PEERS = Symbol.for('peers'); const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); +/** + * Parallel gateway + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function ParallelGateway(activityDef, context) { const activity = new Activity(ParallelGatewayBehaviour, { ...activityDef, isParallelGateway: true }, context); @@ -44,6 +49,10 @@ export function ParallelGateway(activityDef, context) { } } +/** + * Parallel gateway behaviour + * @param {import('#types').Activity} activity + */ export function ParallelGatewayBehaviour(activity) { this.id = activity.id; this.type = activity.type; @@ -61,6 +70,10 @@ Object.defineProperty(ParallelGatewayBehaviour.prototype, 'executionId', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { const routingKey = executeMessage.fields.routingKey; const isRedelivered = executeMessage.fields.redelivered; diff --git a/src/io/BpmnIO.js b/src/io/BpmnIO.js index fc79d50f..f3d134d7 100644 --- a/src/io/BpmnIO.js +++ b/src/io/BpmnIO.js @@ -1,3 +1,9 @@ +/** + * Built-in IO extension. Composes the activity's ioSpecification and properties behaviours. + * @param {import('#types').Activity} activity + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IExtension} + */ export function BpmnIO(activity, context) { this.activity = activity; this.context = context; @@ -15,6 +21,9 @@ Object.defineProperty(BpmnIO.prototype, 'hasIo', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} message + */ BpmnIO.prototype.activate = function activate(message) { const properties = this.properties, specification = this.specification; @@ -22,6 +31,9 @@ BpmnIO.prototype.activate = function activate(message) { if (specification) specification.activate(message); }; +/** + * @param {import('#types').ElementBrokerMessage} message + */ BpmnIO.prototype.deactivate = function deactivate(message) { const properties = this.properties, specification = this.specification; diff --git a/src/io/EnvironmentDataObject.js b/src/io/EnvironmentDataObject.js index fcd4a332..8cd066da 100644 --- a/src/io/EnvironmentDataObject.js +++ b/src/io/EnvironmentDataObject.js @@ -1,7 +1,7 @@ /** - * Builtin data object - * @param {import('moddle-context-serializer').DataObject>} dataObjectDef - * @param {import('../Context.js').ContextInstance} context + * Builtin data object. Reads from / writes to `environment.variables._data`. + * @param {import('moddle-context-serializer').DataObject} dataObjectDef + * @param {import('#types').ContextInstance} context * @satisfies {import('#types').IIOData} */ export function EnvironmentDataObject(dataObjectDef, { environment }) { @@ -9,11 +9,19 @@ export function EnvironmentDataObject(dataObjectDef, { environment }) { this.id = id; this.type = type; this.name = name; + /** @type {Record} */ this.behaviour = behaviour; + /** @type {import('moddle-context-serializer').Parent | undefined} */ this.parent = parent; this.environment = environment; } +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {Record} [messageProperties] + */ EnvironmentDataObject.prototype.read = function read(broker, exchange, routingKeyPrefix, messageProperties) { const environment = this.environment; const value = environment.variables._data?.[this.id]; @@ -21,6 +29,13 @@ EnvironmentDataObject.prototype.read = function read(broker, exchange, routingKe return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {any} value + * @param {Record} [messageProperties] + */ EnvironmentDataObject.prototype.write = function write(broker, exchange, routingKeyPrefix, value, messageProperties) { const environment = this.environment; environment.variables._data = environment.variables._data || {}; diff --git a/src/io/EnvironmentDataStore.js b/src/io/EnvironmentDataStore.js index e549d16f..018e47c0 100644 --- a/src/io/EnvironmentDataStore.js +++ b/src/io/EnvironmentDataStore.js @@ -1,13 +1,27 @@ +/** + * Builtin data store. Reads from / writes to `environment.variables._data`. + * @param {import('moddle-context-serializer').DataStore} dataStoreDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IIOData} + */ export function EnvironmentDataStore(dataStoreDef, { environment }) { const { id, type, name, behaviour, parent } = dataStoreDef; this.id = id; this.type = type; this.name = name; + /** @type {Record} */ this.behaviour = behaviour; + /** @type {import('moddle-context-serializer').Parent | undefined} */ this.parent = parent; this.environment = environment; } +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {Record} [messageProperties] + */ EnvironmentDataStore.prototype.read = function read(broker, exchange, routingKeyPrefix, messageProperties) { const environment = this.environment; const value = environment.variables._data?.[this.id]; @@ -15,6 +29,13 @@ EnvironmentDataStore.prototype.read = function read(broker, exchange, routingKey return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {any} value + * @param {Record} [messageProperties] + */ EnvironmentDataStore.prototype.write = function write(broker, exchange, routingKeyPrefix, value, messageProperties) { const environment = this.environment; environment.variables._data = environment.variables._data || {}; diff --git a/src/io/EnvironmentDataStoreReference.js b/src/io/EnvironmentDataStoreReference.js index 94714fe3..d8295e12 100644 --- a/src/io/EnvironmentDataStoreReference.js +++ b/src/io/EnvironmentDataStoreReference.js @@ -1,13 +1,27 @@ +/** + * Builtin data store reference. Reads from / writes to `environment.variables._data`. + * @param {import('moddle-context-serializer').DataStore} dataObjectDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IIOData} + */ export function EnvironmentDataStoreReference(dataObjectDef, { environment }) { const { id, type, name, behaviour, parent } = dataObjectDef; this.id = id; this.type = type; this.name = name; + /** @type {Record} */ this.behaviour = behaviour; + /** @type {import('moddle-context-serializer').Parent | undefined} */ this.parent = parent; this.environment = environment; } +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {Record} [messageProperties] + */ EnvironmentDataStoreReference.prototype.read = function read(broker, exchange, routingKeyPrefix, messageProperties) { const environment = this.environment; const value = environment.variables._data?.[this.id]; @@ -15,6 +29,13 @@ EnvironmentDataStoreReference.prototype.read = function read(broker, exchange, r return broker.publish(exchange, `${routingKeyPrefix}response`, content, messageProperties); }; +/** + * @param {import('smqp').Broker} broker + * @param {string} exchange + * @param {string} routingKeyPrefix + * @param {any} value + * @param {Record} [messageProperties] + */ EnvironmentDataStoreReference.prototype.write = function write(broker, exchange, routingKeyPrefix, value, messageProperties) { const environment = this.environment; environment.variables._data = environment.variables._data || {}; diff --git a/src/io/InputOutputSpecification.js b/src/io/InputOutputSpecification.js index e1fb5f5f..2454935c 100644 --- a/src/io/InputOutputSpecification.js +++ b/src/io/InputOutputSpecification.js @@ -2,6 +2,13 @@ import { getPropertyValue } from '../getPropertyValue.js'; import { brokerSafeId } from '../shared.js'; import { K_CONSUMING } from '../constants.js'; +/** + * Activity ioSpecification behaviour. Reads bound data objects on enter and writes them on completion. + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').IoSpecification} ioSpecificationDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IExtension} + */ export function IoSpecification(activity, ioSpecificationDef, context) { const { id, type = 'iospecification', behaviour = {} } = ioSpecificationDef; this.id = id; @@ -12,6 +19,9 @@ export function IoSpecification(activity, ioSpecificationDef, context) { this.context = context; } +/** + * @param {import('#types').ElementBrokerMessage} [message] + */ IoSpecification.prototype.activate = function activate(message) { if (this[K_CONSUMING]) return; if (message?.fields.redelivered && message.fields.routingKey === 'run.start') { diff --git a/src/io/Properties.js b/src/io/Properties.js index fa50517d..1c85fff7 100644 --- a/src/io/Properties.js +++ b/src/io/Properties.js @@ -3,6 +3,13 @@ import { K_CONSUMING } from '../constants.js'; const K_PROPERTIES = Symbol.for('properties'); +/** + * Activity properties behaviour. Resolves bound data input/output references during the run. + * @param {import('#types').Activity} activity + * @param {{ type: 'properties', values: import('moddle-context-serializer').IElement[] }} propertiesDef + * @param {import('#types').ContextInstance} context + * @satisfies {import('#types').IExtension} + */ export function Properties(activity, propertiesDef, context) { this.activity = activity; this.broker = activity.broker; @@ -57,6 +64,9 @@ export function Properties(activity, propertiesDef, context) { } } +/** + * @param {import('#types').ElementBrokerMessage} message + */ Properties.prototype.activate = function activate(message) { if (this[K_CONSUMING]) return; if (message.fields.redelivered && message.fields.routingKey === 'run.start') { diff --git a/src/process/Lane.js b/src/process/Lane.js index 448aca1a..35f19c3f 100644 --- a/src/process/Lane.js +++ b/src/process/Lane.js @@ -14,11 +14,14 @@ export function Lane(process, laneDefinition) { this.id = id; this.type = type; + /** @type {string} */ this.name = behaviour.name; + /** @type {import('moddle-context-serializer').Parent} */ this.parent = { id: process.id, type: process.type, }; + /** @type {Record} */ this.behaviour = { ...behaviour }; this.environment = environment; this.broker = broker; diff --git a/src/process/Process.js b/src/process/Process.js index 744c53c1..456c0639 100644 --- a/src/process/Process.js +++ b/src/process/Process.js @@ -216,6 +216,7 @@ Process.prototype.recover = function recover(state) { /** * Walk activity graph from the given start id, or every start activity when omitted. * @param {string} [startId] + * @returns {import('#types').ShakeResult} */ Process.prototype.shake = function shake(startId) { if (this.isRunning) return this.execution.shake(startId); @@ -487,7 +488,7 @@ Process.prototype.getSequenceFlows = function getSequenceFlows() { /** * @param {string} laneId - * @returns {import('./Lane.js') | undefined} + * @returns {import('./Lane.js').Lane | undefined} */ Process.prototype.getLaneById = function getLaneById(laneId) { return this[K_LANES]?.find((lane) => lane.id === laneId); diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index df177bf5..aeb0a681 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -261,6 +261,7 @@ ProcessExecution.prototype.recover = function recover(state) { /** * Walk activity graph from the given start id, or every start activity when omitted. * @param {string} [fromId] + * @returns {import('#types').ShakeResult} */ ProcessExecution.prototype.shake = function shake(fromId) { return Object.fromEntries(this._shakeElements(fromId).sequences); @@ -293,7 +294,7 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) { */ ProcessExecution.prototype.discard = function discard() { this[K_STATUS] = 'discard'; - return this[K_ACTIVITY_Q].queueMessage( + this[K_ACTIVITY_Q].queueMessage( { routingKey: 'execution.discard' }, { id: this.id, @@ -308,7 +309,7 @@ ProcessExecution.prototype.discard = function discard() { * Queue a cancel message that propagates to all running children. */ ProcessExecution.prototype.cancel = function discard() { - return this[K_ACTIVITY_Q].queueMessage( + this[K_ACTIVITY_Q].queueMessage( { routingKey: 'execution.cancel' }, { id: this.id, @@ -580,6 +581,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { result.sequences.set(shakeId, seqnce); } seqnce.push({ ...content, isLooped: routingKey === 'flow.shake.loop' }); + break; } } diff --git a/src/tasks/CallActivity.js b/src/tasks/CallActivity.js index c519dc41..c122a939 100644 --- a/src/tasks/CallActivity.js +++ b/src/tasks/CallActivity.js @@ -3,20 +3,24 @@ import { ActivityError } from '../error/Errors.js'; import { cloneContent } from '../messageHelper.js'; /** - * Create call activity + * Call activity * @param {import('moddle-context-serializer').Activity} activityDef - * @param {import('../Context.js').ContextInstance} context - * @returns Call activity + * @param {import('#types').ContextInstance} context */ export function CallActivity(activityDef, context) { return new Activity(CallActivityBehaviour, activityDef, context); } +/** + * Call activity behaviour + * @param {import('#types').Activity} activity + */ export function CallActivityBehaviour(activity) { const { id, type, behaviour = {} } = activity; this.id = id; this.type = type; this.calledElement = behaviour.calledElement; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; @@ -24,6 +28,10 @@ export function CallActivityBehaviour(activity) { this.environment = activity.environment; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ CallActivityBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/src/tasks/LoopCharacteristics.js b/src/tasks/LoopCharacteristics.js index ec695a50..ed1610c9 100644 --- a/src/tasks/LoopCharacteristics.js +++ b/src/tasks/LoopCharacteristics.js @@ -1,18 +1,26 @@ import { RunError } from '../error/Errors.js'; import { cloneContent, cloneMessage, unshiftParent, cloneParent } from '../messageHelper.js'; +/** + * Loop characteristics + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').SerializableElement} loopCharacteristics + */ export function LoopCharacteristics(activity, loopCharacteristics) { this.activity = activity; this.loopCharacteristics = loopCharacteristics; const { type = 'LoopCharacteristics', behaviour = {} } = loopCharacteristics; this.type = type; const { isSequential = false, collection } = behaviour; + /** @type {boolean} */ this.isSequential = isSequential; + /** @type {string | undefined} */ this.collection = collection; let completionCondition, startCondition, loopCardinality; if ('loopCardinality' in behaviour) loopCardinality = behaviour.loopCardinality; else if ('loopMaximum' in behaviour) loopCardinality = behaviour.loopMaximum; + /** @type {number | undefined} */ this.loopCardinality = loopCardinality; if (behaviour.loopCondition) { @@ -25,15 +33,21 @@ export function LoopCharacteristics(activity, loopCharacteristics) { if (collection) { this.loopType = 'collection'; + /** @type {string | undefined} */ this.elementVariable = behaviour.elementVariable || 'item'; } else if (completionCondition) this.loopType = 'complete condition'; else if (startCondition) this.loopType = 'start condition'; else if (loopCardinality) this.loopType = 'cardinality'; + /** @type {Characteristics} */ this.characteristics = null; this.execution = null; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ LoopCharacteristics.prototype.execute = function execute(executeMessage) { if (!executeMessage) throw new TypeError('LoopCharacteristics execution requires message'); const chr = (this.characteristics = this.characteristics || new Characteristics(this.activity, this.loopCharacteristics, executeMessage)); @@ -45,12 +59,20 @@ LoopCharacteristics.prototype.execute = function execute(executeMessage) { return execution.execute(executeMessage); }; +/** + * @param {import('#types').Activity} activity + * @param {Characteristics} characteristics + */ function SequentialLoopCharacteristics(activity, characteristics) { this.activity = activity; this.id = activity.id; this.characteristics = characteristics; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ SequentialLoopCharacteristics.prototype.execute = function execute(executeMessage) { const { routingKey: executeRoutingKey, redelivered: isRedelivered } = executeMessage.fields || {}; const chr = this.characteristics; @@ -73,11 +95,11 @@ SequentialLoopCharacteristics.prototype._startNext = function startNext(index, i if (!content) return; if (chr.isStartConditionMet({ content })) { - chr.debug('start condition met'); + chr._debug('start condition met'); return; } - chr.debug(`${ignoreIfExecuting ? 'resume' : 'start'} sequential iteration index ${content.index}`); + chr._debug(`${ignoreIfExecuting ? 'resume' : 'start'} sequential iteration index ${content.index}`); const broker = this.activity.broker; broker.publish('execution', 'execute.iteration.next', { ...content, @@ -108,14 +130,18 @@ SequentialLoopCharacteristics.prototype._onCompleteMessage = function onComplete }); if (chr.isCompletionConditionMet(message, loopOutput)) { - chr.debug('complete condition met'); + chr._debug('complete condition met'); } else if (this._startNext(content.index + 1)) return; - chr.debug('sequential loop completed'); + chr._debug('sequential loop completed'); return chr.complete(content); }; +/** + * @param {import('#types').Activity} activity + * @param {Characteristics} characteristics + */ function ParallelLoopCharacteristics(activity, characteristics) { this.activity = activity; this.id = activity.id; @@ -125,6 +151,10 @@ function ParallelLoopCharacteristics(activity, characteristics) { this.discarded = 0; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ParallelLoopCharacteristics.prototype.execute = function execute(executeMessage) { const chr = this.characteristics; if (!chr.cardinality) throw new RunError(`<${this.id}> cardinality or collection is required in parallel loops`, executeMessage); @@ -150,7 +180,7 @@ ParallelLoopCharacteristics.prototype._startBatch = function startBatch() { let startContent = chr.next(this.index); do { - chr.debug(`start parallel iteration index ${this.index}`); + chr._debug(`start parallel iteration index ${this.index}`); batch.add(startContent); this.running++; this.index++; @@ -211,6 +241,12 @@ ParallelLoopCharacteristics.prototype._onCompleteMessage = function onCompleteMe } }; +/** + * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').SerializableElement} loopCharacteristics + * @param {import('#types').ElementBrokerMessage} executeMessage + */ function Characteristics(activity, loopCharacteristics, executeMessage) { this.activity = activity; const behaviour = (this.behaviour = loopCharacteristics.behaviour || {}); @@ -221,27 +257,31 @@ function Characteristics(activity, loopCharacteristics, executeMessage) { this.broker = activity.broker; this.parentExecutionId = executeMessage.content.executionId; + /** @type {boolean} */ this.isSequential = behaviour.isSequential || false; this.output = executeMessage.content.output || []; this.parent = unshiftParent(executeMessage.content.parent, executeMessage.content); - if ('loopCardinality' in behaviour) this.loopCardinality = behaviour.loopCardinality; - else if ('loopMaximum' in behaviour) this.loopCardinality = behaviour.loopMaximum; + if ('loopCardinality' in behaviour) this.loopCardinality = /** @type {number} */ (behaviour.loopCardinality); + else if ('loopMaximum' in behaviour) this.loopCardinality = /** @type {number} */ (behaviour.loopMaximum); if (behaviour.loopCondition) { - if (behaviour.testBefore) this.startCondition = behaviour.loopCondition; - else this.completionCondition = behaviour.loopCondition; + if (behaviour.testBefore) this.startCondition = /** @type {string} */ (behaviour.loopCondition); + else this.completionCondition = /** @type {string} */ (behaviour.loopCondition); } if (behaviour.completionCondition) { + /** @type {string} */ this.completionCondition = behaviour.completionCondition; } const collection = (this.collection = this.getCollection()); if (collection) { + /** @type {string} */ this.elementVariable = behaviour.elementVariable || 'item'; } this.cardinality = this.getCardinality(collection); + /** @private */ this.onApiMessage = this.onApiMessage.bind(this); const environment = activity.environment; @@ -249,6 +289,7 @@ function Characteristics(activity, loopCharacteristics, executeMessage) { this.batchSize = environment.settings.batchSize || 50; } +/** @returns {import('#types').ElementMessageContent} */ Characteristics.prototype.getContent = function getContent() { return { ...cloneContent(this.message.content), @@ -258,6 +299,10 @@ Characteristics.prototype.getContent = function getContent() { }; }; +/** + * @param {number} index + * @returns {import('#types').ElementMessageContent} + */ Characteristics.prototype.next = function next(index) { const cardinality = this.cardinality; if (cardinality > 0 && index >= cardinality) return; @@ -281,6 +326,10 @@ Characteristics.prototype.next = function next(index) { return content; }; +/** + * @param {any} [collection] + * @returns {number | undefined} cardinality + */ Characteristics.prototype.getCardinality = function getCardinality(collection) { const collectionLen = this.collection && Array.isArray(collection) ? collection.length : undefined; if (!this.loopCardinality) { @@ -294,22 +343,34 @@ Characteristics.prototype.getCardinality = function getCardinality(collection) { return Number(value); }; +/** @returns {Array | undefined} */ Characteristics.prototype.getCollection = function getCollection() { const collectionExpression = this.behaviour.collection; if (!collectionExpression) return; return this.activity.environment.resolveExpression(collectionExpression, this.message); }; +/** + * @param {import('#types').ElementBrokerMessage} message + */ Characteristics.prototype.isStartConditionMet = function isStartConditionMet(message) { if (!this.startCondition) return false; return this.activity.environment.resolveExpression(this.startCondition, cloneMessage(message)); }; +/** + * @param {import('#types').ElementBrokerMessage} message + */ Characteristics.prototype.isCompletionConditionMet = function isCompletionConditionMet(message) { if (!this.completionCondition) return false; return this.activity.environment.resolveExpression(this.completionCondition, cloneMessage(message, { loopOutput: this.output })); }; +/** + * @param {import('#types').ElementMessageContent} content + * @param {boolean} [allDiscarded] + * @returns {void} + */ Characteristics.prototype.complete = function complete(content, allDiscarded) { this.stop(); @@ -320,6 +381,9 @@ Characteristics.prototype.complete = function complete(content, allDiscarded) { }); }; +/** + * @param {import('#types').ElementBrokerMessage} onIterationCompleteMessage + */ Characteristics.prototype.subscribe = function subscribe(onIterationCompleteMessage) { this.broker.subscribeTmp( 'api', @@ -346,6 +410,7 @@ Characteristics.prototype.subscribe = function subscribe(onIterationCompleteMess } }; +/** @internal */ Characteristics.prototype.onApiMessage = function onApiMessage(_, message) { switch (message.properties.type) { case 'stop': @@ -360,6 +425,7 @@ Characteristics.prototype.stop = function stop() { this.broker.cancel('_api-multi-instance-tag'); }; -Characteristics.prototype.debug = function debug(msg) { +/** @internal */ +Characteristics.prototype._debug = function debug(msg) { this.logger.debug(`<${this.parentExecutionId} (${this.id})> ${msg}`); }; diff --git a/src/tasks/ReceiveTask.js b/src/tasks/ReceiveTask.js index 47008acf..d6d244f3 100644 --- a/src/tasks/ReceiveTask.js +++ b/src/tasks/ReceiveTask.js @@ -2,6 +2,11 @@ import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; import { K_COMPLETED, K_EXECUTE_MESSAGE, K_REFERENCE_ELEMENT, K_REFERENCE_INFO } from '../constants.js'; +/** + * Receive task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function ReceiveTask(activityDef, context) { const task = new Activity(ReceiveTaskBehaviour, activityDef, context); @@ -11,6 +16,10 @@ export function ReceiveTask(activityDef, context) { return task; } +/** + * Receive task behaviour + * @param {import('#types').Activity} activity + */ export function ReceiveTaskBehaviour(activity) { const { id, type, behaviour } = activity; @@ -31,6 +40,10 @@ export function ReceiveTaskBehaviour(activity) { this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ReceiveTaskBehaviour.prototype.execute = function execute(executeMessage) { return new ReceiveTaskExecution(this).execute(executeMessage); }; diff --git a/src/tasks/ScriptTask.js b/src/tasks/ScriptTask.js index c99aeefc..6925e1d2 100644 --- a/src/tasks/ScriptTask.js +++ b/src/tasks/ScriptTask.js @@ -3,10 +3,19 @@ import { ExecutionScope } from '../activity/ExecutionScope.js'; import { ActivityError } from '../error/Errors.js'; import { cloneContent, cloneMessage } from '../messageHelper.js'; +/** + * Script task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function ScriptTask(activityDef, context) { return new Activity(ScriptTaskBehaviour, activityDef, context); } +/** + * Script task behaviour + * @param {import('#types').Activity} activity + */ export function ScriptTaskBehaviour(activity) { const { id, type, behaviour } = activity; @@ -22,6 +31,10 @@ export function ScriptTaskBehaviour(activity) { environment.registerScript(activity); } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ScriptTaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/src/tasks/ServiceImplementation.js b/src/tasks/ServiceImplementation.js index 03bb4877..3a6dcfd3 100644 --- a/src/tasks/ServiceImplementation.js +++ b/src/tasks/ServiceImplementation.js @@ -1,4 +1,8 @@ import { ExecutionScope } from '../activity/ExecutionScope.js'; +/** + * Service implementation + * @param {import('#types').Activity} activity + */ export function ServiceImplementation(activity) { this.type = `${activity.type}:implementation`; this.implementation = activity.behaviour.implementation; diff --git a/src/tasks/ServiceTask.js b/src/tasks/ServiceTask.js index 1f2d9112..d36d7534 100644 --- a/src/tasks/ServiceTask.js +++ b/src/tasks/ServiceTask.js @@ -2,10 +2,19 @@ import { Activity } from '../activity/Activity.js'; import { ActivityError } from '../error/Errors.js'; import { cloneMessage, cloneContent } from '../messageHelper.js'; +/** + * Service task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function ServiceTask(activityDef, context) { return new Activity(ServiceTaskBehaviour, activityDef, context); } +/** + * Service task behaviour + * @param {import('#types').Activity} activity + */ export function ServiceTaskBehaviour(activity) { const { id, type, behaviour } = activity; @@ -18,6 +27,10 @@ export function ServiceTaskBehaviour(activity) { this.broker = activity.broker; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ ServiceTaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/src/tasks/SignalTask.js b/src/tasks/SignalTask.js index 16b53832..001c0973 100644 --- a/src/tasks/SignalTask.js +++ b/src/tasks/SignalTask.js @@ -2,10 +2,19 @@ import { Activity } from '../activity/Activity.js'; import { ActivityError } from '../error/Errors.js'; import { cloneContent } from '../messageHelper.js'; +/** + * Signal task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function SignalTask(activityDef, context) { return new Activity(SignalTaskBehaviour, activityDef, context); } +/** + * Signal task behaviour + * @param {import('#types').Activity} activity + */ export function SignalTaskBehaviour(activity) { const { id, type, behaviour } = activity; @@ -17,6 +26,10 @@ export function SignalTaskBehaviour(activity) { this.broker = activity.broker; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ SignalTaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/src/tasks/StandardLoopCharacteristics.js b/src/tasks/StandardLoopCharacteristics.js index 52a269a6..00c486a0 100644 --- a/src/tasks/StandardLoopCharacteristics.js +++ b/src/tasks/StandardLoopCharacteristics.js @@ -1,4 +1,9 @@ import { LoopCharacteristics } from './LoopCharacteristics.js'; +/** + * Standard loop characteristics + * @param {import('#types').Activity} activity + * @param {import('moddle-context-serializer').SerializableElement} loopCharacteristics + */ export function StandardLoopCharacteristics(activity, loopCharacteristics) { let { behaviour } = loopCharacteristics; behaviour = { ...behaviour, isSequential: true }; diff --git a/src/tasks/SubProcess.js b/src/tasks/SubProcess.js index 26dfd780..c7b5c788 100644 --- a/src/tasks/SubProcess.js +++ b/src/tasks/SubProcess.js @@ -5,6 +5,11 @@ import { cloneContent } from '../messageHelper.js'; const K_EXECUTIONS = Symbol.for('executions'); const K_ON_EXECUTION_COMPLETED = Symbol.for('execution completed handler'); +/** + * Sub process + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function SubProcess(activityDef, context) { const triggeredByEvent = activityDef.behaviour && activityDef.behaviour.triggeredByEvent; const subProcess = new Activity(SubProcessBehaviour, { ...activityDef, isSubProcess: true, triggeredByEvent }, context); @@ -26,6 +31,11 @@ export function SubProcess(activityDef, context) { } } +/** + * Sub process behaviour + * @param {import('#types').Activity} activity + * @param {import('#types').ContextInstance} context + */ export function SubProcessBehaviour(activity, context) { const { id, type, behaviour } = activity; this.id = id; @@ -54,6 +64,10 @@ Object.defineProperty(SubProcessBehaviour.prototype, 'executions', { }, }); +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ SubProcessBehaviour.prototype.execute = function execute(executeMessage) { const { isRootScope, executionId } = executeMessage.content; diff --git a/src/tasks/Task.js b/src/tasks/Task.js index 1a329874..5829acac 100644 --- a/src/tasks/Task.js +++ b/src/tasks/Task.js @@ -1,10 +1,19 @@ import { Activity } from '../activity/Activity.js'; import { cloneContent } from '../messageHelper.js'; +/** + * Task + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function Task(activityDef, context) { return new Activity(TaskBehaviour, activityDef, context); } +/** + * Task behaviour + * @param {import('#types').Activity} activity + */ export function TaskBehaviour(activity) { const { id, type, behaviour, broker } = activity; this.id = id; @@ -14,6 +23,10 @@ export function TaskBehaviour(activity) { this.broker = broker; } +/** + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {void} + */ TaskBehaviour.prototype.execute = function execute(executeMessage) { const executeContent = executeMessage.content; const loopCharacteristics = this.loopCharacteristics; diff --git a/src/tasks/Transaction.js b/src/tasks/Transaction.js index e5b969ef..bc4ad83e 100644 --- a/src/tasks/Transaction.js +++ b/src/tasks/Transaction.js @@ -1,4 +1,9 @@ import { SubProcess } from './SubProcess.js'; +/** + * Transaction + * @param {import('moddle-context-serializer').Activity} activityDef + * @param {import('#types').ContextInstance} context + */ export function Transaction(activityDef, context) { const transaction = { type: 'transaction', ...activityDef, isTransaction: true }; const activity = SubProcess(transaction, context); diff --git a/test/activities-test.js b/test/activities-test.js index b8c4cc72..71a56687 100644 --- a/test/activities-test.js +++ b/test/activities-test.js @@ -1,4 +1,4 @@ -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import testHelpers from './helpers/testHelpers.js'; const moddle = new BpmnModdle(); diff --git a/test/error/BpmnError-test.js b/test/error/BpmnError-test.js index 39ea56c6..5638e542 100644 --- a/test/error/BpmnError-test.js +++ b/test/error/BpmnError-test.js @@ -1,5 +1,6 @@ import { BpmnErrorActivity } from '../../src/error/BpmnError.js'; import { Environment } from '../../src/Environment.js'; + describe('BpmnError', () => { it('returns BpmnError instanceof from error', () => { const bpmnError = BpmnErrorActivity( diff --git a/test/feature/errors-feature.js b/test/feature/errors-feature.js index c4c9f0e1..a728ae4e 100644 --- a/test/feature/errors-feature.js +++ b/test/feature/errors-feature.js @@ -998,8 +998,75 @@ Feature('Errors', () => { expect(err.inner.stack).to.match(/to-end-2/i); }); }); + + Scenario('recovered state carries an error with an unrecognized type', () => { + let context, definition, serviceCallback; + const options = { + services: { + volatile(_, next) { + serviceCallback = next; + }, + }, + }; + + Given('a source with a volatile service task', async () => { + const source = ` + + + + + `; + + context = await testHelpers.context(source); + definition = new Definition(context, options); + }); + + let state, errored; + When('definition is ran with listener that saves state on error', () => { + definition.once('error', () => { + state = JSON.stringify(definition.getState()); + }); + errored = definition.waitFor('error'); + definition.run(); + }); + + And('service fails', () => { + serviceCallback(new Error('boom')); + }); + + Then('definition errors', () => { + return errored; + }); + + let recovered; + Given('the persisted state has its error type rewritten to an unrecognized value', () => { + const parsed = JSON.parse(state); + mutateErrorType(parsed, 'LegacyError'); + recovered = new Definition(context.clone(), options).recover(parsed); + }); + + let recoveredError; + When('definition is resumed', () => { + recoveredError = recovered.waitFor('error'); + recovered.resume(); + }); + + Then('error bubbles through verbatim', async () => { + const errApi = await recoveredError; + expect(errApi.content).to.have.property('error'); + expect(errApi.content.error).to.have.property('type', 'LegacyError'); + expect(errApi.content.error).to.have.property('description', 'boom'); + expect(errApi.content.error).to.not.be.instanceof(Error); + }); + }); }); +function mutateErrorType(node, type) { + if (!node || typeof node !== 'object') return; + if (node.error && typeof node.error === 'object' && 'type' in node.error) node.error.type = type; + for (const key in node) mutateErrorType(node[key], type); +} + async function prepareSource() { const context = await testHelpers.context(bpmnErrorSource, { extensions: { diff --git a/test/helpers/testHelpers.js b/test/helpers/testHelpers.js index 463b1ce2..7f1dea64 100644 --- a/test/helpers/testHelpers.js +++ b/test/helpers/testHelpers.js @@ -1,6 +1,6 @@ import fs from 'node:fs'; import Debug from 'debug'; -import BpmnModdle from 'bpmn-moddle'; +import { BpmnModdle } from 'bpmn-moddle'; import * as types from 'bpmn-elements'; import { Context, Environment } from 'bpmn-elements'; diff --git a/types/bundle.d.ts b/types/bundle.d.ts index f3f45eba..87c88b9b 100644 --- a/types/bundle.d.ts +++ b/types/bundle.d.ts @@ -27,7 +27,6 @@ export { Properties } from '../src/io/Properties.js'; export { ServiceImplementation } from '../src/tasks/ServiceImplementation.js'; export { Signal } from '../src/activity/Signal.js'; export { StandardLoopCharacteristics } from '../src/tasks/StandardLoopCharacteristics.js'; -export { Timers } from '../src/Timers.js'; export { Association, MessageFlow, SequenceFlow } from '../src/flows/index.js'; export { BoundaryEvent, EndEvent, IntermediateCatchEvent, IntermediateThrowEvent, StartEvent } from '../src/events/index.js'; diff --git a/types/index.d.ts b/types/index.d.ts index 5ef2b19f..bc0a57f1 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -45,6 +45,28 @@ declare module 'bpmn-elements' { path?: Omit[]; } + // --- Shake results ------------------------------------------------------------ + + /** A single hop (activity or sequence flow) recorded during a shake walk. */ + export interface ShakeSequenceItem { + id: string; + type: string; + count?: number; + sourceId?: string; + targetId?: string; + } + + /** A single end-to-end sequence discovered while shaking an activity graph. */ + export interface ShakenSequence extends ElementMessageContent { + /** The activity- and flow-id steps that were walked, in order. */ + sequence: ShakeSequenceItem[]; + /** true when the walk revisited an already-seen activity. */ + isLooped: boolean; + } + + /** Result of shaking an activity graph, keyed by the starting activity id. */ + export type ShakeResult = Record; + // --- Element abstract bases --------------------------------------------------- export class ElementBase { @@ -86,6 +108,13 @@ declare module 'bpmn-elements' { // --- Event definitions -------------------------------------------------------- + export interface EventDefinitionReference { + id?: string; + name?: string; + referenceType: string; + [x: string]: any; + } + // Common ancestor for the typed event definitions; concrete types live in src/eventDefinitions. export class EventDefinition { constructor(activity: Activity, eventDefinitionElement: SerializableElement, context?: ContextInstance, index?: number); @@ -96,11 +125,7 @@ declare module 'bpmn-elements' { get activity(): Activity; get broker(): Broker; get logger(): ILogger; - get reference(): { - id?: string; - name: string; - referenceType: string; - }; + get reference(): EventDefinitionReference; [x: string]: any; execute(executeMessage: ElementBrokerMessage): void; } @@ -505,10 +530,12 @@ declare module 'bpmn-elements' { * @param context Per-execution registry and factory */ constructor(Behaviour: IActivityBehaviour, activityDef: import("moddle-context-serializer").Activity, context: ContextInstance); - id: any; - type: any; - name: any; - behaviour: any; + id: string | undefined; + type: string; + name: string | undefined; + behaviour: { + eventDefinitions: any; + }; Behaviour: IActivityBehaviour; parent: import("moddle-context-serializer").Parent; @@ -644,14 +671,14 @@ declare module 'bpmn-elements' { constructor(activity: Activity, context: ContextInstance); activity: Activity; context: ContextInstance; - id: any; + id: string | undefined; broker: import("smqp").Broker; get completed(): boolean; /** * Begin executing the activity behaviour. Resumes if the message is redelivered. * @throws {Error} when message or executionId is missing */ - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | undefined; executionId: string | undefined; source: IActivityBehaviour | undefined; /** @@ -691,17 +718,21 @@ declare module 'bpmn-elements' { */ stop(): void; } - export function BpmnError(errorDef: any, context: any): { - id: any; - type: any; - name: any; + /** + * BPMN error. + * */ + export function BpmnError(errorDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance): { + id: string | undefined; + type: string | undefined; + name: string; errorCode: any; - resolve: (executionMessage: any, error: any) => { - id: any; - type: any; + resolve: (executionMessage: ElementBrokerMessage, error?: Error) => { + id?: string; + type?: string; messageType: string; - name: any; - code: any; + name: string; + code: string | undefined; + inner?: Error; }; }; /** @@ -875,9 +906,8 @@ declare module 'bpmn-elements' { /** * Walk activity graphs to discover sequences. Limited to the activity's owning process * when startId is given, otherwise all processes are shaken. - * - */ - shake(startId?: string): {} | undefined; + * */ + shake(startId?: string): ShakeResult | undefined; /** * Get every process in the definition. */ @@ -904,7 +934,7 @@ declare module 'bpmn-elements' { * List currently postponed activities as Api wrappers. * */ - getPostponed(...args: any[]): any[]; + getPostponed(...args: any[]): never[] | IApi; /** * Resolve a Definition Api wrapper, preferring the running execution if any. * @throws {Error} when the definition is not running and no message is given @@ -964,11 +994,11 @@ declare module 'bpmn-elements' { * is redelivered. When `content.processId` is set, only that process is started. * @throws {Error} when message or executionId is missing */ - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | true | undefined; /** * Resume after recover by reactivating running processes. */ - resume(): any; + resume(): number | undefined; /** * Restore execution state captured by getState. Reinstates running processes from the snapshot. * */ @@ -1007,9 +1037,8 @@ declare module 'bpmn-elements' { getApi(apiMessage?: ElementBrokerMessage): IApi; /** * List currently postponed activities across every running process. - * - */ - getPostponed(...args: any[]): any[]; + * */ + getPostponed(...args: any[]): IApi; get stopped(): boolean; get completed(): boolean; get status(): string; @@ -1018,13 +1047,16 @@ declare module 'bpmn-elements' { get isRunning(): boolean; get activityStatus(): string; } - export function Category(activityDef: any): { - id: any; - type: any; - name: any; - behaviour: any; + /** + * Placeholder activity for non-executable elements (text annotations, groups, categories). + * */ + export function Category(activityDef: import("moddle-context-serializer").Activity): { + id: string; + type: string; + name: string | undefined; + behaviour: Record; parent: ElementParent; - placeholder: boolean; + placeholder: true; }; /** * Holds global execution config: variables, injected services, timers, scripts engine, @@ -1038,20 +1070,18 @@ declare module 'bpmn-elements' { * */ constructor(options?: EnvironmentOptions); - options: {}; + options: EnvironmentOptions; + expressions: IExpressions; extensions: Record | undefined; output: any; - scripts: Scripts | IScripts; - timers: Timers | ITimers; - settings: { - enableDummyService?: boolean; - step?: boolean; - strict?: boolean; - batchSize?: number; - disableTrackState?: boolean; - skipDiscard: boolean; - }; + + scripts: IScripts; + + timers: ITimers; + + settings: EnvironmentSettings; + Logger: LoggerFactory; get variables(): Record; set services(value: Record); @@ -1068,9 +1098,8 @@ declare module 'bpmn-elements' { /** * Clone the environment, optionally overriding options. Services are merged when * `overrideOptions.services` is supplied. - * - */ - clone(overrideOptions?: EnvironmentOptions): any; + * */ + clone(overrideOptions?: EnvironmentOptions): Environment; /** * Merge variables into the environment. Non-objects are ignored. * */ @@ -1082,11 +1111,11 @@ declare module 'bpmn-elements' { /** * Resolve a registered script by language and identifier. * */ - getScript(...args: any[]): void | Script; + getScript(...args: any[]): Script; /** * Register a script for an activity, delegating to the configured scripts engine. * */ - registerScript(...args: any[]): void | Script; + registerScript(...args: any[]): Script | undefined; /** * Lookup a registered service by name. * */ @@ -1099,53 +1128,73 @@ declare module 'bpmn-elements' { resolveExpression(expression: string, message?: ElementBrokerMessage, expressionFnContext?: any): any; /** * Register a service callable by name. - * */ + * @param name service function name + * @param fn service function + */ addService(name: string, fn: CallableFunction): void; } /** - * Builtin data object - * @param >} dataObjectDef + * Builtin data object. Reads from / writes to `environment.variables._data`. * */ export class DataObject { /** - * Builtin data object - * @param >} dataObjectDef + * Builtin data object. Reads from / writes to `environment.variables._data`. * */ - constructor(dataObjectDef: any, { environment }: ContextInstance); - id: any; - type: any; - name: any; - behaviour: any; - parent: any; + constructor(dataObjectDef: import("moddle-context-serializer").DataObject, { environment }: ContextInstance); + id: string | undefined; + type: string | undefined; + name: string | undefined; + + behaviour: Record; + + parent: import("moddle-context-serializer").Parent | undefined; environment: Environment; - read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; - write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + + read(broker: import("smqp").Broker, exchange: string, routingKeyPrefix: string, messageProperties?: Record): number | undefined; + + write(broker: import("smqp").Broker, exchange: string, routingKeyPrefix: string, value: any, messageProperties?: Record): number | undefined; } + /** + * Builtin data store. Reads from / writes to `environment.variables._data`. + * */ export class DataStore { - constructor(dataStoreDef: any, { environment }: { - environment: any; - }); - id: any; - type: any; - name: any; - behaviour: any; - parent: any; - environment: any; - read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; - write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + /** + * Builtin data store. Reads from / writes to `environment.variables._data`. + * */ + constructor(dataStoreDef: import("moddle-context-serializer").DataStore, { environment }: ContextInstance); + id: string | undefined; + type: string | undefined; + name: string | undefined; + + behaviour: Record; + + parent: import("moddle-context-serializer").Parent | undefined; + environment: Environment; + + read(broker: import("smqp").Broker, exchange: string, routingKeyPrefix: string, messageProperties?: Record): number | undefined; + + write(broker: import("smqp").Broker, exchange: string, routingKeyPrefix: string, value: any, messageProperties?: Record): number | undefined; } + /** + * Builtin data store reference. Reads from / writes to `environment.variables._data`. + * */ export class DataStoreReference { - constructor(dataObjectDef: any, { environment }: { - environment: any; - }); - id: any; - type: any; - name: any; - behaviour: any; - parent: any; - environment: any; - read(broker: any, exchange: any, routingKeyPrefix: any, messageProperties: any): any; - write(broker: any, exchange: any, routingKeyPrefix: any, value: any, messageProperties: any): any; + /** + * Builtin data store reference. Reads from / writes to `environment.variables._data`. + * */ + constructor(dataObjectDef: import("moddle-context-serializer").DataStore, { environment }: ContextInstance); + id: string | undefined; + type: string | undefined; + name: string | undefined; + + behaviour: Record; + + parent: import("moddle-context-serializer").Parent | undefined; + environment: Environment; + + read(broker: import("smqp").Broker, exchange: string, routingKeyPrefix: string, messageProperties?: Record): number | undefined; + + write(broker: import("smqp").Broker, exchange: string, routingKeyPrefix: string, value: any, messageProperties?: Record): number | undefined; } export function Escalation(signalDef: any, context: any): { id: any; @@ -1160,15 +1209,25 @@ declare module 'bpmn-elements' { parent: any; }; }; + /** + * Activity ioSpecification behaviour. Reads bound data objects on enter and writes them on completion. + * */ export class InputOutputSpecification { - constructor(activity: any, ioSpecificationDef: any, context: any); - id: any; - type: any; - behaviour: any; - activity: any; - broker: any; - context: any; - activate(message: any): void; + /** + * Activity ioSpecification behaviour. Reads bound data objects on enter and writes them on completion. + * */ + constructor(activity: Activity, ioSpecificationDef: import("moddle-context-serializer").IoSpecification, context: ContextInstance); + id: string | undefined; + type: string; + behaviour: { + dataInputs?: import("moddle-context-serializer").IElement[]; + dataOutputs?: import("moddle-context-serializer").IElement[]; + }; + activity: Activity; + broker: import("smqp").Broker; + context: ContextInstance; + + activate(message?: ElementBrokerMessage): void; deactivate(): void; } /** @@ -1183,33 +1242,91 @@ declare module 'bpmn-elements' { constructor(process: Process, laneDefinition: import("moddle-context-serializer").SerializableElement); id: string | undefined; type: string | undefined; - name: any; - parent: { - id: any; - type: any; - }; - behaviour: { - [x: string]: any; - }; + + name: string; + + parent: import("moddle-context-serializer").Parent; + + behaviour: Record; environment: Environment; broker: import("smqp").Broker; context: ContextInstance; logger: ILogger; get process(): Process; } + /** + * Loop characteristics + * */ export class MultiInstanceLoopCharacteristics { - constructor(activity: any, loopCharacteristics: any); - activity: any; - loopCharacteristics: any; - type: any; - isSequential: any; - collection: any; - loopCardinality: any; + /** + * Loop characteristics + * */ + constructor(activity: Activity, loopCharacteristics: import("moddle-context-serializer").SerializableElement); + activity: Activity; + loopCharacteristics: import("moddle-context-serializer").SerializableElement>; + type: string; + + isSequential: boolean; + + collection: string | undefined; + + loopCardinality: number | undefined; loopType: string | undefined; - elementVariable: any; - characteristics: any; + + elementVariable: string | undefined; + + characteristics: Characteristics; execution: any; - execute(executeMessage: any): any; + + execute(executeMessage: ElementBrokerMessage): void; + } + /** + * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). + * */ + class Characteristics { + /** + * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). + * */ + constructor(activity: Activity, loopCharacteristics: import("moddle-context-serializer").SerializableElement, executeMessage: ElementBrokerMessage); + activity: Activity; + behaviour: Record; + message: ElementBrokerMessage; + type: string; + id: string | undefined; + broker: import("smqp").Broker; + parentExecutionId: string | undefined; + + isSequential: boolean; + output: any; + parent: ElementParent; + loopCardinality: number | undefined; + startCondition: string | undefined; + completionCondition: string; + collection: any[] | undefined; + + elementVariable: string; + cardinality: number | undefined; + logger: ILogger; + batchSize: number; + + getContent(): ElementMessageContent; + + next(index: number): ElementMessageContent; + /** + * @returns cardinality + */ + getCardinality(collection?: any): number | undefined; + + getCollection(): any[] | undefined; + + isStartConditionMet(message: ElementBrokerMessage): any; + + isCompletionConditionMet(message: ElementBrokerMessage): any; + + complete(content: ElementMessageContent, allDiscarded?: boolean): void; + + subscribe(onIterationCompleteMessage: ElementBrokerMessage): void; + stop(): void; } export function Message(messageDef: any, context: any): { id: any; @@ -1228,9 +1345,9 @@ declare module 'bpmn-elements' { * joins, and parallel activation through ProcessExecution. * */ constructor(processDef: import("moddle-context-serializer").Process, context: ContextInstance); - id: any; - type: any; - name: any; + id: string | undefined; + type: string; + name: string | undefined; parent: ElementParent; @@ -1275,9 +1392,8 @@ declare module 'bpmn-elements' { recover(state?: ProcessState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(startId?: string): any; + * */ + shake(startId?: string): ShakeResult; /** * Stop the process if running. */ @@ -1317,7 +1433,7 @@ declare module 'bpmn-elements' { */ getSequenceFlows(): SequenceFlow | SequenceFlow[]; - getLaneById(laneId: string): any; + getLaneById(laneId: string): Lane | undefined; /** * List currently postponed activities as Api wrappers. * @@ -1336,18 +1452,38 @@ declare module 'bpmn-elements' { get status(): string | undefined; get activityStatus(): string; } - export class Properties { - constructor(activity: any, propertiesDef: any, context: any); - activity: any; - broker: any; - activate(message: any): void; + /** + * Activity properties behaviour. Resolves bound data input/output references during the run. + * */ + export function Properties(activity: Activity, propertiesDef: { + type: "properties"; + values: import("moddle-context-serializer").IElement[]; + }, context: ContextInstance): void; + export class Properties { + /** + * Activity properties behaviour. Resolves bound data input/output references during the run. + * */ + constructor(activity: Activity, propertiesDef: { + type: "properties"; + values: import("moddle-context-serializer").IElement[]; + }, context: ContextInstance); + activity: Activity; + broker: import("smqp").Broker; + + activate(message: ElementBrokerMessage): void; deactivate(): void; } + /** + * Service implementation + * */ export class ServiceImplementation { - constructor(activity: any); + /** + * Service implementation + * */ + constructor(activity: Activity); type: string; implementation: any; - activity: any; + activity: Activity; execute(executionMessage: any, callback: any): any; } export function Signal(signalDef: any, context: any): { @@ -1357,43 +1493,31 @@ declare module 'bpmn-elements' { parent: any; resolve: (executionMessage: any) => any; }; - export function StandardLoopCharacteristics(activity: any, loopCharacteristics: any): MultiInstanceLoopCharacteristics; - export class Timers { - constructor(options: any); - count: number; - options: any; - setTimeout: any; - clearTimeout: any; - get executing(): any[]; - register(owner: any): RegisteredTimers; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; - } + /** + * Standard loop characteristics + * */ + export function StandardLoopCharacteristics(activity: Activity, loopCharacteristics: import("moddle-context-serializer").SerializableElement): MultiInstanceLoopCharacteristics; export class ActivityError extends Error { - constructor(description: any, sourceMessage: any, inner: any); + + constructor(description: string, sourceMessage?: ElementBrokerMessage, inner?: Error | { + name?: string; + code?: string | number; + }); + type: string; - name: any; - description: any; - source: any; - inner: any; - code: any; + + description: string; + + source: Pick | undefined; + + inner: Error | { + name?: string; + code?: string | number; + } | undefined; + + code: string | number | undefined; } export class RunError extends ActivityError { - constructor(...args: any[]); } /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -1405,8 +1529,8 @@ declare module 'bpmn-elements' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: any; - type: any; + id: string | undefined; + type: string; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -1433,9 +1557,8 @@ declare module 'bpmn-elements' { recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(fromId?: string): any; + * */ + shake(fromId?: string): ShakeResult; /** * Stop the running process execution via the api. */ @@ -1448,11 +1571,11 @@ declare module 'bpmn-elements' { /** * Queue a discard message that propagates to all running children. */ - discard(): any; + discard(): void; /** * Queue a cancel message that propagates to all running children. */ - cancel(): any; + cancel(): void; /** * Get child activities in the process scope. * */ @@ -1488,14 +1611,15 @@ declare module 'bpmn-elements' { * events; activities subscribe to drive their inbound queue. * */ constructor(flowDef: import("moddle-context-serializer").SequenceFlow, { environment }: ContextInstance); - id: any; - type: any; - name: any; + id: string | undefined; + type: string; + name: string | undefined; parent: ElementParent; - behaviour: any; - sourceId: any; - targetId: any; - isDefault: any; + + behaviour: Record; + sourceId: string; + targetId: string; + isDefault: boolean | undefined; isSequenceFlow: boolean; environment: Environment; logger: ILogger; @@ -1546,7 +1670,7 @@ declare module 'bpmn-elements' { * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop * when the target was already visited, otherwise flow.shake. * */ - shake(message: ElementBrokerMessage): any; + shake(message: ElementBrokerMessage): number | undefined; /** * Resolve the flow's condition (script or expression). Returns null when no condition is set. * Emits a fatal error when the script language is missing or unsupported. @@ -1593,14 +1717,15 @@ declare module 'bpmn-elements' { * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. * */ - constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + constructor(associationDef: import("moddle-context-serializer").Association, { environment }: ContextInstance); id: string | undefined; type: string; - name: any; + name: string | undefined; parent: ElementParent; + behaviour: Record; - sourceId: any; - targetId: any; + sourceId: string; + targetId: string; isAssociation: boolean; environment: Environment; logger: ILogger; @@ -1656,13 +1781,14 @@ declare module 'bpmn-elements' { * source's `end` event and publishes `message.outbound` whenever the source completes, * carrying any message payload through to the target. * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + constructor(flowDef: import("moddle-context-serializer").MessageFlow, context: ContextInstance); id: string | undefined; type: string; - name: any; + name: string | undefined; parent: ElementParent; - source: any; - target: any; + source: import("moddle-context-serializer").MessageFlowEndpoint; + target: import("moddle-context-serializer").MessageFlowEndpoint; + behaviour: Record; environment: Environment; context: ContextInstance; @@ -1702,79 +1828,150 @@ declare module 'bpmn-elements' { */ deactivate(): void; } - class Scripts { - getScript(): void; - register(): void; - } - export function BoundaryEvent(activityDef: any, context: any): Activity; - export function EndEvent(activityDef: any, context: any): Activity; - export function IntermediateCatchEvent(activityDef: any, context: any): Activity; - export function IntermediateThrowEvent(activityDef: any, context: any): Activity; - export function StartEvent(activityDef: any, context: any): Activity; - export function EventBasedGateway(activityDef: any, context: any): Activity; - export function ExclusiveGateway(activityDef: any, context: any): Activity; - export function InclusiveGateway(activityDef: any, context: any): Activity; + /** + * Boundary event + * */ + export function BoundaryEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * End event + * */ + export function EndEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Intermediate catch event + * */ + export function IntermediateCatchEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Intermediate throw event + * */ + export function IntermediateThrowEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Start event + * */ + export function StartEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Event based gateway + * */ + export function EventBasedGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Exclusive gateway + * */ + export function ExclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Inclusive gateway + * */ + export function InclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Parallel gateway + * */ export class ParallelGateway { - constructor(activityDef: any, context: any); - id: any; + /** + * Parallel gateway + * */ + constructor(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance); + id: string | undefined; } /** - * Create call activity - * @returns Call activity - */ + * Call activity + * */ export function CallActivity(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - export function ReceiveTask(activityDef: any, context: any): Activity; - export function ScriptTask(activityDef: any, context: any): Activity; - export function SendTask(activityDef: any, context: any): Activity; - export function UserTask(activityDef: any, context: any): Activity; - export function AdHocSubProcess(activityDef: any, context: any): Activity; - export function Task(activityDef: any, context: any): Activity; - export function Transaction(activityDef: any, context: any): Activity; + /** + * Receive task + * */ + export function ReceiveTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Script task + * */ + export function ScriptTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Service task + * */ + export function SendTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Signal task + * */ + export function UserTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Sub process + * */ + export function AdHocSubProcess(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Task + * */ + export function Task(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Transaction + * */ + export function Transaction(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Cancel event definition + * */ export class CancelEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Cancel event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): void; } + /** + * Compensate event definition + * */ export class CompensateEventDefinition { - constructor(activity: any, eventDefinition: any, context: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; + /** + * Compensate event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition, context: ContextInstance); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | import("smqp").Consumer | undefined; + + executeCatch(executeMessage: ElementBrokerMessage): import("smqp").Consumer | undefined; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Conditional event definition + * @param index event definition index + */ export class ConditionalEventDefinition { - constructor(activity: any, eventDefinition: any, _context: any, index: any); - id: any; - type: any; - behaviour: any; - activity: any; - environment: any; - broker: any; - logger: any; + /** + * Conditional event definition + * @param index event definition index + */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition, _context: ContextInstance, index: number); + id: string | undefined; + type: string; + behaviour: {}; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + logger: ILogger; condition: ScriptCondition | ExpressionCondition | null; - get executionId(): any; - execute(executeMessage: any): void; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): void; /** * Evaluate condition * */ @@ -1784,115 +1981,178 @@ declare module 'bpmn-elements' { * @param err Condition evaluation error * @param result Result from evaluated condition, completes execution if truthy */ - evaluateCallback(err: Error | null, result: any): any; + evaluateCallback(err: Error | null, result: any): number | undefined; /** * Get condition * @param index Eventdefinition sequence number, used to name registered script * */ getCondition(index: number): ExpressionCondition | ScriptCondition | null; } + /** + * Error event definition + * */ export class ErrorEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Error event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Escalation event definition + * */ export class EscalationEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Escalation event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Link event definition + * */ export class LinkEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - id: any; - linkName: any; - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; + /** + * Link event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | undefined; + + executeCatch(executeMessage: ElementBrokerMessage): number | undefined; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Message event definition + * */ export class MessageEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Message event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Signal event definition + * */ export class SignalEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Signal event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Terminate event definition + * */ export class TerminateEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - activity: any; - broker: any; - logger: any; - execute(executeMessage: any): void; + /** + * Terminate event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + + execute(executeMessage: ElementBrokerMessage): void; } + /** + * Timer event definition + * */ export class TimerEventDefinition { - constructor(activity: any, eventDefinition: any); - type: any; - activity: any; - environment: any; - eventDefinition: any; - timeDuration: any; - timeCycle: any; - timeDate: any; - broker: any; - logger: any; - get executionId(): string | undefined; + /** + * Timer event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + type: string; + activity: Activity; + environment: Environment; + eventDefinition: import("moddle-context-serializer").EventDefinition; + timeDuration: string | undefined; + timeCycle: string | undefined; + timeDate: string | undefined; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; get stopped(): boolean; - get timer(): any; - execute(executeMessage: any): void; + get timer(): Timer | null; + + execute(executeMessage: ElementBrokerMessage): void; startedAt: Date | undefined; stop(): void; - parse(timerType: any, value: any): { + /** + * Parse timer + * */ + parse(timerType: string, value: string): { expireAt: Date | undefined; repeat: number | undefined; delay: number | undefined; @@ -1933,28 +2193,53 @@ declare module 'bpmn-elements' { } declare module 'bpmn-elements/errors' { - export function makeErrorFromMessage(errorMessage: any): any; + import type { MessageEnvelope } from 'smqp'; + import type { ElementBrokerMessage, ElementMessageContent, ElementParent } from 'bpmn-elements'; + + /** + * Get an Error from an error message. + * */ + export function makeErrorFromMessage(errorMessage: ElementBrokerMessage): Error | ActivityError | RunError | BpmnError; export class ActivityError extends Error { - constructor(description: any, sourceMessage: any, inner: any); + + constructor(description: string, sourceMessage?: ElementBrokerMessage, inner?: Error | { + name?: string; + code?: string | number; + }); + type: string; - name: any; - description: any; - source: any; - inner: any; - code: any; + + description: string; + + source: Pick | undefined; + + inner: Error | { + name?: string; + code?: string | number; + } | undefined; + + code: string | number | undefined; } export class RunError extends ActivityError { - constructor(...args: any[]); } export class BpmnError extends Error { - constructor(description: any, behaviour: any, sourceMessage: any, inner: any); + + constructor(description: string, behaviour?: { + id?: string; + name?: string; + errorCode?: string | number; + code?: string; + }, sourceMessage?: ElementBrokerMessage); + type: string; - name: any; - description: any; - code: any; - id: any; - source: any; - inner: any; + + description: string; + + code: string | undefined; + + id: string | undefined; + + source: Pick | undefined; } export {}; @@ -1963,75 +2248,126 @@ declare module 'bpmn-elements/errors' { declare module 'bpmn-elements/events' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - export function BoundaryEvent(activityDef: any, context: any): Activity; + /** + * Boundary event + * */ + export function BoundaryEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Boundary event behaviour + * */ export class BoundaryEventBehaviour { - constructor(activity: any); - id: any; - type: any; - attachedTo: any; - activity: any; - environment: any; - broker: any; - get executionId(): any; - get cancelActivity(): any; - execute(executeMessage: any): any; + /** + * Boundary event behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + attachedTo: Activity | null; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + get executionId(): string | undefined; + get cancelActivity(): unknown; + + execute(executeMessage: ElementBrokerMessage): void; } - export function EndEvent(activityDef: any, context: any): Activity; + /** + * End event + * */ + export function EndEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * End event behaviour + * */ export class EndEventBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute(executeMessage: any): any; + /** + * End event behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + broker: import("smqp").Broker; + + execute(executeMessage: ElementBrokerMessage): void; } - export function IntermediateCatchEvent(activityDef: any, context: any): Activity; + /** + * Intermediate catch event + * */ + export function IntermediateCatchEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Intermediate catch event behaviour + * */ export class IntermediateCatchEventBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute(executeMessage: any): any; + /** + * Intermediate catch event behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + broker: import("smqp").Broker; + + execute(executeMessage: ElementBrokerMessage): void; } - export function IntermediateThrowEvent(activityDef: any, context: any): Activity; + /** + * Intermediate throw event + * */ + export function IntermediateThrowEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Intermediate throw event behaviour + * */ export class IntermediateThrowEventBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute(executeMessage: any): any; - } - export function StartEvent(activityDef: any, context: any): Activity; - export class StartEventBehaviour { - constructor(activity: any); - id: any; - type: any; - activity: any; - broker: any; - get executionId(): any; - execute(executeMessage: any): any; + /** + * Intermediate throw event behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + broker: import("smqp").Broker; + + execute(executeMessage: ElementBrokerMessage): void; } /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. + * Start event * */ - class Formatter { + export function StartEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Start event behaviour + * */ + export class StartEventBehaviour { /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. + * Start event behaviour * */ - constructor(element: ElementBase); - id: string; + constructor(activity: Activity); + id: string | undefined; + type: string; + activity: Activity; broker: import("smqp").Broker; - logger: ILogger; + get executionId(): string | undefined; + + execute(executeMessage: ElementBrokerMessage): void; + } + /** + * Event definition execution orchestrator. Drives a sequence of event definitions for the + * activity and publishes the completed routing key when the last definition completes. + * @param completedRoutingKey Routing key to publish on completion, defaults to `execute.completed` + */ + class EventDefinitionExecution { /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; + * Event definition execution orchestrator. Drives a sequence of event definitions for the + * activity and publishes the completed routing key when the last definition completes. + * @param completedRoutingKey Routing key to publish on completion, defaults to `execute.completed` + */ + constructor(activity: Activity, eventDefinitions: EventDefinition[], completedRoutingKey?: string); + id: string | undefined; + activity: Activity; + broker: import("smqp").Broker; + eventDefinitions: EventDefinition[]; + completedRoutingKey: string; + get completed(): boolean; + get stopped(): boolean; + + execute(executeMessage: ElementBrokerMessage): void; } /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -2043,8 +2379,8 @@ declare module 'bpmn-elements/events' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: any; - type: any; + id: string | undefined; + type: string; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -2071,9 +2407,8 @@ declare module 'bpmn-elements/events' { recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(fromId?: string): any; + * */ + shake(fromId?: string): ShakeResult; /** * Stop the running process execution via the api. */ @@ -2086,11 +2421,11 @@ declare module 'bpmn-elements/events' { /** * Queue a discard message that propagates to all running children. */ - discard(): any; + discard(): void; /** * Queue a cancel message that propagates to all running children. */ - cancel(): any; + cancel(): void; /** * Get child activities in the process scope. * */ @@ -2116,25 +2451,26 @@ declare module 'bpmn-elements/events' { get isRunning(): boolean; get activityStatus(): string; } - class Scripts { - getScript(): void; - register(): void; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; + /** + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. + * */ + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } export {}; @@ -2143,53 +2479,78 @@ declare module 'bpmn-elements/events' { declare module 'bpmn-elements/eventDefinitions' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + /** + * Cancel event definition + * */ export class CancelEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Cancel event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): void; } + /** + * Compensate event definition + * */ export class CompensateEventDefinition { - constructor(activity: any, eventDefinition: any, context: any); - id: any; - type: any; - reference: { - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; + /** + * Compensate event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition, context: ContextInstance); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | import("smqp").Consumer | undefined; + + executeCatch(executeMessage: ElementBrokerMessage): import("smqp").Consumer | undefined; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Conditional event definition + * @param index event definition index + */ export class ConditionalEventDefinition { - constructor(activity: any, eventDefinition: any, _context: any, index: any); - id: any; - type: any; - behaviour: any; - activity: any; - environment: any; - broker: any; - logger: any; + /** + * Conditional event definition + * @param index event definition index + */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition, _context: ContextInstance, index: number); + id: string | undefined; + type: string; + behaviour: {}; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + logger: ILogger; condition: ScriptCondition | ExpressionCondition | null; - get executionId(): any; - execute(executeMessage: any): void; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): void; /** * Evaluate condition * */ @@ -2199,115 +2560,178 @@ declare module 'bpmn-elements/eventDefinitions' { * @param err Condition evaluation error * @param result Result from evaluated condition, completes execution if truthy */ - evaluateCallback(err: Error | null, result: any): any; + evaluateCallback(err: Error | null, result: any): number | undefined; /** * Get condition * @param index Eventdefinition sequence number, used to name registered script * */ getCondition(index: number): ExpressionCondition | ScriptCondition | null; } + /** + * Error event definition + * */ export class ErrorEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - environment: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Error event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Escalation event definition + * */ export class EscalationEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Escalation event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Link event definition + * */ export class LinkEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: { - id: any; - linkName: any; - referenceType: string; - }; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): any; - executeThrow(executeMessage: any): any; + /** + * Link event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | undefined; + + executeCatch(executeMessage: ElementBrokerMessage): number | undefined; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Message event definition + * */ export class MessageEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Message event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Signal event definition + * */ export class SignalEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - reference: any; - isThrowing: any; - activity: any; - broker: any; - logger: any; - get executionId(): any; - execute(executeMessage: any): any; - executeCatch(executeMessage: any): void; - executeThrow(executeMessage: any): any; + /** + * Signal event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string | undefined; + + reference: EventDefinitionReference; + isThrowing: boolean; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; + + execute(executeMessage: ElementBrokerMessage): number | void; + + executeCatch(executeMessage: ElementBrokerMessage): void; + + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } + /** + * Terminate event definition + * */ export class TerminateEventDefinition { - constructor(activity: any, eventDefinition: any); - id: any; - type: any; - activity: any; - broker: any; - logger: any; - execute(executeMessage: any): void; + /** + * Terminate event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + id: string | undefined; + type: string; + activity: Activity; + broker: import("smqp").Broker; + logger: ILogger; + + execute(executeMessage: ElementBrokerMessage): void; } + /** + * Timer event definition + * */ export class TimerEventDefinition { - constructor(activity: any, eventDefinition: any); - type: any; - activity: any; - environment: any; - eventDefinition: any; - timeDuration: any; - timeCycle: any; - timeDate: any; - broker: any; - logger: any; - get executionId(): string | undefined; + /** + * Timer event definition + * */ + constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + type: string; + activity: Activity; + environment: Environment; + eventDefinition: import("moddle-context-serializer").EventDefinition; + timeDuration: string | undefined; + timeCycle: string | undefined; + timeDate: string | undefined; + broker: import("smqp").Broker; + logger: ILogger; + get executionId(): string; get stopped(): boolean; - get timer(): any; - execute(executeMessage: any): void; + get timer(): Timer | null; + + execute(executeMessage: ElementBrokerMessage): void; startedAt: Date | undefined; stop(): void; - parse(timerType: any, value: any): { + /** + * Parse timer + * */ + parse(timerType: string, value: string): { expireAt: Date | undefined; repeat: number | undefined; delay: number | undefined; @@ -2353,8 +2777,8 @@ declare module 'bpmn-elements/eventDefinitions' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: any; - type: any; + id: string | undefined; + type: string; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -2381,9 +2805,8 @@ declare module 'bpmn-elements/eventDefinitions' { recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(fromId?: string): any; + * */ + shake(fromId?: string): ShakeResult; /** * Stop the running process execution via the api. */ @@ -2396,11 +2819,11 @@ declare module 'bpmn-elements/eventDefinitions' { /** * Queue a discard message that propagates to all running children. */ - discard(): any; + discard(): void; /** * Queue a cancel message that propagates to all running children. */ - cancel(): any; + cancel(): void; /** * Get child activities in the process scope. * */ @@ -2447,26 +2870,6 @@ declare module 'bpmn-elements/eventDefinitions' { * */ format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } - class Scripts { - getScript(): void; - register(): void; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; - } export {}; } @@ -2474,7 +2877,7 @@ declare module 'bpmn-elements/eventDefinitions' { declare module 'bpmn-elements/flows' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; /** * Association connecting a source and target activity. Used to drive compensation — @@ -2485,14 +2888,15 @@ declare module 'bpmn-elements/flows' { * Association connecting a source and target activity. Used to drive compensation — * activities marked `isForCompensation` subscribe to inbound association events. * */ - constructor(associationDef: import("moddle-context-serializer").SerializableElement, { environment }: ContextInstance); + constructor(associationDef: import("moddle-context-serializer").Association, { environment }: ContextInstance); id: string | undefined; type: string; - name: any; + name: string | undefined; parent: ElementParent; + behaviour: Record; - sourceId: any; - targetId: any; + sourceId: string; + targetId: string; isAssociation: boolean; environment: Environment; logger: ILogger; @@ -2548,13 +2952,14 @@ declare module 'bpmn-elements/flows' { * source's `end` event and publishes `message.outbound` whenever the source completes, * carrying any message payload through to the target. * */ - constructor(flowDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + constructor(flowDef: import("moddle-context-serializer").MessageFlow, context: ContextInstance); id: string | undefined; type: string; - name: any; + name: string | undefined; parent: ElementParent; - source: any; - target: any; + source: import("moddle-context-serializer").MessageFlowEndpoint; + target: import("moddle-context-serializer").MessageFlowEndpoint; + behaviour: Record; environment: Environment; context: ContextInstance; @@ -2604,14 +3009,15 @@ declare module 'bpmn-elements/flows' { * events; activities subscribe to drive their inbound queue. * */ constructor(flowDef: import("moddle-context-serializer").SequenceFlow, { environment }: ContextInstance); - id: any; - type: any; - name: any; + id: string | undefined; + type: string; + name: string | undefined; parent: ElementParent; - behaviour: any; - sourceId: any; - targetId: any; - isDefault: any; + + behaviour: Record; + sourceId: string; + targetId: string; + isDefault: boolean | undefined; isSequenceFlow: boolean; environment: Environment; logger: ILogger; @@ -2662,7 +3068,7 @@ declare module 'bpmn-elements/flows' { * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop * when the target was already visited, otherwise flow.shake. * */ - shake(message: ElementBrokerMessage): any; + shake(message: ElementBrokerMessage): number | undefined; /** * Resolve the flow's condition (script or expression). Returns null when no condition is set. * Emits a fatal error when the script language is missing or unsupported. @@ -2689,8 +3095,8 @@ declare module 'bpmn-elements/flows' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: any; - type: any; + id: string | undefined; + type: string; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -2717,9 +3123,8 @@ declare module 'bpmn-elements/flows' { recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(fromId?: string): any; + * */ + shake(fromId?: string): ShakeResult; /** * Stop the running process execution via the api. */ @@ -2732,11 +3137,11 @@ declare module 'bpmn-elements/flows' { /** * Queue a discard message that propagates to all running children. */ - discard(): any; + discard(): void; /** * Queue a cancel message that propagates to all running children. */ - cancel(): any; + cancel(): void; /** * Get child activities in the process scope. * */ @@ -2783,26 +3188,6 @@ declare module 'bpmn-elements/flows' { * */ format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } - class Scripts { - getScript(): void; - register(): void; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; - } export {}; } @@ -2810,53 +3195,92 @@ declare module 'bpmn-elements/flows' { declare module 'bpmn-elements/gateways' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - export function EventBasedGateway(activityDef: any, context: any): Activity; + /** + * Event based gateway + * */ + export function EventBasedGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Event based gateway behaviour + * */ export class EventBasedGatewayBehaviour { - constructor(activity: any, context: any); - id: any; - type: any; - activity: any; - broker: any; - context: any; - execute(executeMessage: any): any; + /** + * Event based gateway behaviour + * */ + constructor(activity: Activity, context: ContextInstance); + id: string | undefined; + type: string; + activity: Activity; + broker: import("smqp").Broker; + context: ContextInstance; + + execute(executeMessage: ElementBrokerMessage): void; } - export function ExclusiveGateway(activityDef: any, context: any): Activity; + /** + * Exclusive gateway + * */ + export function ExclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Exclusive gateway behaviour + * */ export class ExclusiveGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute({ content }: { - content: any; - }): void; + /** + * Exclusive gateway behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + broker: import("smqp").Broker; + + execute({ content }: ElementBrokerMessage): void; } - export function InclusiveGateway(activityDef: any, context: any): Activity; + /** + * Inclusive gateway + * */ + export function InclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Inclusive gateway behaviour + * */ export class InclusiveGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - broker: any; - execute({ content }: { - content: any; - }): void; + /** + * Inclusive gateway behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + broker: import("smqp").Broker; + + execute({ content }: ElementBrokerMessage): void; } + /** + * Parallel gateway + * */ export class ParallelGateway { - constructor(activityDef: any, context: any); - id: any; + /** + * Parallel gateway + * */ + constructor(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance); + id: string | undefined; } + /** + * Parallel gateway behaviour + * */ export class ParallelGatewayBehaviour { - constructor(activity: any); - id: any; - type: any; - activity: any; - broker: any; + /** + * Parallel gateway behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + activity: Activity; + broker: import("smqp").Broker; inbound: Set; isConverging: boolean; get executionId(): any; - execute(executeMessage: any): any; - setup(executeMessage: any): any; + + execute(executeMessage: ElementBrokerMessage): void; + setup(executeMessage: any): number | undefined; peerMonitor: PeerMonitor | undefined; } class PeerMonitor { @@ -2877,27 +3301,6 @@ declare module 'bpmn-elements/gateways' { monitor(peerActivity: any): void; stop(): void; } - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - class Formatter { - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - constructor(element: ElementBase); - id: string; - broker: import("smqp").Broker; - logger: ILogger; - /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; - } /** * Drives the execution of a single process or sub-process: activates children, routes activity * events, and rolls completion up to the owning Process or sub-process Activity. @@ -2908,8 +3311,8 @@ declare module 'bpmn-elements/gateways' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: any; - type: any; + id: string | undefined; + type: string; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -2936,9 +3339,8 @@ declare module 'bpmn-elements/gateways' { recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(fromId?: string): any; + * */ + shake(fromId?: string): ShakeResult; /** * Stop the running process execution via the api. */ @@ -2951,11 +3353,11 @@ declare module 'bpmn-elements/gateways' { /** * Queue a discard message that propagates to all running children. */ - discard(): any; + discard(): void; /** * Queue a cancel message that propagates to all running children. */ - cancel(): any; + cancel(): void; /** * Get child activities in the process scope. * */ @@ -2981,25 +3383,26 @@ declare module 'bpmn-elements/gateways' { get isRunning(): boolean; get activityStatus(): string; } - class Scripts { - getScript(): void; - register(): void; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; + /** + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. + * */ + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } export {}; @@ -3008,134 +3411,241 @@ declare module 'bpmn-elements/gateways' { declare module 'bpmn-elements/tasks' { import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, Timer, Timers, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; + import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; /** - * Create call activity - * @returns Call activity - */ + * Call activity + * */ export function CallActivity(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Call activity behaviour + * */ export class CallActivityBehaviour { - constructor(activity: any); - id: any; - type: any; + /** + * Call activity behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; calledElement: any; - loopCharacteristics: any; - activity: any; - broker: any; - environment: any; - execute(executeMessage: any): any; + + loopCharacteristics: LoopCharacteristics; + activity: Activity; + broker: import("smqp").Broker; + environment: Environment; + + execute(executeMessage: ElementBrokerMessage): void; } - export function ReceiveTask(activityDef: any, context: any): Activity; + /** + * Receive task + * */ + export function ReceiveTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Receive task behaviour + * */ export class ReceiveTaskBehaviour { - constructor(activity: any); - id: any; - type: any; + /** + * Receive task behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; reference: any; loopCharacteristics: any; - activity: any; - broker: any; - execute(executeMessage: any): any; + activity: Activity; + broker: import("smqp").Broker; + + execute(executeMessage: ElementBrokerMessage): void; } - export function ScriptTask(activityDef: any, context: any): Activity; + /** + * Script task + * */ + export function ScriptTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Script task behaviour + * */ export class ScriptTaskBehaviour { - constructor(activity: any); - id: any; - type: any; + /** + * Script task behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; scriptFormat: any; loopCharacteristics: any; - activity: any; - environment: any; - execute(executeMessage: any): any; + activity: Activity; + environment: Environment; + + execute(executeMessage: ElementBrokerMessage): void; } - export function ServiceTask(activityDef: any, context: any): Activity; + /** + * Service task + * */ + export function ServiceTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Service task behaviour + * */ export class ServiceTaskBehaviour { - constructor(activity: any); - id: any; - type: any; + /** + * Service task behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; loopCharacteristics: any; - activity: any; - environment: any; - broker: any; - execute(executeMessage: any): any; + activity: Activity; + environment: Environment; + broker: import("smqp").Broker; + + execute(executeMessage: ElementBrokerMessage): void; service: any; getService(message: any): any; } - export function SignalTask(activityDef: any, context: any): Activity; + /** + * Signal task + * */ + export function SignalTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Signal task behaviour + * */ export class SignalTaskBehaviour { - constructor(activity: any); - id: any; - type: any; + /** + * Signal task behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; loopCharacteristics: any; - activity: any; - broker: any; - execute(executeMessage: any): any; + activity: Activity; + broker: import("smqp").Broker; + + execute(executeMessage: ElementBrokerMessage): void; } - export function SubProcess(activityDef: any, context: any): Activity; + /** + * Sub process + * */ + export function SubProcess(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Sub process behaviour + * */ export class SubProcessBehaviour { - constructor(activity: any, context: any); - id: any; - type: any; + /** + * Sub process behaviour + * */ + constructor(activity: Activity, context: ContextInstance); + id: string | undefined; + type: string; loopCharacteristics: any; - activity: any; - context: any; - environment: any; - broker: any; - executionId: any; + activity: Activity; + context: ContextInstance; + environment: Environment; + broker: import("smqp").Broker; + executionId: string | undefined; get execution(): any; get executions(): any[]; - execute(executeMessage: any): any; + + execute(executeMessage: ElementBrokerMessage): void; getState(): any; recover(state: any): this | undefined; getPostponed(): any[]; getApi(apiMessage: any): any; } - export function Task(activityDef: any, context: any): Activity; + /** + * Task + * */ + export function Task(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Task behaviour + * */ export class TaskBehaviour { - constructor(activity: any); - id: any; - type: any; + /** + * Task behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; loopCharacteristics: any; - broker: any; - execute(executeMessage: any): any; + broker: import("smqp").Broker; + + execute(executeMessage: ElementBrokerMessage): void; } - export function Transaction(activityDef: any, context: any): Activity; /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. + * Transaction * */ - class Formatter { + export function Transaction(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Loop characteristics + * */ + class LoopCharacteristics { /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. + * Loop characteristics * */ - constructor(element: ElementBase); - id: string; + constructor(activity: Activity, loopCharacteristics: import("moddle-context-serializer").SerializableElement); + activity: Activity; + loopCharacteristics: import("moddle-context-serializer").SerializableElement>; + type: string; + + isSequential: boolean; + + collection: string | undefined; + + loopCardinality: number | undefined; + loopType: string | undefined; + + elementVariable: string | undefined; + + characteristics: Characteristics; + execution: any; + + execute(executeMessage: ElementBrokerMessage): void; + } + /** + * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). + * */ + class Characteristics { + /** + * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). + * */ + constructor(activity: Activity, loopCharacteristics: import("moddle-context-serializer").SerializableElement, executeMessage: ElementBrokerMessage); + activity: Activity; + behaviour: Record; + message: ElementBrokerMessage; + type: string; + id: string | undefined; broker: import("smqp").Broker; + parentExecutionId: string | undefined; + + isSequential: boolean; + output: any; + parent: ElementParent; + loopCardinality: number | undefined; + startCondition: string | undefined; + completionCondition: string; + collection: any[] | undefined; + + elementVariable: string; + cardinality: number | undefined; logger: ILogger; + batchSize: number; + + getContent(): ElementMessageContent; + + next(index: number): ElementMessageContent; /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; - } - class RegisteredTimers { - constructor(timersApi: any, owner: any); - owner: any; - setTimeout: any; - clearTimeout: any; - } - class Timer_1 { - constructor(owner: any, timerId: any, callback: any, delay: any, args: any); - callback: any; - delay: any; - args: any; - owner: any; - timerId: any; - expireAt: Date; - timerRef: any; + * @returns cardinality + */ + getCardinality(collection?: any): number | undefined; + + getCollection(): any[] | undefined; + + isStartConditionMet(message: ElementBrokerMessage): any; + + isCompletionConditionMet(message: ElementBrokerMessage): any; + + complete(content: ElementMessageContent, allDiscarded?: boolean): void; + + subscribe(onIterationCompleteMessage: ElementBrokerMessage): void; + stop(): void; } /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -3147,8 +3657,8 @@ declare module 'bpmn-elements/tasks' { * events, and rolls completion up to the owning Process or sub-process Activity. * */ constructor(parentActivity: Process | Activity, context: ContextInstance); - id: any; - type: any; + id: string | undefined; + type: string; isSubProcess: any; isTransaction: any; broker: import("smqp").Broker; @@ -3175,9 +3685,8 @@ declare module 'bpmn-elements/tasks' { recover(state?: ProcessExecutionState): this; /** * Walk activity graph from the given start id, or every start activity when omitted. - * - */ - shake(fromId?: string): any; + * */ + shake(fromId?: string): ShakeResult; /** * Stop the running process execution via the api. */ @@ -3190,11 +3699,11 @@ declare module 'bpmn-elements/tasks' { /** * Queue a discard message that propagates to all running children. */ - discard(): any; + discard(): void; /** * Queue a cancel message that propagates to all running children. */ - cancel(): any; + cancel(): void; /** * Get child activities in the process scope. * */ @@ -3220,9 +3729,26 @@ declare module 'bpmn-elements/tasks' { get isRunning(): boolean; get activityStatus(): string; } - class Scripts { - getScript(): void; - register(): void; + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + class Formatter { + /** + * Enriches an element run message via async format start/end messages on the `format` exchange + * before the run message is continued. Handlers publish enrichment by responding to a start + * message with a matching end (or error) routing key. + * */ + constructor(element: ElementBase); + id: string; + broker: import("smqp").Broker; + logger: ILogger; + /** + * Format the given run message. Callback fires with `(err, content, formatted)` once + * formatting completes; `formatted` is true when content was actually enriched. + * */ + format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; } export {}; diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index a7385139..1fbdc22e 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -141,6 +141,28 @@ export interface ElementParent { path?: Omit[]; } +// --- Shake results ------------------------------------------------------------ + +/** A single hop (activity or sequence flow) recorded during a shake walk. */ +export interface ShakeSequenceItem { + id: string; + type: string; + count?: number; + sourceId?: string; + targetId?: string; +} + +/** A single end-to-end sequence discovered while shaking an activity graph. */ +export interface ShakenSequence extends ElementMessageContent { + /** The activity- and flow-id steps that were walked, in order. */ + sequence: ShakeSequenceItem[]; + /** true when the walk revisited an already-seen activity. */ + isLooped: boolean; +} + +/** Result of shaking an activity graph, keyed by the starting activity id. */ +export type ShakeResult = Record; + // --- Element abstract bases --------------------------------------------------- export abstract class ElementBase { @@ -182,6 +204,13 @@ export abstract class MessageElement { // --- Event definitions -------------------------------------------------------- +export interface EventDefinitionReference { + id?: string; + name?: string; + referenceType: string; + [x: string]: any; +} + // Common ancestor for the typed event definitions; concrete types live in src/eventDefinitions. export class EventDefinition { constructor(activity: Activity, eventDefinitionElement: SerializableElement, context?: ContextInstance, index?: number); @@ -192,11 +221,7 @@ export class EventDefinition { get activity(): Activity; get broker(): Broker; get logger(): ILogger; - get reference(): { - id?: string; - name: string; - referenceType: string; - }; + get reference(): EventDefinitionReference; [x: string]: any; execute(executeMessage: ElementBrokerMessage): void; } From 87b3032bbf7d1176fd2c5cc8d0b77e9b03f789f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 30 May 2026 09:27:44 +0200 Subject: [PATCH 16/31] prototype Message, Escalation and Signal behvaiour --- dist/activity/Escalation.js | 58 +++++---- dist/activity/Message.js | 58 +++++---- dist/activity/Signal.js | 58 +++++---- src/activity/Escalation.js | 43 ++++--- src/activity/Message.js | 41 ++++--- src/activity/Signal.js | 41 ++++--- test/activity/Escalation-test.js | 76 ++++++++++++ test/activity/Message-test.js | 82 +++++++++++++ test/activity/Signal-test.js | 81 +++++++++++++ .../MessageEventDefinition-test.js | 2 +- .../SignalEventDefinition-test.js | 2 +- types/index.d.ts | 111 ++++++++++++++---- 12 files changed, 506 insertions(+), 147 deletions(-) create mode 100644 test/activity/Escalation-test.js create mode 100644 test/activity/Message-test.js create mode 100644 test/activity/Signal-test.js diff --git a/dist/activity/Escalation.js b/dist/activity/Escalation.js index b0aa72a4..2bf0dbf8 100644 --- a/dist/activity/Escalation.js +++ b/dist/activity/Escalation.js @@ -4,35 +4,47 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Escalation = Escalation; -function Escalation(signalDef, context) { +/** + * Escalation reference element. Resolves the escalation name expression against the execution message. + * @param {import('moddle-context-serializer').SerializableElement} escalationDef + * @param {import('#types').ContextInstance} context + */ +function Escalation(escalationDef, context) { + if (!(this instanceof Escalation)) return new Escalation(escalationDef, context); const { id, type, name, - parent: originalParent - } = signalDef; - const { - environment - } = context; - const parent = { - ...originalParent + parent + } = escalationDef; + this.id = id; + this.type = type; + this.name = name; + /** @type {import('#types').ElementParent} */ + this.parent = { + ...parent }; - return { + this.environment = context.environment; +} + +/** + * Resolve escalation reference for the given execution message. + * @param {import('#types').ElementBrokerMessage} executionMessage + */ +Escalation.prototype.resolve = function resolve(executionMessage) { + const { id, type, name, - parent, - resolve + parent + } = this; + return { + id, + type, + messageType: 'escalation', + name: name && this.environment.resolveExpression(name, executionMessage), + parent: { + ...parent + } }; - function resolve(executionMessage) { - return { - id, - type, - messageType: 'escalation', - name: name && environment.resolveExpression(name, executionMessage), - parent: { - ...parent - } - }; - } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/dist/activity/Message.js b/dist/activity/Message.js index 440adfdc..e7686ff4 100644 --- a/dist/activity/Message.js +++ b/dist/activity/Message.js @@ -4,37 +4,49 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Message = Message; +/** + * Message reference element. Resolves the message name expression against the execution message. + * @param {import('moddle-context-serializer').SerializableElement} messageDef + * @param {import('#types').ContextInstance} context + */ function Message(messageDef, context) { + if (!(this instanceof Message)) return new Message(messageDef, context); const { id, type, name, - parent: originalParent + parent } = messageDef; - const { - environment - } = context; - const parent = { - ...originalParent + this.id = id; + this.type = type; + this.name = name; + /** @type {import('#types').ElementParent} */ + this.parent = { + ...parent }; - return { + this.environment = context.environment; +} + +/** + * Resolve message reference for the given execution message. + * @param {import('#types').ElementBrokerMessage} executionMessage + */ +Message.prototype.resolve = function resolve(executionMessage) { + const { id, type, name, - parent, - resolve + parent + } = this; + return { + id, + type, + messageType: 'message', + ...(name && { + name: this.environment.resolveExpression(name, executionMessage) + }), + parent: { + ...parent + } }; - function resolve(executionMessage) { - return { - id, - type, - messageType: 'message', - ...(name && { - name: environment.resolveExpression(name, executionMessage) - }), - parent: { - ...parent - } - }; - } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/dist/activity/Signal.js b/dist/activity/Signal.js index bd2f2533..cd1e0d2a 100644 --- a/dist/activity/Signal.js +++ b/dist/activity/Signal.js @@ -4,37 +4,49 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Signal = Signal; +/** + * Signal reference element. Resolves the signal name expression against the execution message. + * @param {import('moddle-context-serializer').SerializableElement} signalDef + * @param {import('#types').ContextInstance} context + */ function Signal(signalDef, context) { + if (!(this instanceof Signal)) return new Signal(signalDef, context); const { id, type = 'Signal', name, - parent: originalParent + parent } = signalDef; - const { - environment - } = context; - const parent = { - ...originalParent + this.id = id; + this.type = type; + this.name = name; + /** @type {import('#types').ElementParent} */ + this.parent = { + ...parent }; - return { + this.environment = context.environment; +} + +/** + * Resolve signal reference for the given execution message. + * @param {import('#types').ElementBrokerMessage} executionMessage + */ +Signal.prototype.resolve = function resolve(executionMessage) { + const { id, type, name, - parent, - resolve + parent + } = this; + return { + id, + type, + messageType: 'signal', + ...(name && { + name: this.environment.resolveExpression(name, executionMessage) + }), + parent: { + ...parent + } }; - function resolve(executionMessage) { - return { - id, - type, - messageType: 'signal', - ...(name && { - name: environment.resolveExpression(name, executionMessage) - }), - parent: { - ...parent - } - }; - } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/activity/Escalation.js b/src/activity/Escalation.js index 491f8bcf..e1ae4878 100644 --- a/src/activity/Escalation.js +++ b/src/activity/Escalation.js @@ -1,23 +1,30 @@ -export function Escalation(signalDef, context) { - const { id, type, name, parent: originalParent } = signalDef; - const { environment } = context; - const parent = { ...originalParent }; +/** + * Escalation reference element. Resolves the escalation name expression against the execution message. + * @param {import('moddle-context-serializer').SerializableElement} escalationDef + * @param {import('#types').ContextInstance} context + */ +export function Escalation(escalationDef, context) { + if (!(this instanceof Escalation)) return new Escalation(escalationDef, context); + const { id, type, name, parent } = escalationDef; + this.id = id; + this.type = type; + this.name = name; + /** @type {import('#types').ElementParent} */ + this.parent = { ...parent }; + this.environment = context.environment; +} +/** + * Resolve escalation reference for the given execution message. + * @param {import('#types').ElementBrokerMessage} executionMessage + */ +Escalation.prototype.resolve = function resolve(executionMessage) { + const { id, type, name, parent } = this; return { id, type, - name, - parent, - resolve, + messageType: 'escalation', + name: name && this.environment.resolveExpression(name, executionMessage), + parent: { ...parent }, }; - - function resolve(executionMessage) { - return { - id, - type, - messageType: 'escalation', - name: name && environment.resolveExpression(name, executionMessage), - parent: { ...parent }, - }; - } -} +}; diff --git a/src/activity/Message.js b/src/activity/Message.js index 4821ac11..b144104d 100644 --- a/src/activity/Message.js +++ b/src/activity/Message.js @@ -1,23 +1,30 @@ +/** + * Message reference element. Resolves the message name expression against the execution message. + * @param {import('moddle-context-serializer').SerializableElement} messageDef + * @param {import('#types').ContextInstance} context + */ export function Message(messageDef, context) { - const { id, type, name, parent: originalParent } = messageDef; - const { environment } = context; - const parent = { ...originalParent }; + if (!(this instanceof Message)) return new Message(messageDef, context); + const { id, type, name, parent } = messageDef; + this.id = id; + this.type = type; + this.name = name; + /** @type {import('#types').ElementParent} */ + this.parent = { ...parent }; + this.environment = context.environment; +} +/** + * Resolve message reference for the given execution message. + * @param {import('#types').ElementBrokerMessage} executionMessage + */ +Message.prototype.resolve = function resolve(executionMessage) { + const { id, type, name, parent } = this; return { id, type, - name, - parent, - resolve, + messageType: 'message', + ...(name && { name: this.environment.resolveExpression(name, executionMessage) }), + parent: { ...parent }, }; - - function resolve(executionMessage) { - return { - id, - type, - messageType: 'message', - ...(name && { name: environment.resolveExpression(name, executionMessage) }), - parent: { ...parent }, - }; - } -} +}; diff --git a/src/activity/Signal.js b/src/activity/Signal.js index b38a9de3..2d52904a 100644 --- a/src/activity/Signal.js +++ b/src/activity/Signal.js @@ -1,23 +1,30 @@ +/** + * Signal reference element. Resolves the signal name expression against the execution message. + * @param {import('moddle-context-serializer').SerializableElement} signalDef + * @param {import('#types').ContextInstance} context + */ export function Signal(signalDef, context) { - const { id, type = 'Signal', name, parent: originalParent } = signalDef; - const { environment } = context; - const parent = { ...originalParent }; + if (!(this instanceof Signal)) return new Signal(signalDef, context); + const { id, type = 'Signal', name, parent } = signalDef; + this.id = id; + this.type = type; + this.name = name; + /** @type {import('#types').ElementParent} */ + this.parent = { ...parent }; + this.environment = context.environment; +} +/** + * Resolve signal reference for the given execution message. + * @param {import('#types').ElementBrokerMessage} executionMessage + */ +Signal.prototype.resolve = function resolve(executionMessage) { + const { id, type, name, parent } = this; return { id, type, - name, - parent, - resolve, + messageType: 'signal', + ...(name && { name: this.environment.resolveExpression(name, executionMessage) }), + parent: { ...parent }, }; - - function resolve(executionMessage) { - return { - id, - type, - messageType: 'signal', - ...(name && { name: environment.resolveExpression(name, executionMessage) }), - parent: { ...parent }, - }; - } -} +}; diff --git a/test/activity/Escalation-test.js b/test/activity/Escalation-test.js new file mode 100644 index 00000000..2c85e172 --- /dev/null +++ b/test/activity/Escalation-test.js @@ -0,0 +1,76 @@ +import { Environment, Escalation } from 'bpmn-elements'; + +describe('Escalation', () => { + let environment; + beforeEach(() => { + environment = new Environment(); + }); + + it('exposes id, type, name and cloned parent', () => { + const parent = { id: 'Process_0', type: 'bpmn:Process' }; + const escalation = new Escalation( + { + id: 'Escalation_0', + type: 'bpmn:Escalation', + name: 'My escalation', + parent, + }, + { environment } + ); + + expect(escalation).to.have.property('id', 'Escalation_0'); + expect(escalation).to.have.property('type', 'bpmn:Escalation'); + expect(escalation).to.have.property('name', 'My escalation'); + expect(escalation.parent).to.eql(parent); + expect(escalation.parent, 'cloned parent').to.not.equal(parent); + }); + + it('falls back to constructing when called without new', () => { + const escalation = Escalation({ id: 'Escalation_0' }, { environment }); + expect(escalation).to.be.instanceof(Escalation); + }); + + describe('resolve', () => { + it('returns id, type and messageType=escalation with cloned parent', () => { + const parent = { id: 'Process_0', type: 'bpmn:Process' }; + const escalation = new Escalation( + { + id: 'Escalation_0', + type: 'bpmn:Escalation', + parent, + }, + { environment } + ); + + const resolved = escalation.resolve({ content: { id: 'task' } }); + + expect(resolved).to.have.property('id', 'Escalation_0'); + expect(resolved).to.have.property('type', 'bpmn:Escalation'); + expect(resolved).to.have.property('messageType', 'escalation'); + expect(resolved.parent).to.eql(parent); + expect(resolved.parent).to.not.equal(parent); + }); + + it('resolves name expression against execution message when name is set', () => { + const escalation = new Escalation( + { + id: 'Escalation_0', + name: 'Escalate ${content.id}', + }, + { environment } + ); + + const resolved = escalation.resolve({ content: { id: 'task' } }); + + expect(resolved).to.have.property('name', 'Escalate task'); + }); + + it('keeps name as falsy value when escalation reference has no name', () => { + const escalation = new Escalation({ id: 'Escalation_0' }, { environment }); + + const resolved = escalation.resolve({ content: { id: 'task' } }); + + expect(resolved).to.have.property('name').that.is.undefined; + }); + }); +}); diff --git a/test/activity/Message-test.js b/test/activity/Message-test.js new file mode 100644 index 00000000..a704442e --- /dev/null +++ b/test/activity/Message-test.js @@ -0,0 +1,82 @@ +import { Environment, Message } from 'bpmn-elements'; + +describe('Message', () => { + let environment; + beforeEach(() => { + environment = new Environment(); + }); + + it('exposes id, type, name and cloned parent', () => { + const parent = { id: 'Process_0', type: 'bpmn:Process' }; + const message = new Message( + { + id: 'Message_0', + type: 'bpmn:Message', + name: 'My message', + parent, + }, + { environment } + ); + + expect(message).to.have.property('id', 'Message_0'); + expect(message).to.have.property('type', 'bpmn:Message'); + expect(message).to.have.property('name', 'My message'); + expect(message.parent).to.eql(parent); + expect(message.parent, 'cloned parent').to.not.equal(parent); + }); + + it('falls back to constructing when called without new', () => { + const message = Message( + { + id: 'Message_0', + type: 'bpmn:Message', + }, + { environment } + ); + expect(message).to.be.instanceof(Message); + }); + + describe('resolve', () => { + it('returns id, type and messageType=message with cloned parent', () => { + const parent = { id: 'Process_0', type: 'bpmn:Process' }; + const message = new Message( + { + id: 'Message_0', + type: 'bpmn:Message', + parent, + }, + { environment } + ); + + const resolved = message.resolve({ content: { id: 'task' } }); + + expect(resolved).to.have.property('id', 'Message_0'); + expect(resolved).to.have.property('type', 'bpmn:Message'); + expect(resolved).to.have.property('messageType', 'message'); + expect(resolved.parent).to.eql(parent); + expect(resolved.parent).to.not.equal(parent); + }); + + it('resolves name expression against execution message when name is set', () => { + const message = new Message( + { + id: 'Message_0', + name: 'My ${content.id}', + }, + { environment } + ); + + const resolved = message.resolve({ content: { id: 'task' } }); + + expect(resolved).to.have.property('name', 'My task'); + }); + + it('omits name when message reference has no name', () => { + const message = new Message({ id: 'Message_0' }, { environment }); + + const resolved = message.resolve({ content: { id: 'task' } }); + + expect(resolved).to.not.have.property('name'); + }); + }); +}); diff --git a/test/activity/Signal-test.js b/test/activity/Signal-test.js new file mode 100644 index 00000000..516a973d --- /dev/null +++ b/test/activity/Signal-test.js @@ -0,0 +1,81 @@ +import { Environment, Signal } from 'bpmn-elements'; + +describe('Signal', () => { + let environment; + beforeEach(() => { + environment = new Environment(); + }); + + it('exposes id, type, name and cloned parent', () => { + const parent = { id: 'Process_0', type: 'bpmn:Process' }; + const signal = new Signal( + { + id: 'Signal_0', + type: 'bpmn:Signal', + name: 'My signal', + parent, + }, + { environment } + ); + + expect(signal).to.have.property('id', 'Signal_0'); + expect(signal).to.have.property('type', 'bpmn:Signal'); + expect(signal).to.have.property('name', 'My signal'); + expect(signal.parent).to.eql(parent); + expect(signal.parent, 'cloned parent').to.not.equal(parent); + }); + + it('defaults type to Signal when missing', () => { + const signal = new Signal({ id: 'Signal_0' }, { environment }); + expect(signal).to.have.property('type', 'Signal'); + }); + + it('falls back to constructing when called without new', () => { + const signal = Signal({ id: 'Signal_0' }, { environment }); + expect(signal).to.be.instanceof(Signal); + }); + + describe('resolve', () => { + it('returns id, type and messageType=signal with cloned parent', () => { + const parent = { id: 'Process_0', type: 'bpmn:Process' }; + const signal = new Signal( + { + id: 'Signal_0', + type: 'bpmn:Signal', + parent, + }, + { environment } + ); + + const resolved = signal.resolve({ content: { id: 'task' } }); + + expect(resolved).to.have.property('id', 'Signal_0'); + expect(resolved).to.have.property('type', 'bpmn:Signal'); + expect(resolved).to.have.property('messageType', 'signal'); + expect(resolved.parent).to.eql(parent); + expect(resolved.parent).to.not.equal(parent); + }); + + it('resolves name expression against execution message when name is set', () => { + const signal = new Signal( + { + id: 'Signal_0', + name: 'Signal for ${content.id}', + }, + { environment } + ); + + const resolved = signal.resolve({ content: { id: 'task' } }); + + expect(resolved).to.have.property('name', 'Signal for task'); + }); + + it('omits name when signal reference has no name', () => { + const signal = new Signal({ id: 'Signal_0' }, { environment }); + + const resolved = signal.resolve({ content: { id: 'task' } }); + + expect(resolved).to.not.have.property('name'); + }); + }); +}); diff --git a/test/eventDefinitions/MessageEventDefinition-test.js b/test/eventDefinitions/MessageEventDefinition-test.js index 06f8290b..16cc637d 100644 --- a/test/eventDefinitions/MessageEventDefinition-test.js +++ b/test/eventDefinitions/MessageEventDefinition-test.js @@ -14,7 +14,7 @@ describe('MessageEventDefinition', () => { broker: ActivityBroker(this).broker, getActivityById(id) { if (id !== 'message_1') return; - return Message( + return new Message( { id: 'message_1', type: 'bpmn:Message', diff --git a/test/eventDefinitions/SignalEventDefinition-test.js b/test/eventDefinitions/SignalEventDefinition-test.js index 9c2fb13d..3b4628fd 100644 --- a/test/eventDefinitions/SignalEventDefinition-test.js +++ b/test/eventDefinitions/SignalEventDefinition-test.js @@ -13,7 +13,7 @@ describe('SignalEventDefinition', () => { broker: ActivityBroker(this).broker, getActivityById(id) { if (id !== 'Signal_0') return; - return Signal({ id }, testHelpers.emptyContext()); + return new Signal({ id }, testHelpers.emptyContext()); }, }; }); diff --git a/types/index.d.ts b/types/index.d.ts index bc0a57f1..cd80fae7 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1196,19 +1196,36 @@ declare module 'bpmn-elements' { write(broker: import("smqp").Broker, exchange: string, routingKeyPrefix: string, value: any, messageProperties?: Record): number | undefined; } - export function Escalation(signalDef: any, context: any): { - id: any; - type: any; - name: any; - parent: any; - resolve: (executionMessage: any) => { - id: any; - type: any; + /** + * Escalation reference element. Resolves the escalation name expression against the execution message. + * */ + export class Escalation { + /** + * Escalation reference element. Resolves the escalation name expression against the execution message. + * */ + constructor(escalationDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string | undefined; + name: string | undefined; + + parent: ElementParent; + environment: Environment | undefined; + /** + * Resolve escalation reference for the given execution message. + * */ + resolve(executionMessage: ElementBrokerMessage): { + id: string | undefined; + type: string | undefined; messageType: string; name: any; - parent: any; + parent: { + id: string; + type: string; + executionId: string; + path?: Omit[]; + }; }; - }; + } /** * Activity ioSpecification behaviour. Reads bound data objects on enter and writes them on completion. * */ @@ -1328,13 +1345,36 @@ declare module 'bpmn-elements' { subscribe(onIterationCompleteMessage: ElementBrokerMessage): void; stop(): void; } - export function Message(messageDef: any, context: any): { - id: any; - type: any; - name: any; - parent: any; - resolve: (executionMessage: any) => any; - }; + /** + * Message reference element. Resolves the message name expression against the execution message. + * */ + export class Message { + /** + * Message reference element. Resolves the message name expression against the execution message. + * */ + constructor(messageDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string | undefined; + name: string | undefined; + + parent: ElementParent; + environment: Environment | undefined; + /** + * Resolve message reference for the given execution message. + * */ + resolve(executionMessage: ElementBrokerMessage): { + parent: { + id: string; + type: string; + executionId: string; + path?: Omit[]; + }; + name?: any; + id: string | undefined; + type: string | undefined; + messageType: string; + }; + } /** * Owns one ``. Wraps the structural definition and orchestrates flow traversal, * joins, and parallel activation through ProcessExecution. @@ -1486,13 +1526,36 @@ declare module 'bpmn-elements' { activity: Activity; execute(executionMessage: any, callback: any): any; } - export function Signal(signalDef: any, context: any): { - id: any; - type: any; - name: any; - parent: any; - resolve: (executionMessage: any) => any; - }; + /** + * Signal reference element. Resolves the signal name expression against the execution message. + * */ + export class Signal { + /** + * Signal reference element. Resolves the signal name expression against the execution message. + * */ + constructor(signalDef: import("moddle-context-serializer").SerializableElement, context: ContextInstance); + id: string | undefined; + type: string | undefined; + name: string | undefined; + + parent: ElementParent; + environment: Environment | undefined; + /** + * Resolve signal reference for the given execution message. + * */ + resolve(executionMessage: ElementBrokerMessage): { + parent: { + id: string; + type: string; + executionId: string; + path?: Omit[]; + }; + name?: any; + id: string | undefined; + type: string | undefined; + messageType: string; + }; + } /** * Standard loop characteristics * */ From 1b5dc812282f52ce1934287d0b847a3c30356b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 31 May 2026 08:10:39 +0200 Subject: [PATCH 17/31] import from bpmn-elements in tests --- dist/EventBroker.js | 6 +- package.json | 3 +- src/EventBroker.js | 6 +- test/Api-test.js | 2 +- test/Context-test.js | 3 +- test/Environment-test.js | 3 +- test/MessageFormatter-test.js | 2 +- test/Timers-test.js | 3 +- test/activity-api-test.js | 2 +- test/activity/Activity-test.js | 8 +- test/activity/ActivityExecution-test.js | 6 +- test/activity/ExecutionScope-test.js | 4 +- test/activity/activity-run-test.js | 7 +- test/definition/Definition-test.js | 7 +- test/definition/DefinitionExecution-test.js | 2 +- test/error/BpmnError-test.js | 3 +- test/error/Errors-test.js | 2 +- .../CancelEventDefinition-test.js | 4 +- .../CompensateEventDefinition-test.js | 10 +- .../ConditionalEventDefinition-test.js | 4 +- .../ErrorEventDefinition-test.js | 5 +- .../EscalationEventDefinition-test.js | 5 +- .../LinkEventDefinition-test.js | 4 +- .../MessageEventDefinition-test.js | 5 +- .../SignalEventDefinition-test.js | 5 +- .../TerminateEventDefinition-test.js | 4 +- .../TimerEventDefinition-test.js | 7 +- test/events/BoundaryEvent-test.js | 9 +- test/events/EndEvent-test.js | 4 +- test/events/IntermediateCatchEvent-test.js | 2 +- test/events/StartEvent-test.js | 4 +- test/flows/Association-test.js | 4 +- test/flows/MessageFlow-test.js | 4 +- test/flows/SequenceFlow-test.js | 7 +- test/gateways/ExclusiveGateway-test.js | 2 +- test/gateways/InclusiveGateway-test.js | 2 +- test/io/DataObject-test.js | 3 +- test/io/InputOutputSpecification-test.js | 2 +- test/io/Properties-test.js | 3 +- test/process/Process-test.js | 6 +- test/process/ProcessExecution-test.js | 22 +- test/tasks/LoopCharacteristics-test.js | 5 +- test/tasks/ReceiveTask-test.js | 4 +- test/tasks/ScriptTask-test.js | 6 +- test/tasks/ServiceTask-test.js | 6 +- test/tasks/SubProcess-test.js | 5 +- test/tasks/Transaction-test.js | 2 +- test/tasks/isForCompensation-test.js | 4 +- tsconfig.json | 3 +- tsconfig.tests.json | 10 - types/index.d.ts | 245 ++++++++---------- 51 files changed, 223 insertions(+), 263 deletions(-) delete mode 100644 tsconfig.tests.json diff --git a/dist/EventBroker.js b/dist/EventBroker.js index f5599785..76d139db 100644 --- a/dist/EventBroker.js +++ b/dist/EventBroker.js @@ -23,6 +23,7 @@ var _Errors = require("./error/Errors.js"); /** * Build the broker for an activity, including run/format/execution/api exchanges and queues. * @param {import('#types').Activity} activity + * @returns {import('#types').ElementBroker} */ function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); @@ -32,6 +33,7 @@ function ActivityBroker(activity) { /** * Build the broker for a process, with an additional api-q bound to all api routing keys. * @param {import('#types').Process} owner + * @returns {import('#types').ElementBroker} */ function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); @@ -47,6 +49,7 @@ function ProcessBroker(owner) { * Build the broker for a definition. Optionally registers a custom return-message handler. * @param {import('#types').Definition} owner * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] + * @returns {import('#types').ElementBroker} */ function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); @@ -54,7 +57,8 @@ function DefinitionBroker(owner, onBrokerReturn) { /** * Build the broker for a message flow with a durable message exchange and message-q. - * @param {import('#types').MessageFlow} owner + * @param {import('./flows/MessageFlow.js').MessageFlow} owner + * @returns {import('#types').ElementBroker} */ function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { diff --git a/package.json b/package.json index ec8b1eb1..71ad40d8 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,8 @@ "scripts": { "test": "mocha -R @bonniernews/hot-bev -p -t 3000", "posttest": "npm run lint && npm run dist", - "lint": "eslint . --cache && prettier . --check --cache", + "lint": "eslint . --cache && prettier . --check --cache && npm run typecheck", + "typecheck": "tsc --noEmit", "prepack": "npm run dist", "test:md": "texample ./docs/Examples.md,./docs/StartEvent.md,./docs/Extension.md,./docs/ConditionalEventDefinition.md", "cov:html": "c8 -r html -r text mocha -R @bonniernews/hot-bev -p -t 3000", diff --git a/src/EventBroker.js b/src/EventBroker.js index a7654559..fed0abb6 100644 --- a/src/EventBroker.js +++ b/src/EventBroker.js @@ -14,6 +14,7 @@ import { makeErrorFromMessage } from './error/Errors.js'; /** * Build the broker for an activity, including run/format/execution/api exchanges and queues. * @param {import('#types').Activity} activity + * @returns {import('#types').ElementBroker} */ export function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); @@ -23,6 +24,7 @@ export function ActivityBroker(activity) { /** * Build the broker for a process, with an additional api-q bound to all api routing keys. * @param {import('#types').Process} owner + * @returns {import('#types').ElementBroker} */ export function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); @@ -35,6 +37,7 @@ export function ProcessBroker(owner) { * Build the broker for a definition. Optionally registers a custom return-message handler. * @param {import('#types').Definition} owner * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] + * @returns {import('#types').ElementBroker} */ export function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); @@ -42,7 +45,8 @@ export function DefinitionBroker(owner, onBrokerReturn) { /** * Build the broker for a message flow with a durable message exchange and message-q. - * @param {import('#types').MessageFlow} owner + * @param {import('./flows/MessageFlow.js').MessageFlow} owner + * @returns {import('#types').ElementBroker} */ export function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { prefix: 'messageflow', autoDelete: false, durable: false }); diff --git a/test/Api-test.js b/test/Api-test.js index 06fa859a..3667fbeb 100644 --- a/test/Api-test.js +++ b/test/Api-test.js @@ -1,6 +1,6 @@ import { Broker } from 'smqp'; +import { Environment } from 'bpmn-elements'; import { ActivityApi } from '../src/Api.js'; -import { Environment } from '../src/Environment.js'; describe('Api', () => { it('Api without message throws', () => { expect(() => { diff --git a/test/Context-test.js b/test/Context-test.js index 84fb4edd..7ddefbbf 100644 --- a/test/Context-test.js +++ b/test/Context-test.js @@ -1,5 +1,4 @@ -import { Activity } from '../src/activity/Activity.js'; -import { Context } from '../src/Context.js'; +import { Activity, Context } from 'bpmn-elements'; import factory from './helpers/factory.js'; import testHelpers from './helpers/testHelpers.js'; diff --git a/test/Environment-test.js b/test/Environment-test.js index 51aaba40..37b1bcae 100644 --- a/test/Environment-test.js +++ b/test/Environment-test.js @@ -1,5 +1,4 @@ -import { Environment } from '../src/Environment.js'; -import { Timers } from '../src/Timers.js'; +import { Environment, Timers } from 'bpmn-elements'; describe('Environment', () => { describe('ctor', () => { diff --git a/test/MessageFormatter-test.js b/test/MessageFormatter-test.js index 5ede8abb..25490ec3 100644 --- a/test/MessageFormatter-test.js +++ b/test/MessageFormatter-test.js @@ -1,5 +1,5 @@ +import { ActivityError } from 'bpmn-elements/errors'; import { ActivityBroker } from '../src/EventBroker.js'; -import { ActivityError } from '../src/error/Errors.js'; import { Formatter } from '../src/MessageFormatter.js'; import { Logger } from './helpers/testHelpers.js'; diff --git a/test/Timers-test.js b/test/Timers-test.js index 2fc285f5..11b8b6d4 100644 --- a/test/Timers-test.js +++ b/test/Timers-test.js @@ -1,6 +1,5 @@ import * as ck from 'chronokinesis'; - -import { Timers } from '../src/Timers.js'; +import { Timers } from 'bpmn-elements'; describe('Timers', () => { describe('setTimeout', () => { diff --git a/test/activity-api-test.js b/test/activity-api-test.js index ba44ab2f..559bb53b 100644 --- a/test/activity-api-test.js +++ b/test/activity-api-test.js @@ -1,4 +1,4 @@ -import { Activity } from '../src/activity/Activity.js'; +import { Activity } from 'bpmn-elements'; import testHelpers from './helpers/testHelpers.js'; import { cloneContent } from '../src/messageHelper.js'; diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index 1513547c..ac3732c1 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -1,10 +1,8 @@ -import { Activity } from 'bpmn-elements'; -import { Association } from '../../src/flows/Association.js'; -import { Environment } from '../../src/Environment.js'; -import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; +import { Activity, Environment } from 'bpmn-elements'; +import { Association, SequenceFlow } from 'bpmn-elements/flows'; +import { TaskBehaviour, SignalTaskBehaviour } from 'bpmn-elements/tasks'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; -import { TaskBehaviour, SignalTaskBehaviour } from '../../src/tasks/index.js'; function Behaviour() { return { diff --git a/test/activity/ActivityExecution-test.js b/test/activity/ActivityExecution-test.js index a47b97fc..984423ea 100644 --- a/test/activity/ActivityExecution-test.js +++ b/test/activity/ActivityExecution-test.js @@ -1,9 +1,7 @@ -import { Activity } from '../../src/activity/Activity.js'; +import { Activity, Environment, MultiInstanceLoopCharacteristics as LoopCharacteristics } from 'bpmn-elements'; +import { SequenceFlow } from 'bpmn-elements/flows'; import { ActivityExecution } from '../../src/activity/ActivityExecution.js'; -import { Environment } from '../../src/Environment.js'; import { EventDefinitionExecution } from '../../src/eventDefinitions/EventDefinitionExecution.js'; -import { LoopCharacteristics } from '../../src/tasks/LoopCharacteristics.js'; -import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; import testHelpers from '../helpers/testHelpers.js'; const Logger = testHelpers.Logger; diff --git a/test/activity/ExecutionScope-test.js b/test/activity/ExecutionScope-test.js index 941eac1b..ecec748c 100644 --- a/test/activity/ExecutionScope-test.js +++ b/test/activity/ExecutionScope-test.js @@ -1,6 +1,6 @@ -import { Environment } from '../../src/Environment.js'; +import { Environment } from 'bpmn-elements'; +import { ActivityError, BpmnError } from 'bpmn-elements/errors'; import { ExecutionScope } from '../../src/activity/ExecutionScope.js'; -import { ActivityError, BpmnError } from '../../src/error/Errors.js'; describe('ExecutionScope', () => { it('exposes environment, error classes, and passed message', () => { diff --git a/test/activity/activity-run-test.js b/test/activity/activity-run-test.js index d9e7ee37..10d3f9d8 100644 --- a/test/activity/activity-run-test.js +++ b/test/activity/activity-run-test.js @@ -1,8 +1,7 @@ -import { Activity } from '../../src/activity/Activity.js'; -import { Environment } from '../../src/Environment.js'; -import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; +import { Activity, Environment } from 'bpmn-elements'; +import { SequenceFlow } from 'bpmn-elements/flows'; +import { TaskBehaviour } from 'bpmn-elements/tasks'; import testHelpers from '../helpers/testHelpers.js'; -import { TaskBehaviour } from '../../src/tasks/Task.js'; const Logger = testHelpers.Logger; diff --git a/test/definition/Definition-test.js b/test/definition/Definition-test.js index dad5e37e..061e9aa9 100644 --- a/test/definition/Definition-test.js +++ b/test/definition/Definition-test.js @@ -1,9 +1,8 @@ -import { Environment } from '../../src/Environment.js'; +import { format } from 'util'; +import { Definition, Environment } from 'bpmn-elements'; +import { ActivityError } from 'bpmn-elements/errors'; import factory from '../helpers/factory.js'; import testHelpers from '../helpers/testHelpers.js'; -import { ActivityError } from '../../src/error/Errors.js'; -import { Definition } from '../../src/definition/Definition.js'; -import { format } from 'util'; import { Scripts as JavaScripts } from '../helpers/JavaScripts.js'; const lanesSource = factory.resource('lanes.bpmn'); diff --git a/test/definition/DefinitionExecution-test.js b/test/definition/DefinitionExecution-test.js index f59aa22e..dd19097e 100644 --- a/test/definition/DefinitionExecution-test.js +++ b/test/definition/DefinitionExecution-test.js @@ -1,4 +1,4 @@ -import { Environment } from '../../src/Environment.js'; +import { Environment } from 'bpmn-elements'; import { DefinitionExecution } from '../../src/definition/DefinitionExecution.js'; import testHelpers from '../helpers/testHelpers.js'; import { DefinitionBroker, ProcessBroker } from '../../src/EventBroker.js'; diff --git a/test/error/BpmnError-test.js b/test/error/BpmnError-test.js index 5638e542..ae22f7cc 100644 --- a/test/error/BpmnError-test.js +++ b/test/error/BpmnError-test.js @@ -1,5 +1,4 @@ -import { BpmnErrorActivity } from '../../src/error/BpmnError.js'; -import { Environment } from '../../src/Environment.js'; +import { BpmnError as BpmnErrorActivity, Environment } from 'bpmn-elements'; describe('BpmnError', () => { it('returns BpmnError instanceof from error', () => { diff --git a/test/error/Errors-test.js b/test/error/Errors-test.js index 5a80c217..ddf75737 100644 --- a/test/error/Errors-test.js +++ b/test/error/Errors-test.js @@ -1,4 +1,4 @@ -import { ActivityError, BpmnError, makeErrorFromMessage } from '../../src/error/Errors.js'; +import { ActivityError, BpmnError, makeErrorFromMessage } from 'bpmn-elements/errors'; describe('Errors', () => { describe('ActivityError', () => { diff --git a/test/eventDefinitions/CancelEventDefinition-test.js b/test/eventDefinitions/CancelEventDefinition-test.js index baa4a440..76583150 100644 --- a/test/eventDefinitions/CancelEventDefinition-test.js +++ b/test/eventDefinitions/CancelEventDefinition-test.js @@ -1,5 +1,5 @@ -import { CancelEventDefinition } from '../../src/eventDefinitions/CancelEventDefinition.js'; -import { Environment } from '../../src/Environment.js'; +import { Environment } from 'bpmn-elements'; +import { CancelEventDefinition } from 'bpmn-elements/eventDefinitions'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/CompensateEventDefinition-test.js b/test/eventDefinitions/CompensateEventDefinition-test.js index 8476e0fd..3fa0cc7c 100644 --- a/test/eventDefinitions/CompensateEventDefinition-test.js +++ b/test/eventDefinitions/CompensateEventDefinition-test.js @@ -1,9 +1,7 @@ -import { Association } from '../../src/flows/Association.js'; -import { BoundaryEvent } from '../../src/events/BoundaryEvent.js'; -import { CompensateEventDefinition } from '../../src/eventDefinitions/CompensateEventDefinition.js'; -import { EndEvent } from '../../src/events/EndEvent.js'; -import { IntermediateThrowEvent } from '../../src/events/IntermediateThrowEvent.js'; -import { Task } from '../../src/tasks/Task.js'; +import { CompensateEventDefinition } from 'bpmn-elements/eventDefinitions'; +import { BoundaryEvent, EndEvent, IntermediateThrowEvent } from 'bpmn-elements/events'; +import { Association } from 'bpmn-elements/flows'; +import { Task } from 'bpmn-elements/tasks'; import testHelpers from '../helpers/testHelpers.js'; describe('CompensateEventDefinition', () => { diff --git a/test/eventDefinitions/ConditionalEventDefinition-test.js b/test/eventDefinitions/ConditionalEventDefinition-test.js index f68db7fe..f96732e8 100644 --- a/test/eventDefinitions/ConditionalEventDefinition-test.js +++ b/test/eventDefinitions/ConditionalEventDefinition-test.js @@ -1,5 +1,5 @@ -import { ConditionalEventDefinition } from '../../src/eventDefinitions/ConditionalEventDefinition.js'; -import { Environment } from '../../src/Environment.js'; +import { Environment } from 'bpmn-elements'; +import { ConditionalEventDefinition } from 'bpmn-elements/eventDefinitions'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; import { ActivityApi } from '../../src/Api.js'; diff --git a/test/eventDefinitions/ErrorEventDefinition-test.js b/test/eventDefinitions/ErrorEventDefinition-test.js index 45054da1..131dece0 100644 --- a/test/eventDefinitions/ErrorEventDefinition-test.js +++ b/test/eventDefinitions/ErrorEventDefinition-test.js @@ -1,6 +1,5 @@ -import { BpmnErrorActivity as BpmnError } from '../../src/error/BpmnError.js'; -import { Environment } from '../../src/Environment.js'; -import { ErrorEventDefinition } from '../../src/eventDefinitions/ErrorEventDefinition.js'; +import { BpmnError, Environment } from 'bpmn-elements'; +import { ErrorEventDefinition } from 'bpmn-elements/eventDefinitions'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; diff --git a/test/eventDefinitions/EscalationEventDefinition-test.js b/test/eventDefinitions/EscalationEventDefinition-test.js index f31b63bc..8d2ae422 100644 --- a/test/eventDefinitions/EscalationEventDefinition-test.js +++ b/test/eventDefinitions/EscalationEventDefinition-test.js @@ -1,6 +1,5 @@ -import { Environment } from '../../src/Environment.js'; -import { Escalation } from '../../src/activity/Escalation.js'; -import { EscalationEventDefinition } from '../../src/eventDefinitions/EscalationEventDefinition.js'; +import { Environment, Escalation } from 'bpmn-elements'; +import { EscalationEventDefinition } from 'bpmn-elements/eventDefinitions'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/LinkEventDefinition-test.js b/test/eventDefinitions/LinkEventDefinition-test.js index 87d6d7a0..70286e0f 100644 --- a/test/eventDefinitions/LinkEventDefinition-test.js +++ b/test/eventDefinitions/LinkEventDefinition-test.js @@ -1,5 +1,5 @@ -import { LinkEventDefinition } from '../../src/eventDefinitions/LinkEventDefinition.js'; -import { Environment } from '../../src/Environment.js'; +import { Environment } from 'bpmn-elements'; +import { LinkEventDefinition } from 'bpmn-elements/eventDefinitions'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/MessageEventDefinition-test.js b/test/eventDefinitions/MessageEventDefinition-test.js index 16cc637d..dd970ae1 100644 --- a/test/eventDefinitions/MessageEventDefinition-test.js +++ b/test/eventDefinitions/MessageEventDefinition-test.js @@ -1,6 +1,5 @@ -import { Message } from '../../src/activity/Message.js'; -import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; -import { Environment } from '../../src/Environment.js'; +import { Environment, Message } from 'bpmn-elements'; +import { MessageEventDefinition } from 'bpmn-elements/eventDefinitions'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; diff --git a/test/eventDefinitions/SignalEventDefinition-test.js b/test/eventDefinitions/SignalEventDefinition-test.js index 3b4628fd..673b9713 100644 --- a/test/eventDefinitions/SignalEventDefinition-test.js +++ b/test/eventDefinitions/SignalEventDefinition-test.js @@ -1,7 +1,6 @@ -import { Environment } from '../../src/Environment.js'; -import { SignalEventDefinition } from '../../src/eventDefinitions/SignalEventDefinition.js'; +import { Environment, Signal } from 'bpmn-elements'; +import { SignalEventDefinition } from 'bpmn-elements/eventDefinitions'; import testHelpers, { Logger } from '../helpers/testHelpers.js'; -import { Signal } from '../../src/activity/Signal.js'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('SignalEventDefinition', () => { diff --git a/test/eventDefinitions/TerminateEventDefinition-test.js b/test/eventDefinitions/TerminateEventDefinition-test.js index bc698647..080863fb 100644 --- a/test/eventDefinitions/TerminateEventDefinition-test.js +++ b/test/eventDefinitions/TerminateEventDefinition-test.js @@ -1,5 +1,5 @@ -import { Environment } from '../../src/Environment.js'; -import { TerminateEventDefinition } from '../../src/eventDefinitions/TerminateEventDefinition.js'; +import { Environment } from 'bpmn-elements'; +import { TerminateEventDefinition } from 'bpmn-elements/eventDefinitions'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('TerminateEventDefinition', () => { diff --git a/test/eventDefinitions/TimerEventDefinition-test.js b/test/eventDefinitions/TimerEventDefinition-test.js index ea620427..67bc4d69 100644 --- a/test/eventDefinitions/TimerEventDefinition-test.js +++ b/test/eventDefinitions/TimerEventDefinition-test.js @@ -1,11 +1,10 @@ import * as ck from 'chronokinesis'; -import { Environment } from '../../src/Environment.js'; +import { Environment, Timers } from 'bpmn-elements'; +import { RunError } from 'bpmn-elements/errors'; +import { TimerEventDefinition } from 'bpmn-elements/eventDefinitions'; import testHelpers from '../helpers/testHelpers.js'; -import { TimerEventDefinition } from '../../src/eventDefinitions/TimerEventDefinition.js'; import { ActivityApi, DefinitionApi } from '../../src/Api.js'; import { ActivityBroker } from '../../src/EventBroker.js'; -import { Timers } from '../../src/Timers.js'; -import { RunError } from '../../src/error/Errors.js'; describe('TimerEventDefinition', () => { let event; diff --git a/test/events/BoundaryEvent-test.js b/test/events/BoundaryEvent-test.js index 87358e30..9dcc908a 100644 --- a/test/events/BoundaryEvent-test.js +++ b/test/events/BoundaryEvent-test.js @@ -1,9 +1,8 @@ +import { Environment } from 'bpmn-elements'; +import { BoundaryEvent, BoundaryEventBehaviour } from 'bpmn-elements/events'; +import { ErrorEventDefinition, MessageEventDefinition } from 'bpmn-elements/eventDefinitions'; +import { SignalTask } from 'bpmn-elements/tasks'; import testHelpers from '../helpers/testHelpers.js'; -import { Environment } from '../../src/Environment.js'; -import { ErrorEventDefinition } from '../../src/eventDefinitions/ErrorEventDefinition.js'; -import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; -import { SignalTask } from '../../src/tasks/SignalTask.js'; -import { BoundaryEvent, BoundaryEventBehaviour } from '../../src/events/BoundaryEvent.js'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('BoundaryEvent', () => { diff --git a/test/events/EndEvent-test.js b/test/events/EndEvent-test.js index 0608df92..30e0db00 100644 --- a/test/events/EndEvent-test.js +++ b/test/events/EndEvent-test.js @@ -1,5 +1,5 @@ -import { EndEvent } from '../../src/events/EndEvent.js'; -import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; +import { EndEvent } from 'bpmn-elements/events'; +import { SequenceFlow } from 'bpmn-elements/flows'; import testHelpers from '../helpers/testHelpers.js'; describe('EndEvent', () => { diff --git a/test/events/IntermediateCatchEvent-test.js b/test/events/IntermediateCatchEvent-test.js index 13404f42..5086293a 100644 --- a/test/events/IntermediateCatchEvent-test.js +++ b/test/events/IntermediateCatchEvent-test.js @@ -1,4 +1,4 @@ -import { IntermediateCatchEvent } from '../../src/events/IntermediateCatchEvent.js'; +import { IntermediateCatchEvent } from 'bpmn-elements/events'; import testHelpers from '../helpers/testHelpers.js'; describe('IntermediateCatchEvent', () => { diff --git a/test/events/StartEvent-test.js b/test/events/StartEvent-test.js index 3b8ccb32..f1df8151 100644 --- a/test/events/StartEvent-test.js +++ b/test/events/StartEvent-test.js @@ -1,6 +1,6 @@ +import { StartEvent } from 'bpmn-elements/events'; +import { MessageEventDefinition } from 'bpmn-elements/eventDefinitions'; import JsExtension from '../resources/extensions/JsExtension.js'; -import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; -import { StartEvent } from '../../src/events/StartEvent.js'; import testHelpers from '../helpers/testHelpers.js'; describe('StartEvent', () => { diff --git a/test/flows/Association-test.js b/test/flows/Association-test.js index ea16fdb8..9d248acd 100644 --- a/test/flows/Association-test.js +++ b/test/flows/Association-test.js @@ -1,5 +1,5 @@ -import { Environment } from '../../src/Environment.js'; -import { Association } from '../../src/flows/Association.js'; +import { Environment } from 'bpmn-elements'; +import { Association } from 'bpmn-elements/flows'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('Association', () => { diff --git a/test/flows/MessageFlow-test.js b/test/flows/MessageFlow-test.js index 93e29d67..85b7206a 100644 --- a/test/flows/MessageFlow-test.js +++ b/test/flows/MessageFlow-test.js @@ -1,6 +1,6 @@ -import { Environment } from '../../src/Environment.js'; +import { Environment } from 'bpmn-elements'; +import { MessageFlow } from 'bpmn-elements/flows'; import factory from '../helpers/factory.js'; -import { MessageFlow } from '../../src/flows/MessageFlow.js'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; diff --git a/test/flows/SequenceFlow-test.js b/test/flows/SequenceFlow-test.js index da37980b..b709e9f0 100644 --- a/test/flows/SequenceFlow-test.js +++ b/test/flows/SequenceFlow-test.js @@ -1,9 +1,9 @@ -import { Environment } from '../../src/Environment.js'; +import { resolveExpression } from '@aircall/expression-parser'; +import { Environment } from 'bpmn-elements'; +import { SequenceFlow } from 'bpmn-elements/flows'; import factory from '../helpers/factory.js'; import js from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; -import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; -import { resolveExpression } from '@aircall/expression-parser'; import { Scripts } from '../helpers/JavaScripts.js'; const extensions = { @@ -70,6 +70,7 @@ describe('SequenceFlow', () => { }); describe('discard', () => { + /** @type {import('bpmn-elements').ContextInstance} */ let context; before(async () => { context = await testHelpers.context(factory.resource('multiple-multiple-inbound.bpmn')); diff --git a/test/gateways/ExclusiveGateway-test.js b/test/gateways/ExclusiveGateway-test.js index 2479d74c..54149ad9 100644 --- a/test/gateways/ExclusiveGateway-test.js +++ b/test/gateways/ExclusiveGateway-test.js @@ -1,5 +1,5 @@ +import { ActivityError } from 'bpmn-elements/errors'; import testHelpers from '../helpers/testHelpers.js'; -import { ActivityError } from '../../src/error/Errors.js'; describe('ExclusiveGateway', () => { describe('behavior', () => { diff --git a/test/gateways/InclusiveGateway-test.js b/test/gateways/InclusiveGateway-test.js index 7590bca1..ed3d94fc 100644 --- a/test/gateways/InclusiveGateway-test.js +++ b/test/gateways/InclusiveGateway-test.js @@ -1,5 +1,5 @@ +import { ActivityError } from 'bpmn-elements/errors'; import testHelpers from '../helpers/testHelpers.js'; -import { ActivityError } from '../../src/error/Errors.js'; describe('InclusiveGateway', () => { describe('behavior', () => { diff --git a/test/io/DataObject-test.js b/test/io/DataObject-test.js index 76a16568..ef68913d 100644 --- a/test/io/DataObject-test.js +++ b/test/io/DataObject-test.js @@ -1,5 +1,4 @@ -import { EnvironmentDataObject as DataObject } from '../../src/io/EnvironmentDataObject.js'; -import { Environment } from '../../src/Environment.js'; +import { DataObject, Environment } from 'bpmn-elements'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('DataObject', () => { diff --git a/test/io/InputOutputSpecification-test.js b/test/io/InputOutputSpecification-test.js index b8d46ae1..9f1526fc 100644 --- a/test/io/InputOutputSpecification-test.js +++ b/test/io/InputOutputSpecification-test.js @@ -1,4 +1,4 @@ -import { IoSpecification as InputOutputSpecification } from '../../src/io/InputOutputSpecification.js'; +import { InputOutputSpecification } from 'bpmn-elements'; import testHelpers from '../helpers/testHelpers.js'; import { ActivityBroker } from '../../src/EventBroker.js'; diff --git a/test/io/Properties-test.js b/test/io/Properties-test.js index 67a389d4..ff754b01 100644 --- a/test/io/Properties-test.js +++ b/test/io/Properties-test.js @@ -1,5 +1,4 @@ -import { Environment } from '../../src/Environment.js'; -import { Properties } from '../../src/io/Properties.js'; +import { Environment, Properties } from 'bpmn-elements'; import { ActivityBroker } from '../../src/EventBroker.js'; describe('Properties', () => { diff --git a/test/process/Process-test.js b/test/process/Process-test.js index df1b6195..1bc3d286 100644 --- a/test/process/Process-test.js +++ b/test/process/Process-test.js @@ -1,9 +1,9 @@ +import { Process } from 'bpmn-elements'; +import { SignalTask } from 'bpmn-elements/tasks'; +import { ActivityError } from 'bpmn-elements/errors'; import factory from '../helpers/factory.js'; import JsExtension from '../resources/extensions/JsExtension.js'; -import { SignalTask } from '../../src/tasks/SignalTask.js'; import testHelpers from '../helpers/testHelpers.js'; -import { ActivityError } from '../../src/error/Errors.js'; -import { Process } from '../../src/process/Process.js'; describe('Process', () => { describe('requirements', () => { diff --git a/test/process/ProcessExecution-test.js b/test/process/ProcessExecution-test.js index 1025e46d..c3ddcc2c 100644 --- a/test/process/ProcessExecution-test.js +++ b/test/process/ProcessExecution-test.js @@ -1,16 +1,14 @@ -import { BoundaryEvent } from '../../src/events/BoundaryEvent.js'; -import { EndEvent } from '../../src/events/EndEvent.js'; -import { ErrorEventDefinition } from '../../src/eventDefinitions/ErrorEventDefinition.js'; -import { MessageEventDefinition } from '../../src/eventDefinitions/MessageEventDefinition.js'; -import { TimerEventDefinition } from '../../src/eventDefinitions/TimerEventDefinition.js'; +import { Process } from 'bpmn-elements'; +import { BoundaryEvent, EndEvent, StartEvent } from 'bpmn-elements/events'; +import { + ErrorEventDefinition, + MessageEventDefinition, + TerminateEventDefinition, + TimerEventDefinition, +} from 'bpmn-elements/eventDefinitions'; +import { SequenceFlow } from 'bpmn-elements/flows'; +import { ServiceTask, SignalTask, SubProcess } from 'bpmn-elements/tasks'; import { ProcessExecution } from '../../src/process/ProcessExecution.js'; -import { Process } from '../../src/process/Process.js'; -import { ServiceTask } from '../../src/tasks/ServiceTask.js'; -import { SequenceFlow } from '../../src/flows/SequenceFlow.js'; -import { SignalTask } from '../../src/tasks/SignalTask.js'; -import { StartEvent } from '../../src/events/StartEvent.js'; -import { SubProcess } from '../../src/tasks/SubProcess.js'; -import { TerminateEventDefinition } from '../../src/eventDefinitions/TerminateEventDefinition.js'; import testHelpers from '../helpers/testHelpers.js'; describe('Process execution', () => { diff --git a/test/tasks/LoopCharacteristics-test.js b/test/tasks/LoopCharacteristics-test.js index 49634131..512488e9 100644 --- a/test/tasks/LoopCharacteristics-test.js +++ b/test/tasks/LoopCharacteristics-test.js @@ -1,8 +1,7 @@ -import { Environment } from '../../src/Environment.js'; -import { LoopCharacteristics } from '../../src/tasks/LoopCharacteristics.js'; +import { Environment, MultiInstanceLoopCharacteristics as LoopCharacteristics } from 'bpmn-elements'; +import { ActivityError } from 'bpmn-elements/errors'; import { ActivityBroker } from '../../src/EventBroker.js'; import { Logger } from '../helpers/testHelpers.js'; -import { ActivityError } from '../../src/error/Errors.js'; describe('LoopCharacteristics', () => { let task; diff --git a/test/tasks/ReceiveTask-test.js b/test/tasks/ReceiveTask-test.js index 038fcc79..3ea5f6f7 100644 --- a/test/tasks/ReceiveTask-test.js +++ b/test/tasks/ReceiveTask-test.js @@ -1,5 +1,5 @@ -import { Message } from '../../src/activity/Message.js'; -import { ReceiveTask } from '../../src/tasks/ReceiveTask.js'; +import { Message } from 'bpmn-elements'; +import { ReceiveTask } from 'bpmn-elements/tasks'; import testHelpers from '../helpers/testHelpers.js'; describe('ReceiveTask', () => { diff --git a/test/tasks/ScriptTask-test.js b/test/tasks/ScriptTask-test.js index abe20cda..98133445 100644 --- a/test/tasks/ScriptTask-test.js +++ b/test/tasks/ScriptTask-test.js @@ -1,9 +1,9 @@ -import js from '../resources/extensions/JsExtension.js'; import nock from 'nock'; +import { Timers } from 'bpmn-elements'; +import { ActivityError } from 'bpmn-elements/errors'; +import js from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; -import { ActivityError } from '../../src/error/Errors.js'; import { Scripts } from '../helpers/JavaScripts.js'; -import { Timers } from '../../src/Timers.js'; const extensions = { js, diff --git a/test/tasks/ServiceTask-test.js b/test/tasks/ServiceTask-test.js index 5a99b998..86a09d98 100644 --- a/test/tasks/ServiceTask-test.js +++ b/test/tasks/ServiceTask-test.js @@ -1,8 +1,8 @@ -import JsExtension from '../resources/extensions/JsExtension.js'; import nock from 'nock'; -import { ServiceTask } from '../../src/tasks/ServiceTask.js'; +import { ServiceTask } from 'bpmn-elements/tasks'; +import { ActivityError } from 'bpmn-elements/errors'; +import JsExtension from '../resources/extensions/JsExtension.js'; import testHelpers from '../helpers/testHelpers.js'; -import { ActivityError } from '../../src/error/Errors.js'; describe('ServiceTask', () => { describe('behaviour', () => { diff --git a/test/tasks/SubProcess-test.js b/test/tasks/SubProcess-test.js index e418f0bb..b0e0a1da 100644 --- a/test/tasks/SubProcess-test.js +++ b/test/tasks/SubProcess-test.js @@ -1,9 +1,8 @@ +import { SignalTask, SubProcess } from 'bpmn-elements/tasks'; +import { BpmnError } from 'bpmn-elements/errors'; import factory from '../helpers/factory.js'; import JsExtension from '../resources/extensions/JsExtension.js'; -import { SignalTask } from '../../src/tasks/SignalTask.js'; -import { SubProcess } from '../../src/tasks/SubProcess.js'; import testHelpers from '../helpers/testHelpers.js'; -import { BpmnError } from '../../src/error/Errors.js'; const subProcessSource = factory.resource('sub-process.bpmn'); diff --git a/test/tasks/Transaction-test.js b/test/tasks/Transaction-test.js index 74961554..86611076 100644 --- a/test/tasks/Transaction-test.js +++ b/test/tasks/Transaction-test.js @@ -1,4 +1,4 @@ -import { Transaction } from '../../src/tasks/Transaction.js'; +import { Transaction } from 'bpmn-elements/tasks'; import testHelpers from '../helpers/testHelpers.js'; describe('Transaction', () => { diff --git a/test/tasks/isForCompensation-test.js b/test/tasks/isForCompensation-test.js index a759cf7e..0862ebd7 100644 --- a/test/tasks/isForCompensation-test.js +++ b/test/tasks/isForCompensation-test.js @@ -1,5 +1,5 @@ -import { Association } from '../../src/flows/Association.js'; -import { ServiceTask } from '../../src/tasks/ServiceTask.js'; +import { Association } from 'bpmn-elements/flows'; +import { ServiceTask } from 'bpmn-elements/tasks'; import testHelpers from '../helpers/testHelpers.js'; describe('isForCompensation task', () => { diff --git a/tsconfig.json b/tsconfig.json index 7ac8fb21..3560a0e4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,8 @@ { - "include": ["src/**/*", "types"], + "include": ["src/**/*", "test/**/*", "types"], "compilerOptions": { "emitDeclarationOnly": true, "sourceMap": false, - "rootDir": "src", "lib": ["es2020"], "target": "es2020", "outDir": "./tmp/ignore", diff --git a/tsconfig.tests.json b/tsconfig.tests.json deleted file mode 100644 index 8591c495..00000000 --- a/tsconfig.tests.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["src/**/*", "test/**/*", "types"], - "compilerOptions": { - "rootDir": ".", - "noEmit": true, - "emitDeclarationOnly": false, - "declaration": false - } -} diff --git a/types/index.d.ts b/types/index.d.ts index cd80fae7..d569a80c 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -545,16 +545,13 @@ declare module 'bpmn-elements' { context: ContextInstance; status: ActivityRunStatus; - broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; - emitFatal: (error: Error, content?: Record) => void; + broker: any; + on: (eventName: string, callback: (event: { + name: string; + } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; + once: any; + waitFor: any; + emitFatal: any; /** * Subscribe to inbound flows and start consuming the inbound queue. * */ @@ -608,7 +605,7 @@ declare module 'bpmn-elements' { /** * Stop the activity. If not currently running, just cancels the inbound consumer. */ - stop(): boolean | void; + stop(): any; /** * Advance one run-step when the environment runs in step mode. No-op otherwise. */ @@ -672,13 +669,13 @@ declare module 'bpmn-elements' { activity: Activity; context: ContextInstance; id: string | undefined; - broker: import("smqp").Broker; + broker: any; get completed(): boolean; /** * Begin executing the activity behaviour. Resumes if the message is redelivered. * @throws {Error} when message or executionId is missing */ - execute(executeMessage: ElementBrokerMessage): number | undefined; + execute(executeMessage: ElementBrokerMessage): any; executionId: string | undefined; source: IActivityBehaviour | undefined; /** @@ -871,16 +868,13 @@ declare module 'bpmn-elements' { context: ContextInstance | undefined; broker: import("smqp").Broker; - on: ((eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer) | undefined; - once: ((eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer) | undefined; - waitFor: ((eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise) | undefined; - emit: ((eventName: string, content?: Record, props?: any) => void) | undefined; - emitFatal: ((error: Error, content?: Record) => void) | undefined; + on: ((eventName: string, callback: (event: { + name: string; + } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer) | undefined; + once: any; + waitFor: any; + emit: any; + emitFatal: any; logger: ILogger; /** @@ -1241,7 +1235,7 @@ declare module 'bpmn-elements' { dataOutputs?: import("moddle-context-serializer").IElement[]; }; activity: Activity; - broker: import("smqp").Broker; + broker: any; context: ContextInstance; activate(message?: ElementBrokerMessage): void; @@ -1266,7 +1260,7 @@ declare module 'bpmn-elements' { behaviour: Record; environment: Environment; - broker: import("smqp").Broker; + broker: any; context: ContextInstance; logger: ILogger; get process(): Process; @@ -1310,7 +1304,7 @@ declare module 'bpmn-elements' { message: ElementBrokerMessage; type: string; id: string | undefined; - broker: import("smqp").Broker; + broker: any; parentExecutionId: string | undefined; isSequential: boolean; @@ -1395,15 +1389,12 @@ declare module 'bpmn-elements' { isExecutable: any; environment: Environment; context: ContextInstance; - broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + broker: any; + on: (eventName: string, callback: (event: { + name: string; + } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; + once: any; + waitFor: any; logger: ILogger; /** * Allocate an executionId and emit init event without starting the run. @@ -1508,7 +1499,7 @@ declare module 'bpmn-elements' { values: import("moddle-context-serializer").IElement[]; }, context: ContextInstance); activity: Activity; - broker: import("smqp").Broker; + broker: any; activate(message: ElementBrokerMessage): void; deactivate(): void; @@ -1596,7 +1587,7 @@ declare module 'bpmn-elements' { type: string; isSubProcess: any; isTransaction: any; - broker: import("smqp").Broker; + broker: any; environment: Environment; context: ContextInstance; executionId: string | undefined; @@ -1855,16 +1846,13 @@ declare module 'bpmn-elements' { behaviour: Record; environment: Environment; context: ContextInstance; - broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - emit: (eventName: string, content?: Record, props?: any) => void; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + broker: any; + on: (eventName: string, callback: (event: { + name: string; + } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; + once: any; + emit: any; + waitFor: any; logger: ILogger; get counters(): { messages: number; @@ -1980,7 +1968,7 @@ declare module 'bpmn-elements' { isThrowing: boolean; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; @@ -2004,15 +1992,15 @@ declare module 'bpmn-elements' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | import("smqp").Consumer | undefined; + execute(executeMessage: ElementBrokerMessage): any; - executeCatch(executeMessage: ElementBrokerMessage): import("smqp").Consumer | undefined; + executeCatch(executeMessage: ElementBrokerMessage): any; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Conditional event definition @@ -2029,7 +2017,7 @@ declare module 'bpmn-elements' { behaviour: {}; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; logger: ILogger; condition: ScriptCondition | ExpressionCondition | null; get executionId(): string; @@ -2044,7 +2032,7 @@ declare module 'bpmn-elements' { * @param err Condition evaluation error * @param result Result from evaluated condition, completes execution if truthy */ - evaluateCallback(err: Error | null, result: any): number | undefined; + evaluateCallback(err: Error | null, result: any): any; /** * Get condition * @param index Eventdefinition sequence number, used to name registered script @@ -2066,15 +2054,15 @@ declare module 'bpmn-elements' { isThrowing: boolean; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Escalation event definition @@ -2090,15 +2078,15 @@ declare module 'bpmn-elements' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Link event definition @@ -2114,15 +2102,15 @@ declare module 'bpmn-elements' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | undefined; + execute(executeMessage: ElementBrokerMessage): any; - executeCatch(executeMessage: ElementBrokerMessage): number | undefined; + executeCatch(executeMessage: ElementBrokerMessage): any; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Message event definition @@ -2138,15 +2126,15 @@ declare module 'bpmn-elements' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Signal event definition @@ -2162,15 +2150,15 @@ declare module 'bpmn-elements' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Terminate event definition @@ -2183,7 +2171,7 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; execute(executeMessage: ElementBrokerMessage): void; @@ -2203,7 +2191,7 @@ declare module 'bpmn-elements' { timeDuration: string | undefined; timeCycle: string | undefined; timeDate: string | undefined; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; get stopped(): boolean; @@ -2330,7 +2318,7 @@ declare module 'bpmn-elements/events' { attachedTo: Activity | null; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; get executionId(): string | undefined; get cancelActivity(): unknown; @@ -2350,7 +2338,7 @@ declare module 'bpmn-elements/events' { constructor(activity: Activity); id: string | undefined; type: string; - broker: import("smqp").Broker; + broker: any; execute(executeMessage: ElementBrokerMessage): void; } @@ -2368,7 +2356,7 @@ declare module 'bpmn-elements/events' { constructor(activity: Activity); id: string | undefined; type: string; - broker: import("smqp").Broker; + broker: any; execute(executeMessage: ElementBrokerMessage): void; } @@ -2386,7 +2374,7 @@ declare module 'bpmn-elements/events' { constructor(activity: Activity); id: string | undefined; type: string; - broker: import("smqp").Broker; + broker: any; execute(executeMessage: ElementBrokerMessage): void; } @@ -2405,7 +2393,7 @@ declare module 'bpmn-elements/events' { id: string | undefined; type: string; activity: Activity; - broker: import("smqp").Broker; + broker: any; get executionId(): string | undefined; execute(executeMessage: ElementBrokerMessage): void; @@ -2424,7 +2412,7 @@ declare module 'bpmn-elements/events' { constructor(activity: Activity, eventDefinitions: EventDefinition[], completedRoutingKey?: string); id: string | undefined; activity: Activity; - broker: import("smqp").Broker; + broker: any; eventDefinitions: EventDefinition[]; completedRoutingKey: string; get completed(): boolean; @@ -2446,7 +2434,7 @@ declare module 'bpmn-elements/events' { type: string; isSubProcess: any; isTransaction: any; - broker: import("smqp").Broker; + broker: any; environment: Environment; context: ContextInstance; executionId: string | undefined; @@ -2559,7 +2547,7 @@ declare module 'bpmn-elements/eventDefinitions' { isThrowing: boolean; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; @@ -2583,15 +2571,15 @@ declare module 'bpmn-elements/eventDefinitions' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | import("smqp").Consumer | undefined; + execute(executeMessage: ElementBrokerMessage): any; - executeCatch(executeMessage: ElementBrokerMessage): import("smqp").Consumer | undefined; + executeCatch(executeMessage: ElementBrokerMessage): any; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Conditional event definition @@ -2608,7 +2596,7 @@ declare module 'bpmn-elements/eventDefinitions' { behaviour: {}; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; logger: ILogger; condition: ScriptCondition | ExpressionCondition | null; get executionId(): string; @@ -2623,7 +2611,7 @@ declare module 'bpmn-elements/eventDefinitions' { * @param err Condition evaluation error * @param result Result from evaluated condition, completes execution if truthy */ - evaluateCallback(err: Error | null, result: any): number | undefined; + evaluateCallback(err: Error | null, result: any): any; /** * Get condition * @param index Eventdefinition sequence number, used to name registered script @@ -2645,15 +2633,15 @@ declare module 'bpmn-elements/eventDefinitions' { isThrowing: boolean; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Escalation event definition @@ -2669,15 +2657,15 @@ declare module 'bpmn-elements/eventDefinitions' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Link event definition @@ -2693,15 +2681,15 @@ declare module 'bpmn-elements/eventDefinitions' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | undefined; + execute(executeMessage: ElementBrokerMessage): any; - executeCatch(executeMessage: ElementBrokerMessage): number | undefined; + executeCatch(executeMessage: ElementBrokerMessage): any; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Message event definition @@ -2717,15 +2705,15 @@ declare module 'bpmn-elements/eventDefinitions' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Signal event definition @@ -2741,15 +2729,15 @@ declare module 'bpmn-elements/eventDefinitions' { reference: EventDefinitionReference; isThrowing: boolean; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): number | void; + execute(executeMessage: ElementBrokerMessage): any; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): number | undefined; + executeThrow(executeMessage: ElementBrokerMessage): any; } /** * Terminate event definition @@ -2762,7 +2750,7 @@ declare module 'bpmn-elements/eventDefinitions' { id: string | undefined; type: string; activity: Activity; - broker: import("smqp").Broker; + broker: any; logger: ILogger; execute(executeMessage: ElementBrokerMessage): void; @@ -2782,7 +2770,7 @@ declare module 'bpmn-elements/eventDefinitions' { timeDuration: string | undefined; timeCycle: string | undefined; timeDate: string | undefined; - broker: import("smqp").Broker; + broker: any; logger: ILogger; get executionId(): string; get stopped(): boolean; @@ -2844,7 +2832,7 @@ declare module 'bpmn-elements/eventDefinitions' { type: string; isSubProcess: any; isTransaction: any; - broker: import("smqp").Broker; + broker: any; environment: Environment; context: ContextInstance; executionId: string | undefined; @@ -3026,16 +3014,13 @@ declare module 'bpmn-elements/flows' { behaviour: Record; environment: Environment; context: ContextInstance; - broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - emit: (eventName: string, content?: Record, props?: any) => void; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + broker: any; + on: (eventName: string, callback: (event: { + name: string; + } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; + once: any; + emit: any; + waitFor: any; logger: ILogger; get counters(): { messages: number; @@ -3162,7 +3147,7 @@ declare module 'bpmn-elements/flows' { type: string; isSubProcess: any; isTransaction: any; - broker: import("smqp").Broker; + broker: any; environment: Environment; context: ContextInstance; executionId: string | undefined; @@ -3275,7 +3260,7 @@ declare module 'bpmn-elements/gateways' { id: string | undefined; type: string; activity: Activity; - broker: import("smqp").Broker; + broker: any; context: ContextInstance; execute(executeMessage: ElementBrokerMessage): void; @@ -3294,7 +3279,7 @@ declare module 'bpmn-elements/gateways' { constructor(activity: Activity); id: string | undefined; type: string; - broker: import("smqp").Broker; + broker: any; execute({ content }: ElementBrokerMessage): void; } @@ -3312,7 +3297,7 @@ declare module 'bpmn-elements/gateways' { constructor(activity: Activity); id: string | undefined; type: string; - broker: import("smqp").Broker; + broker: any; execute({ content }: ElementBrokerMessage): void; } @@ -3337,13 +3322,13 @@ declare module 'bpmn-elements/gateways' { id: string | undefined; type: string; activity: Activity; - broker: import("smqp").Broker; + broker: any; inbound: Set; isConverging: boolean; get executionId(): any; execute(executeMessage: ElementBrokerMessage): void; - setup(executeMessage: any): number | undefined; + setup(executeMessage: any): any; peerMonitor: PeerMonitor | undefined; } class PeerMonitor { @@ -3378,7 +3363,7 @@ declare module 'bpmn-elements/gateways' { type: string; isSubProcess: any; isTransaction: any; - broker: import("smqp").Broker; + broker: any; environment: Environment; context: ContextInstance; executionId: string | undefined; @@ -3494,7 +3479,7 @@ declare module 'bpmn-elements/tasks' { loopCharacteristics: LoopCharacteristics; activity: Activity; - broker: import("smqp").Broker; + broker: any; environment: Environment; execute(executeMessage: ElementBrokerMessage): void; @@ -3516,7 +3501,7 @@ declare module 'bpmn-elements/tasks' { reference: any; loopCharacteristics: any; activity: Activity; - broker: import("smqp").Broker; + broker: any; execute(executeMessage: ElementBrokerMessage): void; } @@ -3558,7 +3543,7 @@ declare module 'bpmn-elements/tasks' { loopCharacteristics: any; activity: Activity; environment: Environment; - broker: import("smqp").Broker; + broker: any; execute(executeMessage: ElementBrokerMessage): void; service: any; @@ -3580,7 +3565,7 @@ declare module 'bpmn-elements/tasks' { type: string; loopCharacteristics: any; activity: Activity; - broker: import("smqp").Broker; + broker: any; execute(executeMessage: ElementBrokerMessage): void; } @@ -3602,7 +3587,7 @@ declare module 'bpmn-elements/tasks' { activity: Activity; context: ContextInstance; environment: Environment; - broker: import("smqp").Broker; + broker: any; executionId: string | undefined; get execution(): any; get executions(): any[]; @@ -3628,7 +3613,7 @@ declare module 'bpmn-elements/tasks' { id: string | undefined; type: string; loopCharacteristics: any; - broker: import("smqp").Broker; + broker: any; execute(executeMessage: ElementBrokerMessage): void; } @@ -3675,7 +3660,7 @@ declare module 'bpmn-elements/tasks' { message: ElementBrokerMessage; type: string; id: string | undefined; - broker: import("smqp").Broker; + broker: any; parentExecutionId: string | undefined; isSequential: boolean; @@ -3724,7 +3709,7 @@ declare module 'bpmn-elements/tasks' { type: string; isSubProcess: any; isTransaction: any; - broker: import("smqp").Broker; + broker: any; environment: Environment; context: ContextInstance; executionId: string | undefined; From e021756930bbcf100c90e6e2b4d2e14b6596173f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 31 May 2026 08:49:37 +0200 Subject: [PATCH 18/31] drop sub module bundling files --- scripts/build-types.js | 182 ++- types/bundle-eventDefinitions.d.ts | 1 - types/bundle-events.d.ts | 1 - types/bundle-flows.d.ts | 1 - types/bundle-gateways.d.ts | 1 - types/bundle-tasks.d.ts | 1 - types/bundle.d.ts | 45 +- types/index.d.ts | 1705 +++++----------------------- 8 files changed, 454 insertions(+), 1483 deletions(-) delete mode 100644 types/bundle-eventDefinitions.d.ts delete mode 100644 types/bundle-events.d.ts delete mode 100644 types/bundle-flows.d.ts delete mode 100644 types/bundle-gateways.d.ts delete mode 100644 types/bundle-tasks.d.ts diff --git a/scripts/build-types.js b/scripts/build-types.js index 8d7fae32..3364a6ce 100644 --- a/scripts/build-types.js +++ b/scripts/build-types.js @@ -1,25 +1,46 @@ import { readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, resolve as resolvePath } from 'node:path'; import ts from 'typescript'; import MagicString from 'magic-string'; import { createBundle } from 'dts-buddy'; const output = 'types/index.d.ts'; +const repoRoot = resolvePath(dirname(fileURLToPath(import.meta.url)), '..'); + +// Submodules emitted as trivial re-export blocks from the root 'bpmn-elements' +// module. Every name in the source index must already be re-exported by +// `types/bundle.d.ts`. +const reexportSubmodules = [ + { name: 'events', source: 'src/events/index.js' }, + { name: 'eventDefinitions', source: 'src/eventDefinitions/index.js' }, + { name: 'flows', source: 'src/flows/index.js' }, + { name: 'gateways', source: 'src/gateways/index.js' }, + { name: 'tasks', source: 'src/tasks/index.js' }, +]; + +// dts-buddy collapses multiple `export X as Y` aliases of the same source export +// to a single name (the last in source order). We keep the canonical name in +// `bundle.d.ts` and inject the lost BPMN-spec aliases back into the root module +// after the bundle is emitted, so consumers can still +// `import { SendTask } from 'bpmn-elements'`. +const rootAliases = { + ServiceTask: ['BusinessRuleTask', 'SendTask'], + SignalTask: ['ManualTask', 'UserTask'], + SubProcess: ['AdHocSubProcess'], +}; // Point dts-buddy at hand-written bundle entries that re-export the runtime -// classes from `src/*.js` once each plus the shared interfaces from -// `types/interfaces.d.ts`. This gives a single source of truth per name -// (no `_1` aliases) and avoids cross-sub-module duplication. +// classes from `src/*.js`. The root entry carries every public name so the +// submodule re-export blocks (appended below) can simply forward to it. +// `bpmn-elements/errors` keeps its own dts-buddy entry because its `BpmnError` +// is a JS Error subclass — distinct from the root's `BpmnError` activity element. createBundle({ project: 'tsconfig.json', output, modules: { 'bpmn-elements': 'types/bundle.d.ts', 'bpmn-elements/errors': 'types/bundle-errors.d.ts', - 'bpmn-elements/events': 'types/bundle-events.d.ts', - 'bpmn-elements/eventDefinitions': 'types/bundle-eventDefinitions.d.ts', - 'bpmn-elements/flows': 'types/bundle-flows.d.ts', - 'bpmn-elements/gateways': 'types/bundle-gateways.d.ts', - 'bpmn-elements/tasks': 'types/bundle-tasks.d.ts', }, }) .then(() => { @@ -35,11 +56,21 @@ createBundle({ // or `private` so they don't leak into the public bundle. bundle = stripClassMembers(bundle); - // dts-buddy emits a self-contained type tree per module, so types exported from - // the root (`bpmn-elements`) get re-declared inside every sub-module that references - // them. Strip those redeclarations and `import type` from the root instead. + // The errors module redeclares ActivityError / RunError that already live in the + // root bundle. Hoist them so the emitted block re-imports from 'bpmn-elements'. bundle = hoistSharedTypes(bundle); + // Restore BPMN-spec aliases that dts-buddy collapsed away (see `rootAliases`). + bundle = injectRootAliases(bundle, rootAliases); + + // Append `declare module 'bpmn-elements/' { export { ... } from 'bpmn-elements' }` + // for every submodule whose surface is a pure re-export of the root. + bundle = bundle.replace(/\s*$/, '\n'); + for (const sub of reexportSubmodules) { + const names = collectExportedNames(resolvePath(repoRoot, sub.source)); + bundle += `\ndeclare module 'bpmn-elements/${sub.name}' {\n\texport { ${names.join(', ')} } from 'bpmn-elements';\n}\n`; + } + // The declaration map dts-buddy emits is stale after our rewrites — drop it // and remove the sourceMappingURL comment. bundle = bundle.replace(/\n*\/\/# sourceMappingURL=.*$/m, '\n'); @@ -51,6 +82,42 @@ createBundle({ throw err; }); +/** + * Parse a JS source file and return the external names it exports, in source order. + * Handles `export { a, b as c }`, `export { a } from './x.js'`, `export class A {}`, + * and `export function A() {}`. Duplicates are de-duped. + * + * @param {string} filePath + * @returns {string[]} + */ +function collectExportedNames(filePath) { + const source = readFileSync(filePath, 'utf8'); + const ast = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, false, ts.ScriptKind.JS); + + /** @type {string[]} */ + const names = []; + const seen = new Set(); + const push = (name) => { + if (seen.has(name)) return; + seen.add(name); + names.push(name); + }; + + for (const stmt of ast.statements) { + if (ts.isExportDeclaration(stmt) && stmt.exportClause && ts.isNamedExports(stmt.exportClause)) { + for (const element of stmt.exportClause.elements) { + push(element.name.text); + } + continue; + } + if ((ts.isClassDeclaration(stmt) || ts.isFunctionDeclaration(stmt)) && hasExportModifier(stmt) && stmt.name) { + push(stmt.name.text); + } + } + + return names; +} + /** * @param {string} source * @returns {string} @@ -165,12 +232,16 @@ function hoistSharedTypes(source) { const root = modules.find((m) => /** @type {ts.StringLiteral} */ (m.name).text === 'bpmn-elements'); if (!root || !root.body || !ts.isModuleBlock(root.body)) return source; - // Collect names exported from the root module — these are the candidates for hoisting. - const rootExports = new Set(); + // Collect exported declarations from the root module, keyed by name. Submodule + // redeclarations only count as hoist candidates when the root has the *same* kind + // — `BpmnError` is a class in `bpmn-elements/errors` but a function (activity + // factory) in root, so it must not be aliased onto the root export. + /** @type {Map} */ + const rootExports = new Map(); for (const stmt of root.body.statements) { if (!hasExportModifier(stmt)) continue; const name = getDeclName(stmt); - if (name) rootExports.add(name); + if (name) rootExports.set(name, stmt.kind); } for (const mod of modules) { @@ -183,26 +254,87 @@ function hoistSharedTypes(source) { for (const stmt of mod.body.statements) { if (insertBefore === null && !ts.isImportDeclaration(stmt)) insertBefore = stmt; - // private redeclarations have no `export` modifier; sub-module's own exports stay. - if (hasExportModifier(stmt)) continue; - const name = getDeclName(stmt); - if (name && rootExports.has(name)) { - magic.remove(stmt.getFullStart(), stmt.getEnd()); - stripped.add(name); - } + if (!name) continue; + const rootKind = rootExports.get(name); + if (rootKind === undefined || rootKind !== stmt.kind) continue; + + // The declaration is redundant — strip it. If it was exported, replace with a + // `export { name } from 'bpmn-elements'` so the symbol is still re-exported. + magic.remove(stmt.getFullStart(), stmt.getEnd()); + stripped.add({ name, exported: hasExportModifier(stmt) }); } if (stripped.size === 0) continue; - const imports = [...stripped].sort(); - const importStmt = `\timport type { ${imports.join(', ')} } from 'bpmn-elements';\n`; + const imported = [...stripped] + .filter((s) => !s.exported) + .map((s) => s.name) + .sort(); + const reexported = [...stripped] + .filter((s) => s.exported) + .map((s) => s.name) + .sort(); + + // Re-exports (`export { X } from 'bpmn-elements'`) don't introduce a local + // binding — they're invisible to surviving declarations in the same module. + // Pair the re-export with a value import so the name resolves both ways. + let block = ''; + if (imported.length) block += `\timport type { ${imported.join(', ')} } from 'bpmn-elements';\n`; + if (reexported.length) { + block += `\timport { ${reexported.join(', ')} } from 'bpmn-elements';\n`; + block += `\texport { ${reexported.join(', ')} };\n`; + } + + if (block && insertBefore) { + magic.appendLeft(insertBefore.getFullStart(), `\n${block}`); + } + } + + return magic.toString(); +} + +/** + * Insert `export const Alias: typeof Canonical;` lines into the root + * 'bpmn-elements' module, for every alias whose canonical name is exported. + * + * @param {string} source + * @param {Record} aliasMap canonical name → alias names + * @returns {string} + */ +function injectRootAliases(source, aliasMap) { + const ast = ts.createSourceFile('bundle.d.ts', source, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS); + + let root = null; + for (const stmt of ast.statements) { + if (ts.isModuleDeclaration(stmt) && ts.isStringLiteral(stmt.name) && stmt.name.text === 'bpmn-elements') { + root = stmt; + break; + } + } + if (!root || !root.body || !ts.isModuleBlock(root.body)) return source; + + const exported = new Set(); + for (const stmt of root.body.statements) { + if (!hasExportModifier(stmt)) continue; + const name = getDeclName(stmt); + if (name) exported.add(name); + } - if (insertBefore) { - magic.appendLeft(insertBefore.getFullStart(), `\n${importStmt}`); + const lines = []; + for (const [canonical, aliases] of Object.entries(aliasMap)) { + if (!exported.has(canonical)) continue; + for (const alias of aliases) { + if (exported.has(alias)) continue; + lines.push(`\texport const ${alias}: typeof ${canonical};`); } } + if (lines.length === 0) return source; + const magic = new MagicString(source); + // Insert immediately before the closing brace of the root module body. + const insertAt = root.body.getEnd() - 1; + magic.appendLeft(insertAt, `${lines.join('\n')}\n`); return magic.toString(); } diff --git a/types/bundle-eventDefinitions.d.ts b/types/bundle-eventDefinitions.d.ts deleted file mode 100644 index 3e507ef0..00000000 --- a/types/bundle-eventDefinitions.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../src/eventDefinitions/index.js'; diff --git a/types/bundle-events.d.ts b/types/bundle-events.d.ts deleted file mode 100644 index dd29ff84..00000000 --- a/types/bundle-events.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../src/events/index.js'; diff --git a/types/bundle-flows.d.ts b/types/bundle-flows.d.ts deleted file mode 100644 index 4bc80561..00000000 --- a/types/bundle-flows.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../src/flows/index.js'; diff --git a/types/bundle-gateways.d.ts b/types/bundle-gateways.d.ts deleted file mode 100644 index 4d3592f3..00000000 --- a/types/bundle-gateways.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../src/gateways/index.js'; diff --git a/types/bundle-tasks.d.ts b/types/bundle-tasks.d.ts deleted file mode 100644 index 6e9124c8..00000000 --- a/types/bundle-tasks.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../src/tasks/index.js'; diff --git a/types/bundle.d.ts b/types/bundle.d.ts index 87c88b9b..9dcd2c13 100644 --- a/types/bundle.d.ts +++ b/types/bundle.d.ts @@ -1,6 +1,10 @@ // Hand-written entry for dts-buddy. Re-exports the runtime classes once each // and the shared interfaces in one place so the emitted bundle has a single // declaration per name (no `_1` aliases, no per-module duplicates). +// +// Submodule type entries (`bpmn-elements/events`, `…/tasks`, etc.) are +// emitted as trivial re-export blocks by `scripts/build-types.js`, so every +// public name needs a home here. export * from './interfaces.js'; export { Activity } from '../src/activity/Activity.js'; @@ -29,21 +33,52 @@ export { Signal } from '../src/activity/Signal.js'; export { StandardLoopCharacteristics } from '../src/tasks/StandardLoopCharacteristics.js'; export { Association, MessageFlow, SequenceFlow } from '../src/flows/index.js'; -export { BoundaryEvent, EndEvent, IntermediateCatchEvent, IntermediateThrowEvent, StartEvent } from '../src/events/index.js'; -export { EventBasedGateway, ExclusiveGateway, InclusiveGateway, ParallelGateway } from '../src/gateways/index.js'; +export { + BoundaryEvent, + BoundaryEventBehaviour, + EndEvent, + EndEventBehaviour, + IntermediateCatchEvent, + IntermediateCatchEventBehaviour, + IntermediateThrowEvent, + IntermediateThrowEventBehaviour, + StartEvent, + StartEventBehaviour, +} from '../src/events/index.js'; +export { + EventBasedGateway, + EventBasedGatewayBehaviour, + ExclusiveGateway, + ExclusiveGatewayBehaviour, + InclusiveGateway, + InclusiveGatewayBehaviour, + ParallelGateway, + ParallelGatewayBehaviour, +} from '../src/gateways/index.js'; +// dts-buddy collapses multi-aliased exports to a single name (the last in source +// order), so the canonical name must come *after* its aliases — otherwise the +// alias wins and the root module loses the canonical name that the +// `bpmn-elements/tasks` re-export depends on. export { CallActivity, + CallActivityBehaviour, ReceiveTask, - ServiceTask, + ReceiveTaskBehaviour, ServiceTask as BusinessRuleTask, ServiceTask as SendTask, + ServiceTask, + ServiceTaskBehaviour, ScriptTask, - SignalTask, + ScriptTaskBehaviour, SignalTask as ManualTask, SignalTask as UserTask, - SubProcess, + SignalTask, + SignalTaskBehaviour, SubProcess as AdHocSubProcess, + SubProcess, + SubProcessBehaviour, Task, + TaskBehaviour, Transaction, } from '../src/tasks/index.js'; export { diff --git a/types/index.d.ts b/types/index.d.ts index d569a80c..5cbf666e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1884,654 +1884,362 @@ declare module 'bpmn-elements' { * */ export function BoundaryEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * End event - * */ - export function EndEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Intermediate catch event - * */ - export function IntermediateCatchEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Intermediate throw event - * */ - export function IntermediateThrowEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Start event - * */ - export function StartEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Event based gateway - * */ - export function EventBasedGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Exclusive gateway - * */ - export function ExclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Inclusive gateway - * */ - export function InclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Parallel gateway + * Boundary event behaviour * */ - export class ParallelGateway { + export class BoundaryEventBehaviour { /** - * Parallel gateway + * Boundary event behaviour * */ - constructor(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance); + constructor(activity: Activity); id: string | undefined; + type: string; + attachedTo: Activity | null; + activity: Activity; + environment: Environment; + broker: any; + get executionId(): string | undefined; + get cancelActivity(): unknown; + + execute(executeMessage: ElementBrokerMessage): void; } /** - * Call activity - * */ - export function CallActivity(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Receive task - * */ - export function ReceiveTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Script task - * */ - export function ScriptTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Service task - * */ - export function SendTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Signal task - * */ - export function UserTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Sub process + * End event * */ - export function AdHocSubProcess(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export function EndEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Task + * End event behaviour * */ - export function Task(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export class EndEventBehaviour { + /** + * End event behaviour + * */ + constructor(activity: Activity); + id: string | undefined; + type: string; + broker: any; + + execute(executeMessage: ElementBrokerMessage): void; + } /** - * Transaction + * Intermediate catch event * */ - export function Transaction(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export function IntermediateCatchEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Cancel event definition + * Intermediate catch event behaviour * */ - export class CancelEventDefinition { + export class IntermediateCatchEventBehaviour { /** - * Cancel event definition + * Intermediate catch event behaviour * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + constructor(activity: Activity); id: string | undefined; - type: string | undefined; - - reference: EventDefinitionReference; - isThrowing: boolean; - activity: Activity; - environment: Environment; + type: string; broker: any; - logger: ILogger; - get executionId(): string; execute(executeMessage: ElementBrokerMessage): void; - - executeCatch(executeMessage: ElementBrokerMessage): void; - - executeThrow(executeMessage: ElementBrokerMessage): void; } /** - * Compensate event definition + * Intermediate throw event * */ - export class CompensateEventDefinition { + export function IntermediateThrowEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Intermediate throw event behaviour + * */ + export class IntermediateThrowEventBehaviour { /** - * Compensate event definition + * Intermediate throw event behaviour * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition, context: ContextInstance); + constructor(activity: Activity); id: string | undefined; - type: string | undefined; - - reference: EventDefinitionReference; - isThrowing: boolean; - activity: Activity; + type: string; broker: any; - logger: ILogger; - get executionId(): string; - - execute(executeMessage: ElementBrokerMessage): any; - - executeCatch(executeMessage: ElementBrokerMessage): any; - executeThrow(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): void; } /** - * Conditional event definition - * @param index event definition index - */ - export class ConditionalEventDefinition { + * Start event + * */ + export function StartEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Start event behaviour + * */ + export class StartEventBehaviour { /** - * Conditional event definition - * @param index event definition index - */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition, _context: ContextInstance, index: number); + * Start event behaviour + * */ + constructor(activity: Activity); id: string | undefined; type: string; - behaviour: {}; activity: Activity; - environment: Environment; broker: any; - logger: ILogger; - condition: ScriptCondition | ExpressionCondition | null; - get executionId(): string; + get executionId(): string | undefined; execute(executeMessage: ElementBrokerMessage): void; - /** - * Evaluate condition - * */ - evaluate(message: ElementBrokerMessage, callback: CallableFunction): any; - /** - * Handle evaluate result or error - * @param err Condition evaluation error - * @param result Result from evaluated condition, completes execution if truthy - */ - evaluateCallback(err: Error | null, result: any): any; - /** - * Get condition - * @param index Eventdefinition sequence number, used to name registered script - * */ - getCondition(index: number): ExpressionCondition | ScriptCondition | null; } /** - * Error event definition + * Event based gateway * */ - export class ErrorEventDefinition { + export function EventBasedGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Event based gateway behaviour + * */ + export class EventBasedGatewayBehaviour { /** - * Error event definition + * Event based gateway behaviour * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + constructor(activity: Activity, context: ContextInstance); id: string | undefined; type: string; - - reference: EventDefinitionReference; - isThrowing: boolean; activity: Activity; - environment: Environment; broker: any; - logger: ILogger; - get executionId(): string; - - execute(executeMessage: ElementBrokerMessage): any; - - executeCatch(executeMessage: ElementBrokerMessage): void; + context: ContextInstance; - executeThrow(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): void; } /** - * Escalation event definition + * Exclusive gateway * */ - export class EscalationEventDefinition { + export function ExclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Exclusive gateway behaviour + * */ + export class ExclusiveGatewayBehaviour { /** - * Escalation event definition + * Exclusive gateway behaviour * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + constructor(activity: Activity); id: string | undefined; - type: string | undefined; - - reference: EventDefinitionReference; - isThrowing: boolean; - activity: Activity; + type: string; broker: any; - logger: ILogger; - get executionId(): string; - - execute(executeMessage: ElementBrokerMessage): any; - - executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): any; + execute({ content }: ElementBrokerMessage): void; } /** - * Link event definition + * Inclusive gateway * */ - export class LinkEventDefinition { + export function InclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + /** + * Inclusive gateway behaviour + * */ + export class InclusiveGatewayBehaviour { /** - * Link event definition + * Inclusive gateway behaviour * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + constructor(activity: Activity); id: string | undefined; type: string; - - reference: EventDefinitionReference; - isThrowing: boolean; - activity: Activity; broker: any; - logger: ILogger; - get executionId(): string; - - execute(executeMessage: ElementBrokerMessage): any; - - executeCatch(executeMessage: ElementBrokerMessage): any; - executeThrow(executeMessage: ElementBrokerMessage): any; + execute({ content }: ElementBrokerMessage): void; } /** - * Message event definition + * Parallel gateway * */ - export class MessageEventDefinition { + export class ParallelGateway { /** - * Message event definition + * Parallel gateway * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + constructor(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance); id: string | undefined; - type: string; - - reference: EventDefinitionReference; - isThrowing: boolean; - activity: Activity; - broker: any; - logger: ILogger; - get executionId(): string; - - execute(executeMessage: ElementBrokerMessage): any; - - executeCatch(executeMessage: ElementBrokerMessage): void; - - executeThrow(executeMessage: ElementBrokerMessage): any; - } - /** - * Signal event definition - * */ - export class SignalEventDefinition { - /** - * Signal event definition - * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); - id: string | undefined; - type: string | undefined; - - reference: EventDefinitionReference; - isThrowing: boolean; - activity: Activity; - broker: any; - logger: ILogger; - get executionId(): string; - - execute(executeMessage: ElementBrokerMessage): any; - - executeCatch(executeMessage: ElementBrokerMessage): void; - - executeThrow(executeMessage: ElementBrokerMessage): any; } /** - * Terminate event definition + * Parallel gateway behaviour * */ - export class TerminateEventDefinition { + export class ParallelGatewayBehaviour { /** - * Terminate event definition + * Parallel gateway behaviour * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); + constructor(activity: Activity); id: string | undefined; type: string; activity: Activity; broker: any; - logger: ILogger; + inbound: Set; + isConverging: boolean; + get executionId(): any; execute(executeMessage: ElementBrokerMessage): void; + setup(executeMessage: any): any; + peerMonitor: PeerMonitor | undefined; } - /** - * Timer event definition - * */ - export class TimerEventDefinition { - /** - * Timer event definition - * */ - constructor(activity: Activity, eventDefinition: import("moddle-context-serializer").EventDefinition); - type: string; - activity: Activity; - environment: Environment; - eventDefinition: import("moddle-context-serializer").EventDefinition; - timeDuration: string | undefined; - timeCycle: string | undefined; - timeDate: string | undefined; + class PeerMonitor { + constructor(activity: any, peers: any, targets: any); + activity: any; + id: any; broker: any; - logger: ILogger; - get executionId(): string; - get stopped(): boolean; - get timer(): Timer | null; - - execute(executeMessage: ElementBrokerMessage): void; - startedAt: Date | undefined; + running: Map; + index: number; + discarded: number; + watching: Map; + peers: any; + targets: any; + touched: Set; + inbound: any[]; + get isRunning(): boolean; + execute(executeMessage: any): number; + monitor(peerActivity: any): void; stop(): void; - /** - * Parse timer - * */ - parse(timerType: string, value: string): { - expireAt: Date | undefined; - repeat: number | undefined; - delay: number | undefined; - }; } /** - * Script condition + * Call activity * */ - class ScriptCondition { - /** - * Script condition - * */ - constructor(owner: ElementBase, script: any, language: string); - type: string; - language: string; - /** - * Execute - * */ - execute(message: any, callback: CallableFunction): any; - } + export function CallActivity(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Expression condition + * Call activity behaviour * */ - class ExpressionCondition { - /** - * Expression condition - * */ - constructor(owner: ElementBase, expression: string); - type: string; - expression: string; + export class CallActivityBehaviour { /** - * Execute + * Call activity behaviour * */ - execute(message: ElementBrokerMessage, callback: CallableFunction): any; - } - - export { Consumer, MessageFields, MessageProperties, SerializableContext, SerializableElement }; -} - -declare module 'bpmn-elements/errors' { - import type { MessageEnvelope } from 'smqp'; - import type { ElementBrokerMessage, ElementMessageContent, ElementParent } from 'bpmn-elements'; - - /** - * Get an Error from an error message. - * */ - export function makeErrorFromMessage(errorMessage: ElementBrokerMessage): Error | ActivityError | RunError | BpmnError; - export class ActivityError extends Error { - - constructor(description: string, sourceMessage?: ElementBrokerMessage, inner?: Error | { - name?: string; - code?: string | number; - }); - - type: string; - - description: string; - - source: Pick | undefined; - - inner: Error | { - name?: string; - code?: string | number; - } | undefined; - - code: string | number | undefined; - } - export class RunError extends ActivityError { - } - export class BpmnError extends Error { - - constructor(description: string, behaviour?: { - id?: string; - name?: string; - errorCode?: string | number; - code?: string; - }, sourceMessage?: ElementBrokerMessage); - + constructor(activity: Activity); + id: string | undefined; type: string; + calledElement: any; - description: string; - - code: string | undefined; - - id: string | undefined; + loopCharacteristics: MultiInstanceLoopCharacteristics; + activity: Activity; + broker: any; + environment: Environment; - source: Pick | undefined; + execute(executeMessage: ElementBrokerMessage): void; } - - export {}; -} - -declare module 'bpmn-elements/events' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - /** - * Boundary event + * Receive task * */ - export function BoundaryEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export function ReceiveTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Boundary event behaviour + * Receive task behaviour * */ - export class BoundaryEventBehaviour { + export class ReceiveTaskBehaviour { /** - * Boundary event behaviour + * Receive task behaviour * */ constructor(activity: Activity); id: string | undefined; type: string; - attachedTo: Activity | null; + reference: any; + loopCharacteristics: any; activity: Activity; - environment: Environment; broker: any; - get executionId(): string | undefined; - get cancelActivity(): unknown; execute(executeMessage: ElementBrokerMessage): void; } /** - * End event + * Script task * */ - export function EndEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export function ScriptTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * End event behaviour + * Script task behaviour * */ - export class EndEventBehaviour { + export class ScriptTaskBehaviour { /** - * End event behaviour + * Script task behaviour * */ constructor(activity: Activity); id: string | undefined; type: string; - broker: any; + scriptFormat: any; + loopCharacteristics: any; + activity: Activity; + environment: Environment; execute(executeMessage: ElementBrokerMessage): void; } /** - * Intermediate catch event + * Service task * */ - export function IntermediateCatchEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export function ServiceTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Intermediate catch event behaviour + * Service task behaviour * */ - export class IntermediateCatchEventBehaviour { + export class ServiceTaskBehaviour { /** - * Intermediate catch event behaviour + * Service task behaviour * */ constructor(activity: Activity); id: string | undefined; type: string; + loopCharacteristics: any; + activity: Activity; + environment: Environment; broker: any; execute(executeMessage: ElementBrokerMessage): void; + service: any; + getService(message: any): any; } /** - * Intermediate throw event + * Signal task * */ - export function IntermediateThrowEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export function SignalTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Intermediate throw event behaviour + * Signal task behaviour * */ - export class IntermediateThrowEventBehaviour { + export class SignalTaskBehaviour { /** - * Intermediate throw event behaviour + * Signal task behaviour * */ constructor(activity: Activity); id: string | undefined; type: string; + loopCharacteristics: any; + activity: Activity; broker: any; execute(executeMessage: ElementBrokerMessage): void; } /** - * Start event + * Sub process * */ - export function StartEvent(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; + export function SubProcess(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Start event behaviour + * Sub process behaviour * */ - export class StartEventBehaviour { + export class SubProcessBehaviour { /** - * Start event behaviour + * Sub process behaviour * */ - constructor(activity: Activity); + constructor(activity: Activity, context: ContextInstance); id: string | undefined; type: string; + loopCharacteristics: any; activity: Activity; + context: ContextInstance; + environment: Environment; broker: any; - get executionId(): string | undefined; + executionId: string | undefined; + get execution(): any; + get executions(): any[]; execute(executeMessage: ElementBrokerMessage): void; + getState(): any; + recover(state: any): this | undefined; + getPostponed(): any[]; + getApi(apiMessage: any): any; } /** - * Event definition execution orchestrator. Drives a sequence of event definitions for the - * activity and publishes the completed routing key when the last definition completes. - * @param completedRoutingKey Routing key to publish on completion, defaults to `execute.completed` - */ - class EventDefinitionExecution { - /** - * Event definition execution orchestrator. Drives a sequence of event definitions for the - * activity and publishes the completed routing key when the last definition completes. - * @param completedRoutingKey Routing key to publish on completion, defaults to `execute.completed` - */ - constructor(activity: Activity, eventDefinitions: EventDefinition[], completedRoutingKey?: string); - id: string | undefined; - activity: Activity; - broker: any; - eventDefinitions: EventDefinition[]; - completedRoutingKey: string; - get completed(): boolean; - get stopped(): boolean; - - execute(executeMessage: ElementBrokerMessage): void; - } + * Task + * */ + export function Task(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. + * Task behaviour * */ - class ProcessExecution { + export class TaskBehaviour { /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. + * Task behaviour * */ - constructor(parentActivity: Process | Activity, context: ContextInstance); + constructor(activity: Activity); id: string | undefined; type: string; - isSubProcess: any; - isTransaction: any; + loopCharacteristics: any; broker: any; - environment: Environment; - context: ContextInstance; - executionId: string | undefined; - /** - * Activate children and start the process execution. Resumes if the message is redelivered. - * @throws {Error} when message or executionId is missing - */ - execute(executeMessage: ElementBrokerMessage): true | void; - /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. - */ - resume(): void; - /** - * Snapshot execution state including children, flows, message flows, and associations. - * */ - getState(): ProcessExecutionState; - /** - * Restore execution state captured by getState. - * */ - recover(state?: ProcessExecutionState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * */ - shake(fromId?: string): ShakeResult; - /** - * Stop the running process execution via the api. - */ - stop(): void; - /** - * List currently postponed children as Api wrappers. - * - */ - getPostponed(filterFn?: filterPostponed): IApi[]; - /** - * Queue a discard message that propagates to all running children. - */ - discard(): void; - /** - * Queue a cancel message that propagates to all running children. - */ - cancel(): void; - /** - * Get child activities in the process scope. - * */ - getActivities(): Activity[]; - getActivityById(activityId: string): Activity; - /** - * Get sequence flows in the process scope. - * */ - getSequenceFlows(): SequenceFlow; - /** - * Get associations in the process scope. - * */ - getAssociations(): Association; - /** - * Resolve a process or child Api for the given message. - * */ - getApi(message?: ElementBrokerMessage): IApi; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; + execute(executeMessage: ElementBrokerMessage): void; } /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. + * Transaction * */ - class Formatter { - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - constructor(element: ElementBase); - id: string; - broker: import("smqp").Broker; - logger: ILogger; - /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; - } - - export {}; -} - -declare module 'bpmn-elements/eventDefinitions' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - + export function Transaction(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; /** * Cancel event definition * */ @@ -2788,6 +2496,28 @@ declare module 'bpmn-elements/eventDefinitions' { delay: number | undefined; }; } + /** + * Event definition execution orchestrator. Drives a sequence of event definitions for the + * activity and publishes the completed routing key when the last definition completes. + * @param completedRoutingKey Routing key to publish on completion, defaults to `execute.completed` + */ + class EventDefinitionExecution { + /** + * Event definition execution orchestrator. Drives a sequence of event definitions for the + * activity and publishes the completed routing key when the last definition completes. + * @param completedRoutingKey Routing key to publish on completion, defaults to `execute.completed` + */ + constructor(activity: Activity, eventDefinitions: EventDefinition[], completedRoutingKey?: string); + id: string | undefined; + activity: Activity; + broker: any; + eventDefinitions: EventDefinition[]; + completedRoutingKey: string; + get completed(): boolean; + get stopped(): boolean; + + execute(executeMessage: ElementBrokerMessage): void; + } /** * Script condition * */ @@ -2818,986 +2548,65 @@ declare module 'bpmn-elements/eventDefinitions' { * */ execute(message: ElementBrokerMessage, callback: CallableFunction): any; } + + export { Consumer, MessageFields, MessageProperties, SerializableContext, SerializableElement }; + export const BusinessRuleTask: typeof ServiceTask; + export const SendTask: typeof ServiceTask; + export const ManualTask: typeof SignalTask; + export const UserTask: typeof SignalTask; + export const AdHocSubProcess: typeof SubProcess; +} + +declare module 'bpmn-elements/errors' { + import type { MessageEnvelope } from 'smqp'; + import type { ElementBrokerMessage, ElementMessageContent, ElementParent } from 'bpmn-elements'; + import { ActivityError, RunError } from 'bpmn-elements'; + export { ActivityError, RunError }; + /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. + * Get an Error from an error message. * */ - class ProcessExecution { - /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. - * */ - constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; + export function makeErrorFromMessage(errorMessage: ElementBrokerMessage): Error | ActivityError | RunError | BpmnError; + export class BpmnError extends Error { + + constructor(description: string, behaviour?: { + id?: string; + name?: string; + errorCode?: string | number; + code?: string; + }, sourceMessage?: ElementBrokerMessage); + type: string; - isSubProcess: any; - isTransaction: any; - broker: any; - environment: Environment; - context: ContextInstance; - executionId: string | undefined; - /** - * Activate children and start the process execution. Resumes if the message is redelivered. - * @throws {Error} when message or executionId is missing - */ - execute(executeMessage: ElementBrokerMessage): true | void; - /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. - */ - resume(): void; - /** - * Snapshot execution state including children, flows, message flows, and associations. - * */ - getState(): ProcessExecutionState; - /** - * Restore execution state captured by getState. - * */ - recover(state?: ProcessExecutionState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * */ - shake(fromId?: string): ShakeResult; - /** - * Stop the running process execution via the api. - */ - stop(): void; - /** - * List currently postponed children as Api wrappers. - * - */ - getPostponed(filterFn?: filterPostponed): IApi[]; - /** - * Queue a discard message that propagates to all running children. - */ - discard(): void; - /** - * Queue a cancel message that propagates to all running children. - */ - cancel(): void; - /** - * Get child activities in the process scope. - * */ - getActivities(): Activity[]; - getActivityById(activityId: string): Activity; - /** - * Get sequence flows in the process scope. - * */ - getSequenceFlows(): SequenceFlow; - /** - * Get associations in the process scope. - * */ - getAssociations(): Association; - /** - * Resolve a process or child Api for the given message. - * */ - getApi(message?: ElementBrokerMessage): IApi; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - class Formatter { - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - constructor(element: ElementBase); - id: string; - broker: import("smqp").Broker; - logger: ILogger; - /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; - } - - export {}; -} - -declare module 'bpmn-elements/flows' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - - /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. - * */ - export class Association { - /** - * Association connecting a source and target activity. Used to drive compensation — - * activities marked `isForCompensation` subscribe to inbound association events. - * */ - constructor(associationDef: import("moddle-context-serializer").Association, { environment }: ContextInstance); - id: string | undefined; - type: string; - name: string | undefined; - parent: ElementParent; - - behaviour: Record; - sourceId: string; - targetId: string; - isAssociation: boolean; - environment: Environment; - logger: ILogger; - broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; - get counters(): { - take: number; - discard: number; - }; - /** - * Take the association and publish association.take. - * - */ - take(content?: Record): boolean; - /** - * Discard the association and publish association.discard. - * - */ - discard(content?: Record): boolean; - /** - * Snapshot association state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): AssociationState | undefined; - /** - * Restore association state captured by getState. - * */ - recover(state: AssociationState): void; - /** - * Resolve an association-scoped Api wrapper. - * */ - getApi(message?: ElementBrokerMessage): IApi; - /** - * Stop the association's broker. - */ - stop(): void; - } - /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - export class MessageFlow { - /** - * Message flow connecting a source activity (or process) to a target. Subscribes to the - * source's `end` event and publishes `message.outbound` whenever the source completes, - * carrying any message payload through to the target. - * */ - constructor(flowDef: import("moddle-context-serializer").MessageFlow, context: ContextInstance); - id: string | undefined; - type: string; - name: string | undefined; - parent: ElementParent; - source: import("moddle-context-serializer").MessageFlowEndpoint; - target: import("moddle-context-serializer").MessageFlowEndpoint; - - behaviour: Record; - environment: Environment; - context: ContextInstance; - broker: any; - on: (eventName: string, callback: (event: { - name: string; - } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; - once: any; - emit: any; - waitFor: any; - logger: ILogger; - get counters(): { - messages: number; - }; - /** - * Snapshot message-flow state. Returns undefined when broker has no state and - * `disableTrackState` is set. - * */ - getState(): MessageFlowState | undefined; - /** - * Restore message-flow state captured by getState. - * */ - recover(state: MessageFlowState): void; - /** - * Resolve a message-scoped Api wrapper. - * */ - getApi(message?: ElementBrokerMessage): IApi; - /** - * Subscribe to the source element's message and end events to bridge the message across. - */ - activate(): void; - /** - * Cancel the source element subscriptions added by activate. - */ - deactivate(): void; - } - /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - export class SequenceFlow { - /** - * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped - * events; activities subscribe to drive their inbound queue. - * */ - constructor(flowDef: import("moddle-context-serializer").SequenceFlow, { environment }: ContextInstance); - id: string | undefined; - type: string; - name: string | undefined; - parent: ElementParent; - - behaviour: Record; - sourceId: string; - targetId: string; - isDefault: boolean | undefined; - isSequenceFlow: boolean; - environment: Environment; - logger: ILogger; - broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; - emitFatal: (error: Error, content?: Record) => void; - get counters(): { - take: number; - discard: number; - looped: number; - }; - /** - * Take the flow and publish flow.take. - * - */ - take(content?: Record): boolean; - /** - * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits - * flow.looped instead when the target id is already in the sequence. - * - */ - discard(content?: Record): void; - /** - * Snapshot flow state. Returns undefined when the broker has no state and `disableTrackState` - * is set. - * */ - getState(): SequenceFlowState | undefined; - /** - * Restore flow state captured by getState. - * */ - recover(state: SequenceFlowState): void; - /** - * Resolve a Flow Api wrapper. - * */ - getApi(message?: ElementBrokerMessage): IApi; - /** - * Stop the flow's broker. - */ - stop(): void; - /** - * Walk the flow as part of a process shake. Detects loops and publishes flow.shake.loop - * when the target was already visited, otherwise flow.shake. - * */ - shake(message: ElementBrokerMessage): number | undefined; - /** - * Resolve the flow's condition (script or expression). Returns null when no condition is set. - * Emits a fatal error when the script language is missing or unsupported. - * */ - getCondition(): ISequenceFlowCondition | null; - /** - * Build a flow event message body, optionally merging override content. - * */ - createMessage(override?: Record): ElementMessageContent; - /** - * Evaluate the flow's condition for the source activity message. Default flows are always taken. - * @param fromMessage Source activity message - * @param callback Callback with truthy result if flow should be taken - */ - evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error | null, result?: boolean | unknown) => void): void; - } - /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. - * */ - class ProcessExecution { - /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. - * */ - constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; - isSubProcess: any; - isTransaction: any; - broker: any; - environment: Environment; - context: ContextInstance; - executionId: string | undefined; - /** - * Activate children and start the process execution. Resumes if the message is redelivered. - * @throws {Error} when message or executionId is missing - */ - execute(executeMessage: ElementBrokerMessage): true | void; - /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. - */ - resume(): void; - /** - * Snapshot execution state including children, flows, message flows, and associations. - * */ - getState(): ProcessExecutionState; - /** - * Restore execution state captured by getState. - * */ - recover(state?: ProcessExecutionState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * */ - shake(fromId?: string): ShakeResult; - /** - * Stop the running process execution via the api. - */ - stop(): void; - /** - * List currently postponed children as Api wrappers. - * - */ - getPostponed(filterFn?: filterPostponed): IApi[]; - /** - * Queue a discard message that propagates to all running children. - */ - discard(): void; - /** - * Queue a cancel message that propagates to all running children. - */ - cancel(): void; - /** - * Get child activities in the process scope. - * */ - getActivities(): Activity[]; - - getActivityById(activityId: string): Activity; - /** - * Get sequence flows in the process scope. - * */ - getSequenceFlows(): SequenceFlow; - /** - * Get associations in the process scope. - * */ - getAssociations(): Association; - /** - * Resolve a process or child Api for the given message. - * */ - getApi(message?: ElementBrokerMessage): IApi; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - class Formatter { - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - constructor(element: ElementBase); - id: string; - broker: import("smqp").Broker; - logger: ILogger; - /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; - } - - export {}; -} - -declare module 'bpmn-elements/gateways' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - - /** - * Event based gateway - * */ - export function EventBasedGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Event based gateway behaviour - * */ - export class EventBasedGatewayBehaviour { - /** - * Event based gateway behaviour - * */ - constructor(activity: Activity, context: ContextInstance); - id: string | undefined; - type: string; - activity: Activity; - broker: any; - context: ContextInstance; - - execute(executeMessage: ElementBrokerMessage): void; - } - /** - * Exclusive gateway - * */ - export function ExclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Exclusive gateway behaviour - * */ - export class ExclusiveGatewayBehaviour { - /** - * Exclusive gateway behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - broker: any; - - execute({ content }: ElementBrokerMessage): void; - } - /** - * Inclusive gateway - * */ - export function InclusiveGateway(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Inclusive gateway behaviour - * */ - export class InclusiveGatewayBehaviour { - /** - * Inclusive gateway behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - broker: any; - - execute({ content }: ElementBrokerMessage): void; - } - /** - * Parallel gateway - * */ - export class ParallelGateway { - /** - * Parallel gateway - * */ - constructor(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance); - id: string | undefined; - } - /** - * Parallel gateway behaviour - * */ - export class ParallelGatewayBehaviour { - /** - * Parallel gateway behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - activity: Activity; - broker: any; - inbound: Set; - isConverging: boolean; - get executionId(): any; - - execute(executeMessage: ElementBrokerMessage): void; - setup(executeMessage: any): any; - peerMonitor: PeerMonitor | undefined; - } - class PeerMonitor { - constructor(activity: any, peers: any, targets: any); - activity: any; - id: any; - broker: any; - running: Map; - index: number; - discarded: number; - watching: Map; - peers: any; - targets: any; - touched: Set; - inbound: any[]; - get isRunning(): boolean; - execute(executeMessage: any): number; - monitor(peerActivity: any): void; - stop(): void; - } - /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. - * */ - class ProcessExecution { - /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. - * */ - constructor(parentActivity: Process | Activity, context: ContextInstance); - id: string | undefined; - type: string; - isSubProcess: any; - isTransaction: any; - broker: any; - environment: Environment; - context: ContextInstance; - executionId: string | undefined; - /** - * Activate children and start the process execution. Resumes if the message is redelivered. - * @throws {Error} when message or executionId is missing - */ - execute(executeMessage: ElementBrokerMessage): true | void; - /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. - */ - resume(): void; - /** - * Snapshot execution state including children, flows, message flows, and associations. - * */ - getState(): ProcessExecutionState; - /** - * Restore execution state captured by getState. - * */ - recover(state?: ProcessExecutionState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * */ - shake(fromId?: string): ShakeResult; - /** - * Stop the running process execution via the api. - */ - stop(): void; - /** - * List currently postponed children as Api wrappers. - * - */ - getPostponed(filterFn?: filterPostponed): IApi[]; - /** - * Queue a discard message that propagates to all running children. - */ - discard(): void; - /** - * Queue a cancel message that propagates to all running children. - */ - cancel(): void; - /** - * Get child activities in the process scope. - * */ - getActivities(): Activity[]; - - getActivityById(activityId: string): Activity; - /** - * Get sequence flows in the process scope. - * */ - getSequenceFlows(): SequenceFlow; - /** - * Get associations in the process scope. - * */ - getAssociations(): Association; - /** - * Resolve a process or child Api for the given message. - * */ - getApi(message?: ElementBrokerMessage): IApi; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - class Formatter { - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - constructor(element: ElementBase); - id: string; - broker: import("smqp").Broker; - logger: ILogger; - /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; - } - - export {}; -} - -declare module 'bpmn-elements/tasks' { - import type { Broker, BrokerState, MessageEnvelope } from 'smqp'; - import type { SerializableElement } from 'moddle-context-serializer'; - import type { Activity, ActivityError, ActivityExecution, ActivityExecutionState, ActivityRunStatus, ActivityState, Association, AssociationState, ContextInstance, ElementBase, ElementBroker, ElementBrokerMessage, ElementMessageContent, ElementParent, ElementState, Environment, EnvironmentOptions, EnvironmentSettings, EnvironmentState, EventDefinition, EventDefinitionReference, ExecutionScope, Extension, IActivityBehaviour, IApi, IExpressions, IExtension, IExtensions, IExtensionsMapper, IIOData, ILogger, IScripts, ISequenceFlowCondition, ITimers, Lane, LoggerFactory, MessageFlow, MessageFlowState, Process, ProcessExecutionState, ProcessState, RegisteredTimer, Script, SequenceFlow, SequenceFlowState, ShakeResult, ShakeSequenceItem, ShakenSequence, Timer, completedCounters, filterPostponed, signalMessage, startActivityFilterOptions, wrappedClearTimeout, wrappedSetTimeout } from 'bpmn-elements'; - - /** - * Call activity - * */ - export function CallActivity(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Call activity behaviour - * */ - export class CallActivityBehaviour { - /** - * Call activity behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - calledElement: any; - - loopCharacteristics: LoopCharacteristics; - activity: Activity; - broker: any; - environment: Environment; - - execute(executeMessage: ElementBrokerMessage): void; - } - /** - * Receive task - * */ - export function ReceiveTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Receive task behaviour - * */ - export class ReceiveTaskBehaviour { - /** - * Receive task behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - reference: any; - loopCharacteristics: any; - activity: Activity; - broker: any; - - execute(executeMessage: ElementBrokerMessage): void; - } - /** - * Script task - * */ - export function ScriptTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Script task behaviour - * */ - export class ScriptTaskBehaviour { - /** - * Script task behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - scriptFormat: any; - loopCharacteristics: any; - activity: Activity; - environment: Environment; - - execute(executeMessage: ElementBrokerMessage): void; - } - /** - * Service task - * */ - export function ServiceTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Service task behaviour - * */ - export class ServiceTaskBehaviour { - /** - * Service task behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - loopCharacteristics: any; - activity: Activity; - environment: Environment; - broker: any; - - execute(executeMessage: ElementBrokerMessage): void; - service: any; - getService(message: any): any; - } - /** - * Signal task - * */ - export function SignalTask(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Signal task behaviour - * */ - export class SignalTaskBehaviour { - /** - * Signal task behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - loopCharacteristics: any; - activity: Activity; - broker: any; - - execute(executeMessage: ElementBrokerMessage): void; - } - /** - * Sub process - * */ - export function SubProcess(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Sub process behaviour - * */ - export class SubProcessBehaviour { - /** - * Sub process behaviour - * */ - constructor(activity: Activity, context: ContextInstance); - id: string | undefined; - type: string; - loopCharacteristics: any; - activity: Activity; - context: ContextInstance; - environment: Environment; - broker: any; - executionId: string | undefined; - get execution(): any; - get executions(): any[]; - - execute(executeMessage: ElementBrokerMessage): void; - getState(): any; - recover(state: any): this | undefined; - getPostponed(): any[]; - getApi(apiMessage: any): any; - } - /** - * Task - * */ - export function Task(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Task behaviour - * */ - export class TaskBehaviour { - /** - * Task behaviour - * */ - constructor(activity: Activity); - id: string | undefined; - type: string; - loopCharacteristics: any; - broker: any; - - execute(executeMessage: ElementBrokerMessage): void; - } - /** - * Transaction - * */ - export function Transaction(activityDef: import("moddle-context-serializer").Activity, context: ContextInstance): Activity; - /** - * Loop characteristics - * */ - class LoopCharacteristics { - /** - * Loop characteristics - * */ - constructor(activity: Activity, loopCharacteristics: import("moddle-context-serializer").SerializableElement); - activity: Activity; - loopCharacteristics: import("moddle-context-serializer").SerializableElement>; - type: string; - - isSequential: boolean; - - collection: string | undefined; - - loopCardinality: number | undefined; - loopType: string | undefined; - - elementVariable: string | undefined; - - characteristics: Characteristics; - execution: any; - - execute(executeMessage: ElementBrokerMessage): void; - } - /** - * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). - * */ - class Characteristics { - /** - * Per-execution snapshot of resolved loop characteristics (cardinality, collection, conditions). - * */ - constructor(activity: Activity, loopCharacteristics: import("moddle-context-serializer").SerializableElement, executeMessage: ElementBrokerMessage); - activity: Activity; - behaviour: Record; - message: ElementBrokerMessage; - type: string; - id: string | undefined; - broker: any; - parentExecutionId: string | undefined; - - isSequential: boolean; - output: any; - parent: ElementParent; - loopCardinality: number | undefined; - startCondition: string | undefined; - completionCondition: string; - collection: any[] | undefined; - - elementVariable: string; - cardinality: number | undefined; - logger: ILogger; - batchSize: number; - - getContent(): ElementMessageContent; - - next(index: number): ElementMessageContent; - /** - * @returns cardinality - */ - getCardinality(collection?: any): number | undefined; - - getCollection(): any[] | undefined; - - isStartConditionMet(message: ElementBrokerMessage): any; - - isCompletionConditionMet(message: ElementBrokerMessage): any; + description: string; - complete(content: ElementMessageContent, allDiscarded?: boolean): void; + code: string | undefined; - subscribe(onIterationCompleteMessage: ElementBrokerMessage): void; - stop(): void; - } - /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. - * */ - class ProcessExecution { - /** - * Drives the execution of a single process or sub-process: activates children, routes activity - * events, and rolls completion up to the owning Process or sub-process Activity. - * */ - constructor(parentActivity: Process | Activity, context: ContextInstance); id: string | undefined; - type: string; - isSubProcess: any; - isTransaction: any; - broker: any; - environment: Environment; - context: ContextInstance; - executionId: string | undefined; - /** - * Activate children and start the process execution. Resumes if the message is redelivered. - * @throws {Error} when message or executionId is missing - */ - execute(executeMessage: ElementBrokerMessage): true | void; - /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. - */ - resume(): void; - /** - * Snapshot execution state including children, flows, message flows, and associations. - * */ - getState(): ProcessExecutionState; - /** - * Restore execution state captured by getState. - * */ - recover(state?: ProcessExecutionState): this; - /** - * Walk activity graph from the given start id, or every start activity when omitted. - * */ - shake(fromId?: string): ShakeResult; - /** - * Stop the running process execution via the api. - */ - stop(): void; - /** - * List currently postponed children as Api wrappers. - * - */ - getPostponed(filterFn?: filterPostponed): IApi[]; - /** - * Queue a discard message that propagates to all running children. - */ - discard(): void; - /** - * Queue a cancel message that propagates to all running children. - */ - cancel(): void; - /** - * Get child activities in the process scope. - * */ - getActivities(): Activity[]; - getActivityById(activityId: string): Activity; - /** - * Get sequence flows in the process scope. - * */ - getSequenceFlows(): SequenceFlow; - /** - * Get associations in the process scope. - * */ - getAssociations(): Association; - /** - * Resolve a process or child Api for the given message. - * */ - getApi(message?: ElementBrokerMessage): IApi; - get stopped(): boolean; - get completed(): boolean; - get status(): string; - get postponedCount(): number; - get isRunning(): boolean; - get activityStatus(): string; - } - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - class Formatter { - /** - * Enriches an element run message via async format start/end messages on the `format` exchange - * before the run message is continued. Handlers publish enrichment by responding to a start - * message with a matching end (or error) routing key. - * */ - constructor(element: ElementBase); - id: string; - broker: import("smqp").Broker; - logger: ILogger; - /** - * Format the given run message. Callback fires with `(err, content, formatted)` once - * formatting completes; `formatted` is true when content was actually enriched. - * */ - format(message: ElementBrokerMessage, callback: (err: Error | null, content?: ElementMessageContent, formatted?: boolean) => void): void; + source: Pick | undefined; } export {}; } + + +declare module 'bpmn-elements/events' { + export { BoundaryEvent, BoundaryEventBehaviour, EndEvent, EndEventBehaviour, IntermediateCatchEvent, IntermediateCatchEventBehaviour, IntermediateThrowEvent, IntermediateThrowEventBehaviour, StartEvent, StartEventBehaviour } from 'bpmn-elements'; +} + +declare module 'bpmn-elements/eventDefinitions' { + export { CancelEventDefinition, CompensateEventDefinition, ConditionalEventDefinition, ErrorEventDefinition, EscalationEventDefinition, LinkEventDefinition, MessageEventDefinition, SignalEventDefinition, TerminateEventDefinition, TimerEventDefinition } from 'bpmn-elements'; +} + +declare module 'bpmn-elements/flows' { + export { Association, MessageFlow, SequenceFlow } from 'bpmn-elements'; +} + +declare module 'bpmn-elements/gateways' { + export { EventBasedGateway, EventBasedGatewayBehaviour, ExclusiveGateway, ExclusiveGatewayBehaviour, InclusiveGateway, InclusiveGatewayBehaviour, ParallelGateway, ParallelGatewayBehaviour } from 'bpmn-elements'; +} + +declare module 'bpmn-elements/tasks' { + export { CallActivity, CallActivityBehaviour, ReceiveTask, ReceiveTaskBehaviour, ScriptTask, ScriptTaskBehaviour, ServiceTask, ServiceTaskBehaviour, SignalTask, SignalTaskBehaviour, SubProcess, SubProcessBehaviour, Task, TaskBehaviour, Transaction } from 'bpmn-elements'; +} From cb08d5b064ad51f1642cc35700006d1d1979be5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 31 May 2026 09:33:55 +0200 Subject: [PATCH 19/31] definition must be instantiated with new --- CHANGELOG.md | 31 +- dist/EventBroker.js | 29 +- dist/Timers.js | 3 +- dist/activity/Activity.js | 4 +- dist/definition/Definition.js | 2 - .../eventDefinitions/CancelEventDefinition.js | 2 +- .../CompensateEventDefinition.js | 2 +- .../ConditionalEventDefinition.js | 2 +- dist/eventDefinitions/ErrorEventDefinition.js | 2 +- .../EscalationEventDefinition.js | 2 +- dist/eventDefinitions/LinkEventDefinition.js | 2 +- .../MessageEventDefinition.js | 2 +- .../eventDefinitions/SignalEventDefinition.js | 2 +- dist/eventDefinitions/TimerEventDefinition.js | 3 +- dist/flows/SequenceFlow.js | 2 +- dist/tasks/CallActivity.js | 2 +- dist/tasks/ReceiveTask.js | 8 +- dist/tasks/ScriptTask.js | 2 + dist/tasks/ServiceTask.js | 1 + dist/tasks/SignalTask.js | 1 + dist/tasks/SubProcess.js | 1 + dist/tasks/Task.js | 1 + src/EventBroker.js | 28 +- src/Timers.js | 3 +- src/activity/Activity.js | 4 +- src/definition/Definition.js | 2 - src/eventDefinitions/CancelEventDefinition.js | 2 +- .../CompensateEventDefinition.js | 2 +- .../ConditionalEventDefinition.js | 2 +- src/eventDefinitions/ErrorEventDefinition.js | 2 +- .../EscalationEventDefinition.js | 2 +- src/eventDefinitions/LinkEventDefinition.js | 2 +- .../MessageEventDefinition.js | 2 +- src/eventDefinitions/SignalEventDefinition.js | 2 +- src/eventDefinitions/TimerEventDefinition.js | 3 +- src/flows/SequenceFlow.js | 2 +- src/tasks/CallActivity.js | 2 +- src/tasks/ReceiveTask.js | 8 +- src/tasks/ScriptTask.js | 1 + src/tasks/ServiceTask.js | 1 + src/tasks/SignalTask.js | 1 + src/tasks/SubProcess.js | 1 + src/tasks/Task.js | 1 + test/definition/Definition-test.js | 10 - test/feature/errors-feature.js | 2 +- test/feature/escalation-feature.js | 2 +- types/index.d.ts | 492 +++++++++--------- types/interfaces.d.ts | 195 ++++--- 48 files changed, 430 insertions(+), 450 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2897e6bb..a6d7f5d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,36 +1,27 @@ # Changelog -## Unreleased - -- fix `Activity.recover()` to return the activity when called without state -- expose throwable error classes via new `bpmn-elements/errors` subpath: `import { ActivityError, BpmnError, RunError } from 'bpmn-elements/errors'` (the `BpmnError` activity factory remains the named export of `bpmn-elements`) -- drop default exports across all implementation files in favour of named exports — internal-facing churn only, the package's public exports map (`bpmn-elements`, `bpmn-elements/events`, `…/eventDefinitions`, `…/flows`, `…/gateways`, `…/tasks`) is unchanged -- replace hand-rolled class declarations in `types/types.d.ts` with re-exports from the implementation files — the type definitions track the JSDoc-driven source rather than living in parallel -- strip the duplicate `export function Foo(...)` declarations that tsc emits alongside `export class Foo` for constructor-function patterns — the bundled `Definition`, `Activity`, `Process`, etc. are now plain class declarations that merge cleanly with the property augmentations -- strip internal class members (`@internal`, `private`, and underscore-prefixed names) from the bundled `.d.ts` — dts-buddy's built-in `stripInternal` only handles `PropertySignature` (interface members), so the build script now walks the bundle AST and removes matching `MethodDeclaration`/`PropertyDeclaration`/accessor nodes - -### Types - -- bundle `types/index.d.ts` with [dts-buddy](https://github.com/Rich-Harris/dts-buddy); types are generated from JSDoc and source-mapped to `src/*.js` -- migrate runtime types to JSDoc, covering `Activity`, `ActivityExecution`, `Context`, `Process`, `ProcessExecution`, `Definition`, `DefinitionExecution`, `Environment`, `Api`, `EventBroker`, `MessageFormatter`, `SequenceFlow`, `MessageFlow`, `Association`, and `Lane` -- separate hand-written contracts into `types/interfaces.d.ts` -- update `smqp` type imports for `smqp@12` - -## v18.0.0 - 2026-01-14 +## v18.0.0 - 2026-05-31 Refactor parallel converging and forking gateways. ### Breaking -- parallel gateways now enters execution as soon as first nbound sequence flow is touched +- parallel gateways now enter execution as soon as the first inbound sequence flow is touched - shake sequence has changed - IntermediateCatchEvent cannot be used as a starting element, or it can but will not be started by default +- `Definition` must be called with `new` ### Additions -- fix link event definition shaking +- expose throwable error classes via new `bpmn-elements/errors` subpath: `import { ActivityError, BpmnError, RunError } from 'bpmn-elements/errors'` - activity readonly property `isParallelJoin` indicating a parallel converging gateway -- new activity event published when parallel gateway is executed, namely `activity.converge` +- new activity event `activity.converge` published when parallel gateway is executed +- fix link event definition shaking +- fix `Activity.recover()` to return the activity when called without state + +### Types + +- runtime types are now generated from JSDoc and bundled with [dts-buddy](https://github.com/Rich-Harris/dts-buddy); status enums (`ActivityStatus`, `DefinitionStatus`, `ProcessStatus`) and `TimerType` accept both enum members and their string literals. ## v17.3.0 - 2025-12-03 diff --git a/dist/EventBroker.js b/dist/EventBroker.js index 76d139db..f37f002a 100644 --- a/dist/EventBroker.js +++ b/dist/EventBroker.js @@ -10,20 +10,10 @@ exports.MessageFlowBroker = MessageFlowBroker; exports.ProcessBroker = ProcessBroker; var _smqp = require("smqp"); var _Errors = require("./error/Errors.js"); -/** - * @typedef {object} BrokerApi Shape of the bound event helpers exposed by an EventBroker - * (and inherited by every element class that destructures from one). - * @property {(eventName: string, callback: CallableFunction, eventOptions?: { once?: boolean, [x: string]: any }) => import('smqp').Consumer} on - * @property {(eventName: string, callback: CallableFunction, eventOptions?: { [x: string]: any }) => import('smqp').Consumer} once - * @property {(eventName: string, onMessage?: (routingKey: string, message: import('#types').ElementBrokerMessage, owner: any) => boolean) => Promise} waitFor - * @property {(eventName: string, content?: Record, props?: any) => void} emit - * @property {(error: Error, content?: Record) => void} emitFatal - */ - /** * Build the broker for an activity, including run/format/execution/api exchanges and queues. * @param {import('#types').Activity} activity - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); @@ -33,7 +23,7 @@ function ActivityBroker(activity) { /** * Build the broker for a process, with an additional api-q bound to all api routing keys. * @param {import('#types').Process} owner - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); @@ -49,7 +39,7 @@ function ProcessBroker(owner) { * Build the broker for a definition. Optionally registers a custom return-message handler. * @param {import('#types').Definition} owner * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); @@ -58,7 +48,7 @@ function DefinitionBroker(owner, onBrokerReturn) { /** * Build the broker for a message flow with a durable message exchange and message-q. * @param {import('./flows/MessageFlow.js').MessageFlow} owner - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { @@ -132,23 +122,16 @@ function EventBroker(brokerOwner, options, onBrokerReturn) { const broker = this.broker = new _smqp.Broker(brokerOwner); broker.assertExchange('event', 'topic', options); broker.on('return', onBrokerReturn ? onBrokerReturn.bind(brokerOwner) : this._onBrokerReturnFn.bind(this)); - - /** @type {BrokerApi['on']} */ this.on = this.on.bind(this); - /** @type {BrokerApi['once']} */ this.once = this.once.bind(this); - /** @type {BrokerApi['waitFor']} */ this.waitFor = this.waitFor.bind(this); - /** @type {BrokerApi['emit']} */ this.emit = this.emit.bind(this); - /** @type {BrokerApi['emitFatal']} */ this.emitFatal = this.emitFatal.bind(this); } /** * Subscribe to a prefixed event. Errors are unwrapped via `makeErrorFromMessage`, * other events resolve to the owner's Api wrapper. - * @type {BrokerApi['on']} */ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { once: false @@ -167,7 +150,6 @@ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { /** * Subscribe to the next occurrence of an event. - * @type {BrokerApi['once']} */ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { return this.on(eventName, callback, { @@ -178,7 +160,6 @@ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { /** * Promise-style wait for an event. Rejects on a mandatory `*.error` message. - * @type {BrokerApi['waitFor']} */ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { const key = this._getEventRoutingKey(eventName); @@ -208,7 +189,6 @@ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { /** * Publish a prefixed event message. - * @type {BrokerApi['emit']} */ EventBroker.prototype.emit = function emit(eventName, content, props) { this.broker.publish('event', `${this.eventPrefix}.${eventName}`, { @@ -221,7 +201,6 @@ EventBroker.prototype.emit = function emit(eventName, content, props) { /** * Emit a mandatory error event. Surfaces via `on('error', ...)` or causes a return message to throw. - * @type {BrokerApi['emitFatal']} */ EventBroker.prototype.emitFatal = function emitFatal(error, content) { this.emit('error', { diff --git a/dist/Timers.js b/dist/Timers.js index 227f3e8c..47daf367 100644 --- a/dist/Timers.js +++ b/dist/Timers.js @@ -9,8 +9,7 @@ const K_TIMER_API = Symbol.for('timers api'); const MAX_DELAY = 2147483647; /** - * - * @param {*} options + * @param {import('#types').TimersOptions} options */ function Timers(options) { this.count = 0; diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index f0e56ad1..736d1b04 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -42,6 +42,7 @@ function Activity(Behaviour, activityDef, context) { this.id = id; this.type = type; this.name = name; + /** @type {import('moddle-context-serializer').ActivityBehaviour} */ this.behaviour = { ...behaviour, eventDefinitions @@ -53,7 +54,7 @@ function Activity(Behaviour, activityDef, context) { this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; - /** @type {import('#types').ActivityRunStatus} */ + /** @type {import('#types').ActivityStatus | undefined} */ this.status = undefined; this[_constants.K_COUNTERS] = { taken: 0, @@ -397,6 +398,7 @@ Activity.prototype.resume = function resume() { /** * Discard the activity. Stops execution if running and discards outbound flows. * @param {Record} [discardContent] Optional content propagated with the discard + * @returns {void} */ Activity.prototype.discard = function discard(discardContent) { if (!this.status) return this._runDiscard(discardContent); diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index 53f952db..7bc573da 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -18,7 +18,6 @@ var _constants = require("../constants.js"); * @param {import('#types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged */ function Definition(context, options) { - if (!(this instanceof Definition)) return new Definition(context, options); if (!context) throw new Error('No context'); const { id, @@ -60,7 +59,6 @@ function Definition(context, options) { emit, emitFatal } = (0, _EventBroker.DefinitionBroker)(this, onBrokerReturn); - /** @type {import('smqp').Broker} */ this.broker = broker; this.on = on; this.once = once; diff --git a/dist/eventDefinitions/CancelEventDefinition.js b/dist/eventDefinitions/CancelEventDefinition.js index c16d6c25..6970d44f 100644 --- a/dist/eventDefinitions/CancelEventDefinition.js +++ b/dist/eventDefinitions/CancelEventDefinition.js @@ -21,7 +21,7 @@ function CancelEventDefinition(activity, eventDefinition) { const type = eventDefinition.type; this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { referenceType: 'cancel' }; diff --git a/dist/eventDefinitions/CompensateEventDefinition.js b/dist/eventDefinitions/CompensateEventDefinition.js index 27780c61..994e5166 100644 --- a/dist/eventDefinitions/CompensateEventDefinition.js +++ b/dist/eventDefinitions/CompensateEventDefinition.js @@ -26,7 +26,7 @@ function CompensateEventDefinition(activity, eventDefinition, context) { this.id = id; const type = this.type = eventDefinition.type; const referenceType = 'compensate'; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { referenceType }; diff --git a/dist/eventDefinitions/ConditionalEventDefinition.js b/dist/eventDefinitions/ConditionalEventDefinition.js index 05ba2945..831bd4b7 100644 --- a/dist/eventDefinitions/ConditionalEventDefinition.js +++ b/dist/eventDefinitions/ConditionalEventDefinition.js @@ -129,7 +129,7 @@ ConditionalEventDefinition.prototype.evaluateCallback = function evaluateCallbac /** * Get condition * @param {number} index Eventdefinition sequence number, used to name registered script - * @returns {ExpressionCondition|ScriptCondition|null} + * @returns {import('#types').ICondition | null} */ ConditionalEventDefinition.prototype.getCondition = function getCondition(index) { const behaviour = this.behaviour; diff --git a/dist/eventDefinitions/ErrorEventDefinition.js b/dist/eventDefinitions/ErrorEventDefinition.js index 8b875422..3eb125e5 100644 --- a/dist/eventDefinitions/ErrorEventDefinition.js +++ b/dist/eventDefinitions/ErrorEventDefinition.js @@ -26,7 +26,7 @@ function ErrorEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.errorRef, diff --git a/dist/eventDefinitions/EscalationEventDefinition.js b/dist/eventDefinitions/EscalationEventDefinition.js index 9b95815e..adf11266 100644 --- a/dist/eventDefinitions/EscalationEventDefinition.js +++ b/dist/eventDefinitions/EscalationEventDefinition.js @@ -29,7 +29,7 @@ function EscalationEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.escalationRef, diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index dae51678..91afe04a 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -26,7 +26,7 @@ function LinkEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { id: behaviour.name, linkName: behaviour.name, diff --git a/dist/eventDefinitions/MessageEventDefinition.js b/dist/eventDefinitions/MessageEventDefinition.js index 632e937f..b7d305d6 100644 --- a/dist/eventDefinitions/MessageEventDefinition.js +++ b/dist/eventDefinitions/MessageEventDefinition.js @@ -27,7 +27,7 @@ function MessageEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.messageRef, diff --git a/dist/eventDefinitions/SignalEventDefinition.js b/dist/eventDefinitions/SignalEventDefinition.js index b5ab00a4..4e43f8f3 100644 --- a/dist/eventDefinitions/SignalEventDefinition.js +++ b/dist/eventDefinitions/SignalEventDefinition.js @@ -28,7 +28,7 @@ function SignalEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.signalRef, diff --git a/dist/eventDefinitions/TimerEventDefinition.js b/dist/eventDefinitions/TimerEventDefinition.js index 4af169f5..d4702bb8 100644 --- a/dist/eventDefinitions/TimerEventDefinition.js +++ b/dist/eventDefinitions/TimerEventDefinition.js @@ -213,8 +213,9 @@ TimerEventDefinition.prototype._stop = function stop() { /** * Parse timer - * @param {string} timerType + * @param {import('#types').TimerType} timerType * @param {string} value + * @returns {import('#types').parsedTimer} */ TimerEventDefinition.prototype.parse = function parse(timerType, value) { let repeat, delay, expireAt; diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index b5474c50..be643251 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -186,7 +186,7 @@ SequenceFlow.prototype.shake = function shake(message) { /** * Resolve the flow's condition (script or expression). Returns null when no condition is set. * Emits a fatal error when the script language is missing or unsupported. - * @returns {import('#types').ISequenceFlowCondition | null} + * @returns {import('#types').ICondition | null} */ SequenceFlow.prototype.getCondition = function getCondition() { const conditionExpression = this.behaviour.conditionExpression; diff --git a/dist/tasks/CallActivity.js b/dist/tasks/CallActivity.js index def42ad7..dc7f018a 100644 --- a/dist/tasks/CallActivity.js +++ b/dist/tasks/CallActivity.js @@ -30,7 +30,7 @@ function CallActivityBehaviour(activity) { this.id = id; this.type = type; this.calledElement = behaviour.calledElement; - /** @type {import('./LoopCharacteristics.js').LoopCharacteristics} */ + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.broker = activity.broker; diff --git a/dist/tasks/ReceiveTask.js b/dist/tasks/ReceiveTask.js index f17abc46..e153ddda 100644 --- a/dist/tasks/ReceiveTask.js +++ b/dist/tasks/ReceiveTask.js @@ -37,15 +37,19 @@ function ReceiveTaskBehaviour(activity) { } = activity; this.id = id; this.type = type; - const reference = this.reference = { + + /** @type {import('#types').EventReference} */ + this.reference = { name: 'anonymous', ...behaviour.messageRef, referenceType: 'message' }; + + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined } */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.broker = activity.broker; - this[_constants.K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); + this[_constants.K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id); } /** diff --git a/dist/tasks/ScriptTask.js b/dist/tasks/ScriptTask.js index d19b16dd..5fb26c5c 100644 --- a/dist/tasks/ScriptTask.js +++ b/dist/tasks/ScriptTask.js @@ -31,6 +31,8 @@ function ScriptTaskBehaviour(activity) { this.id = id; this.type = type; this.scriptFormat = behaviour.scriptFormat; + + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; const environment = this.environment = activity.environment; diff --git a/dist/tasks/ServiceTask.js b/dist/tasks/ServiceTask.js index 441fbaa5..e6012fce 100644 --- a/dist/tasks/ServiceTask.js +++ b/dist/tasks/ServiceTask.js @@ -29,6 +29,7 @@ function ServiceTaskBehaviour(activity) { } = activity; this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.environment = activity.environment; diff --git a/dist/tasks/SignalTask.js b/dist/tasks/SignalTask.js index da5ff9d3..06475e11 100644 --- a/dist/tasks/SignalTask.js +++ b/dist/tasks/SignalTask.js @@ -29,6 +29,7 @@ function SignalTaskBehaviour(activity) { } = activity; this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.broker = activity.broker; diff --git a/dist/tasks/SubProcess.js b/dist/tasks/SubProcess.js index d6da2896..fc3aab24 100644 --- a/dist/tasks/SubProcess.js +++ b/dist/tasks/SubProcess.js @@ -59,6 +59,7 @@ function SubProcessBehaviour(activity, context) { } = activity; this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.context = context; diff --git a/dist/tasks/Task.js b/dist/tasks/Task.js index 83eec443..d67eace9 100644 --- a/dist/tasks/Task.js +++ b/dist/tasks/Task.js @@ -29,6 +29,7 @@ function TaskBehaviour(activity) { } = activity; this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.broker = broker; } diff --git a/src/EventBroker.js b/src/EventBroker.js index fed0abb6..5d6d9380 100644 --- a/src/EventBroker.js +++ b/src/EventBroker.js @@ -1,20 +1,10 @@ import { Broker } from 'smqp'; import { makeErrorFromMessage } from './error/Errors.js'; -/** - * @typedef {object} BrokerApi Shape of the bound event helpers exposed by an EventBroker - * (and inherited by every element class that destructures from one). - * @property {(eventName: string, callback: CallableFunction, eventOptions?: { once?: boolean, [x: string]: any }) => import('smqp').Consumer} on - * @property {(eventName: string, callback: CallableFunction, eventOptions?: { [x: string]: any }) => import('smqp').Consumer} once - * @property {(eventName: string, onMessage?: (routingKey: string, message: import('#types').ElementBrokerMessage, owner: any) => boolean) => Promise} waitFor - * @property {(eventName: string, content?: Record, props?: any) => void} emit - * @property {(error: Error, content?: Record) => void} emitFatal - */ - /** * Build the broker for an activity, including run/format/execution/api exchanges and queues. * @param {import('#types').Activity} activity - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ export function ActivityBroker(activity) { const executionBroker = ExecutionBroker(activity, 'activity'); @@ -24,7 +14,7 @@ export function ActivityBroker(activity) { /** * Build the broker for a process, with an additional api-q bound to all api routing keys. * @param {import('#types').Process} owner - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ export function ProcessBroker(owner) { const executionBroker = ExecutionBroker(owner, 'process'); @@ -37,7 +27,7 @@ export function ProcessBroker(owner) { * Build the broker for a definition. Optionally registers a custom return-message handler. * @param {import('#types').Definition} owner * @param {(message: import('#types').ElementBrokerMessage) => void} [onBrokerReturn] - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ export function DefinitionBroker(owner, onBrokerReturn) { return ExecutionBroker(owner, 'definition', onBrokerReturn); @@ -46,7 +36,7 @@ export function DefinitionBroker(owner, onBrokerReturn) { /** * Build the broker for a message flow with a durable message exchange and message-q. * @param {import('./flows/MessageFlow.js').MessageFlow} owner - * @returns {import('#types').ElementBroker} + * @returns {import('#types').EventBroker} */ export function MessageFlowBroker(owner) { const eventBroker = new EventBroker(owner, { prefix: 'messageflow', autoDelete: false, durable: false }); @@ -94,22 +84,16 @@ export function EventBroker(brokerOwner, options, onBrokerReturn) { broker.assertExchange('event', 'topic', options); broker.on('return', onBrokerReturn ? onBrokerReturn.bind(brokerOwner) : this._onBrokerReturnFn.bind(this)); - /** @type {BrokerApi['on']} */ this.on = this.on.bind(this); - /** @type {BrokerApi['once']} */ this.once = this.once.bind(this); - /** @type {BrokerApi['waitFor']} */ this.waitFor = this.waitFor.bind(this); - /** @type {BrokerApi['emit']} */ this.emit = this.emit.bind(this); - /** @type {BrokerApi['emitFatal']} */ this.emitFatal = this.emitFatal.bind(this); } /** * Subscribe to a prefixed event. Errors are unwrapped via `makeErrorFromMessage`, * other events resolve to the owner's Api wrapper. - * @type {BrokerApi['on']} */ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { once: false }) { const key = this._getEventRoutingKey(eventName); @@ -125,7 +109,6 @@ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { onc /** * Subscribe to the next occurrence of an event. - * @type {BrokerApi['once']} */ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { return this.on(eventName, callback, { ...eventOptions, once: true }); @@ -133,7 +116,6 @@ EventBroker.prototype.once = function once(eventName, callback, eventOptions) { /** * Promise-style wait for an event. Rejects on a mandatory `*.error` message. - * @type {BrokerApi['waitFor']} */ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { const key = this._getEventRoutingKey(eventName); @@ -166,7 +148,6 @@ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) { /** * Publish a prefixed event message. - * @type {BrokerApi['emit']} */ EventBroker.prototype.emit = function emit(eventName, content, props) { this.broker.publish('event', `${this.eventPrefix}.${eventName}`, { ...content }, { type: eventName, ...props }); @@ -174,7 +155,6 @@ EventBroker.prototype.emit = function emit(eventName, content, props) { /** * Emit a mandatory error event. Surfaces via `on('error', ...)` or causes a return message to throw. - * @type {BrokerApi['emitFatal']} */ EventBroker.prototype.emitFatal = function emitFatal(error, content) { this.emit('error', { ...content, error }, { mandatory: true }); diff --git a/src/Timers.js b/src/Timers.js index 5131c438..1272e1da 100644 --- a/src/Timers.js +++ b/src/Timers.js @@ -4,8 +4,7 @@ const K_TIMER_API = Symbol.for('timers api'); const MAX_DELAY = 2147483647; /** - * - * @param {*} options + * @param {import('#types').TimersOptions} options */ export function Timers(options) { this.count = 0; diff --git a/src/activity/Activity.js b/src/activity/Activity.js index ace4f99f..ab1cb0a9 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -38,6 +38,7 @@ export function Activity(Behaviour, activityDef, context) { this.id = id; this.type = type; this.name = name; + /** @type {import('moddle-context-serializer').ActivityBehaviour} */ this.behaviour = { ...behaviour, eventDefinitions }; this.Behaviour = Behaviour; /** @type {import('moddle-context-serializer').Parent} */ @@ -46,7 +47,7 @@ export function Activity(Behaviour, activityDef, context) { this.logger = context.environment.Logger(type.toLowerCase()); this.environment = context.environment; this.context = context; - /** @type {import('#types').ActivityRunStatus} */ + /** @type {import('#types').ActivityStatus | undefined} */ this.status = undefined; this[K_COUNTERS] = { @@ -390,6 +391,7 @@ Activity.prototype.resume = function resume() { /** * Discard the activity. Stops execution if running and discards outbound flows. * @param {Record} [discardContent] Optional content propagated with the discard + * @returns {void} */ Activity.prototype.discard = function discard(discardContent) { if (!this.status) return this._runDiscard(discardContent); diff --git a/src/definition/Definition.js b/src/definition/Definition.js index 036d0f01..30e7d36b 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -22,7 +22,6 @@ import { * @param {import('#types').EnvironmentOptions} [options] When provided, environment is cloned and settings merged */ export function Definition(context, options) { - if (!(this instanceof Definition)) return new Definition(context, options); if (!context) throw new Error('No context'); const { id, name, type = 'definition' } = context; @@ -59,7 +58,6 @@ export function Definition(context, options) { }; const { broker, on, once, waitFor, emit, emitFatal } = DefinitionBroker(this, onBrokerReturn); - /** @type {import('smqp').Broker} */ this.broker = broker; this.on = on; diff --git a/src/eventDefinitions/CancelEventDefinition.js b/src/eventDefinitions/CancelEventDefinition.js index 8cd6c511..682bd880 100644 --- a/src/eventDefinitions/CancelEventDefinition.js +++ b/src/eventDefinitions/CancelEventDefinition.js @@ -12,7 +12,7 @@ export function CancelEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { referenceType: 'cancel' }; this.isThrowing = isThrowing; this.activity = activity; diff --git a/src/eventDefinitions/CompensateEventDefinition.js b/src/eventDefinitions/CompensateEventDefinition.js index a6fadf08..5db629d0 100644 --- a/src/eventDefinitions/CompensateEventDefinition.js +++ b/src/eventDefinitions/CompensateEventDefinition.js @@ -17,7 +17,7 @@ export function CompensateEventDefinition(activity, eventDefinition, context) { this.id = id; const type = (this.type = eventDefinition.type); const referenceType = 'compensate'; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { referenceType }; this.isThrowing = isThrowing; this.activity = activity; diff --git a/src/eventDefinitions/ConditionalEventDefinition.js b/src/eventDefinitions/ConditionalEventDefinition.js index 770e588f..4dc50494 100644 --- a/src/eventDefinitions/ConditionalEventDefinition.js +++ b/src/eventDefinitions/ConditionalEventDefinition.js @@ -128,7 +128,7 @@ ConditionalEventDefinition.prototype.evaluateCallback = function evaluateCallbac /** * Get condition * @param {number} index Eventdefinition sequence number, used to name registered script - * @returns {ExpressionCondition|ScriptCondition|null} + * @returns {import('#types').ICondition | null} */ ConditionalEventDefinition.prototype.getCondition = function getCondition(index) { const behaviour = this.behaviour; diff --git a/src/eventDefinitions/ErrorEventDefinition.js b/src/eventDefinitions/ErrorEventDefinition.js index a7031a34..565423dc 100644 --- a/src/eventDefinitions/ErrorEventDefinition.js +++ b/src/eventDefinitions/ErrorEventDefinition.js @@ -14,7 +14,7 @@ export function ErrorEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.errorRef, diff --git a/src/eventDefinitions/EscalationEventDefinition.js b/src/eventDefinitions/EscalationEventDefinition.js index b47b2728..1db94d96 100644 --- a/src/eventDefinitions/EscalationEventDefinition.js +++ b/src/eventDefinitions/EscalationEventDefinition.js @@ -17,7 +17,7 @@ export function EscalationEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.escalationRef, diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 29df0bee..71dd4b46 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -14,7 +14,7 @@ export function LinkEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { id: behaviour.name, linkName: behaviour.name, diff --git a/src/eventDefinitions/MessageEventDefinition.js b/src/eventDefinitions/MessageEventDefinition.js index 8d83bc2f..6cf2f5df 100644 --- a/src/eventDefinitions/MessageEventDefinition.js +++ b/src/eventDefinitions/MessageEventDefinition.js @@ -15,7 +15,7 @@ export function MessageEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.messageRef, diff --git a/src/eventDefinitions/SignalEventDefinition.js b/src/eventDefinitions/SignalEventDefinition.js index e098cd7c..2721b931 100644 --- a/src/eventDefinitions/SignalEventDefinition.js +++ b/src/eventDefinitions/SignalEventDefinition.js @@ -15,7 +15,7 @@ export function SignalEventDefinition(activity, eventDefinition) { this.id = id; this.type = type; - /** @type {import('#types').EventDefinitionReference} */ + /** @type {import('#types').EventReference} */ this.reference = { name: 'anonymous', ...behaviour.signalRef, diff --git a/src/eventDefinitions/TimerEventDefinition.js b/src/eventDefinitions/TimerEventDefinition.js index 2132af63..4edf1170 100644 --- a/src/eventDefinitions/TimerEventDefinition.js +++ b/src/eventDefinitions/TimerEventDefinition.js @@ -210,8 +210,9 @@ TimerEventDefinition.prototype._stop = function stop() { /** * Parse timer - * @param {string} timerType + * @param {import('#types').TimerType} timerType * @param {string} value + * @returns {import('#types').parsedTimer} */ TimerEventDefinition.prototype.parse = function parse(timerType, value) { let repeat, delay, expireAt; diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index 38b5687e..d2c288df 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -162,7 +162,7 @@ SequenceFlow.prototype.shake = function shake(message) { /** * Resolve the flow's condition (script or expression). Returns null when no condition is set. * Emits a fatal error when the script language is missing or unsupported. - * @returns {import('#types').ISequenceFlowCondition | null} + * @returns {import('#types').ICondition | null} */ SequenceFlow.prototype.getCondition = function getCondition() { const conditionExpression = this.behaviour.conditionExpression; diff --git a/src/tasks/CallActivity.js b/src/tasks/CallActivity.js index c122a939..f4138094 100644 --- a/src/tasks/CallActivity.js +++ b/src/tasks/CallActivity.js @@ -20,7 +20,7 @@ export function CallActivityBehaviour(activity) { this.id = id; this.type = type; this.calledElement = behaviour.calledElement; - /** @type {import('./LoopCharacteristics.js').LoopCharacteristics} */ + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; diff --git a/src/tasks/ReceiveTask.js b/src/tasks/ReceiveTask.js index d6d244f3..f795261f 100644 --- a/src/tasks/ReceiveTask.js +++ b/src/tasks/ReceiveTask.js @@ -26,18 +26,20 @@ export function ReceiveTaskBehaviour(activity) { this.id = id; this.type = type; - const reference = (this.reference = { + /** @type {import('#types').EventReference} */ + this.reference = { name: 'anonymous', ...behaviour.messageRef, referenceType: 'message', - }); + }; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined } */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; this.broker = activity.broker; - this[K_REFERENCE_ELEMENT] = reference.id && activity.getActivityById(reference.id); + this[K_REFERENCE_ELEMENT] = this.reference.id && activity.getActivityById(this.reference.id); } /** diff --git a/src/tasks/ScriptTask.js b/src/tasks/ScriptTask.js index 6925e1d2..c2369055 100644 --- a/src/tasks/ScriptTask.js +++ b/src/tasks/ScriptTask.js @@ -23,6 +23,7 @@ export function ScriptTaskBehaviour(activity) { this.type = type; this.scriptFormat = behaviour.scriptFormat; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; diff --git a/src/tasks/ServiceTask.js b/src/tasks/ServiceTask.js index d36d7534..30d0f470 100644 --- a/src/tasks/ServiceTask.js +++ b/src/tasks/ServiceTask.js @@ -20,6 +20,7 @@ export function ServiceTaskBehaviour(activity) { this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; diff --git a/src/tasks/SignalTask.js b/src/tasks/SignalTask.js index 001c0973..fb1b504b 100644 --- a/src/tasks/SignalTask.js +++ b/src/tasks/SignalTask.js @@ -20,6 +20,7 @@ export function SignalTaskBehaviour(activity) { this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; diff --git a/src/tasks/SubProcess.js b/src/tasks/SubProcess.js index c7b5c788..386f15b6 100644 --- a/src/tasks/SubProcess.js +++ b/src/tasks/SubProcess.js @@ -40,6 +40,7 @@ export function SubProcessBehaviour(activity, context) { const { id, type, behaviour } = activity; this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.activity = activity; diff --git a/src/tasks/Task.js b/src/tasks/Task.js index 5829acac..c835c84a 100644 --- a/src/tasks/Task.js +++ b/src/tasks/Task.js @@ -18,6 +18,7 @@ export function TaskBehaviour(activity) { const { id, type, behaviour, broker } = activity; this.id = id; this.type = type; + /** @type {import('./LoopCharacteristics.js').LoopCharacteristics | undefined} */ this.loopCharacteristics = behaviour.loopCharacteristics && new behaviour.loopCharacteristics.Behaviour(activity, behaviour.loopCharacteristics); this.broker = broker; diff --git a/test/definition/Definition-test.js b/test/definition/Definition-test.js index 061e9aa9..93aca425 100644 --- a/test/definition/Definition-test.js +++ b/test/definition/Definition-test.js @@ -8,16 +8,6 @@ import { Scripts as JavaScripts } from '../helpers/JavaScripts.js'; const lanesSource = factory.resource('lanes.bpmn'); describe('Definition', () => { - describe('#ctor', () => { - it('can be invoked without new', () => { - const newNewDefinition = Definition({ - id: 'Def_1', - environment: new Environment(), - }); - expect(newNewDefinition.run).to.be.a('function'); - }); - }); - describe('requirements', () => { it('requires a context with id and environment', () => { const definition = new Definition({ diff --git a/test/feature/errors-feature.js b/test/feature/errors-feature.js index a728ae4e..47852797 100644 --- a/test/feature/errors-feature.js +++ b/test/feature/errors-feature.js @@ -1073,7 +1073,7 @@ async function prepareSource() { camunda: CamundaExtension, }, }); - return Definition(context, { + return new Definition(context, { services: { isAbove(treshold, value) { return parseInt(treshold) < parseInt(value); diff --git a/test/feature/escalation-feature.js b/test/feature/escalation-feature.js index 24e5c86d..fb99271c 100644 --- a/test/feature/escalation-feature.js +++ b/test/feature/escalation-feature.js @@ -542,7 +542,7 @@ async function prepareSource() { camunda: CamundaExtension, }, }); - return Definition(context, { + return new Definition(context, { services: { isAbove(treshold, value) { return parseInt(treshold) < parseInt(value); diff --git a/types/index.d.ts b/types/index.d.ts index 5cbf666e..a1f9d4b7 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -7,6 +7,24 @@ declare module 'bpmn-elements' { get owner(): T; } + /** + * Wrapper returned by `ActivityBroker`, `ProcessBroker`, `DefinitionBroker`, + * `MessageFlowBroker`, and `new EventBroker(owner, options)`. Owns an underlying + * smqp Broker and exposes bound, prefixed event helpers. + * + * @template T Broker owner element type (Activity, Process, Definition, ...). + */ + export interface EventBroker { + options: { prefix: string; autoDelete?: boolean; durable?: boolean }; + eventPrefix: string; + broker: ElementBroker; + on(eventName: string, callback: CallableFunction, eventOptions?: { once?: boolean; [x: string]: any }): Consumer; + once(eventName: string, callback: CallableFunction, eventOptions?: { [x: string]: any }): Consumer; + waitFor(eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: T) => boolean): Promise>; + emit(eventName: string, content?: Record, props?: any): void; + emitFatal(error: Error, content?: Record): void; + } + export type signalMessage = { /** * Optional signal id @@ -82,33 +100,9 @@ declare module 'bpmn-elements' { get logger(): ILogger; } - export class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): IApi; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; - } - - export class MessageElement { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - resolve(executionMessage: ElementBrokerMessage): { - parent: ElementParent; - name: string; - id: string; - type: string; - messageType: string; - }; - } - // --- Event definitions -------------------------------------------------------- - export interface EventDefinitionReference { + export interface EventReference { id?: string; name?: string; referenceType: string; @@ -125,17 +119,21 @@ declare module 'bpmn-elements' { get activity(): Activity; get broker(): Broker; get logger(): ILogger; - get reference(): EventDefinitionReference; + get reference(): EventReference; [x: string]: any; execute(executeMessage: ElementBrokerMessage): void; } - export enum TimerType { + /** Supported BPMN timer event definition types. */ + export enum TimerTypeValue { TimeCycle = 'timeCycle', TimeDuration = 'timeDuration', TimeDate = 'timeDate', } + /** Accepts either a `TimerTypeValue` enum member or its underlying string literal. */ + export type TimerType = TimerTypeValue | `${TimerTypeValue}`; + export type parsedTimer = { /** Expires at date time */ expireAt?: Date; @@ -151,18 +149,12 @@ declare module 'bpmn-elements' { /** Condition type */ get type(): string; [x: string]: any; - execute(message: ElementBrokerMessage, callback: CallableFunction): void; - } - - export interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; /** - * Execute sequence flow condition + * Execute condition * @param message Source element execution message * @param callback Callback with truthy result if flow should be taken */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + execute(message: ElementBrokerMessage, callback: CallableFunction): void; } // --- Activity behaviour & extensions ------------------------------------------ @@ -176,10 +168,8 @@ declare module 'bpmn-elements' { execute(executeMessage: ElementBrokerMessage): void; } - // Custom activity behaviour factory signature. - export function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; - export type Extension = (activity: any, context: any) => IExtension; + export interface IExtension { activate(message: ElementBrokerMessage): void; deactivate(message: ElementBrokerMessage): void; @@ -243,35 +233,95 @@ declare module 'bpmn-elements' { // --- Run-status enums --------------------------------------------------------- - export enum DefinitionRunStatus { + /** + * Definition status values. Covers both the entity (`Definition.status`) and + * the execution (`DefinitionExecution.status`) lifecycles. + */ + export enum DefinitionStatusValue { + /** DefinitionExecution constructed, not yet started */ + Init = 'init', + /** Definition run entered */ Entered = 'entered', + /** Definition run started */ Start = 'start', + /** Definition is executing */ Executing = 'executing', + /** Definition run ended */ End = 'end', + /** Definition run discarded */ Discarded = 'discarded', + /** Definition execution completed successfully */ + Completed = 'completed', + /** Definition execution failed */ + Error = 'error', } - export enum ProcessRunStatus { + /** Accepts either a `DefinitionStatusValue` enum member or its string literal. */ + export type DefinitionStatus = DefinitionStatusValue | `${DefinitionStatusValue}`; + + /** + * Process status values. Covers both the entity (`Process.status`) and the + * execution (`ProcessExecution.status`) lifecycles. + */ + export enum ProcessStatusValue { + /** ProcessExecution constructed, not yet started */ + Init = 'init', + /** Process run entered */ Entered = 'entered', + /** Process run started */ Start = 'start', + /** Process is executing */ Executing = 'executing', + /** Process run errored */ Errored = 'errored', + /** Process run ended */ End = 'end', + /** Process run discarded */ Discarded = 'discarded', + /** Process execution discard in progress */ + Discard = 'discard', + /** Process execution cancelled */ + Cancel = 'cancel', + /** Process execution completed successfully */ + Completed = 'completed', + /** Process execution failed */ + Error = 'error', + /** Process execution terminated by a terminate end event */ + Terminated = 'terminated', } + /** Accepts either a `ProcessStatusValue` enum member or its string literal. */ + export type ProcessStatus = ProcessStatusValue | `${ProcessStatusValue}`; + /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. + * Activity status values. Covers both the per-activity run lifecycle and the + * rollup states surfaced by Process/Definition `activityStatus` getters. Save + * point candidates are `Timer` and `Wait`. */ - export enum ActivityStatus { + export enum ActivityStatusValue { /** Idle, not running anything */ Idle = 'idle', + /** Run entered, triggered by taken inbound flow */ + Entered = 'entered', + /** Run started */ + Started = 'started', /** * At least one activity is executing, * e.g. a service task making a asynchronous request */ Executing = 'executing', + /** Activity behaviour execution completed successfully */ + Executed = 'executed', + /** Run end, take outbound flows */ + End = 'end', + /** Entering discard run, triggered by discarded inbound flow */ + Discard = 'discard', + /** Run was discarded, discard outbound flows */ + Discarded = 'discarded', + /** Activity behaviour execution failed, discard run */ + Error = 'error', + /** Formatting next run message */ + Formatting = 'formatting', /** * At least one activity is waiting for a timer to complete, * usually only TimerEventDefinition's @@ -285,28 +335,11 @@ declare module 'bpmn-elements' { } /** - * Activity run status + * Accepts either an `ActivityStatusValue` enum member or its underlying string + * literal, so JSDoc-typed assignments like `this.status = 'entered'` keep + * type-checking. */ - export enum ActivityRunStatus { - /** Run entered, triggered by taken inbound flow */ - Entered = 'entered', - /** Run started */ - Started = 'started', - /** Executing activity behaviour */ - Executing = 'executing', - /** Activity behaviour execution completed successfully */ - Executed = 'executed', - /** Run end, take outbound flows */ - End = 'end', - /** Entering discard run, triggered by discarded inbound flow */ - Discard = 'discard', - /** Run was discarded, discard outbound flows */ - Discarded = 'discarded', - /** Activity behaviour execution failed, discard run */ - Error = 'error', - /** Formatting next run message */ - Formatting = 'formatting', - } + export type ActivityStatus = ActivityStatusValue | `${ActivityStatusValue}`; // --- State snapshots ---------------------------------------------------------- @@ -331,7 +364,7 @@ declare module 'bpmn-elements' { } export interface ActivityState extends ElementState { - status?: string; + status?: ActivityStatus; executionId: string; stopped: boolean; counters: { taken: number; discarded: number }; @@ -354,7 +387,7 @@ declare module 'bpmn-elements' { executionId: string; stopped: boolean; completed: boolean; - status: string; + status: ProcessStatus; children: ActivityState[]; flows?: SequenceFlowState[]; messageFlows?: MessageFlowState[]; @@ -362,7 +395,7 @@ declare module 'bpmn-elements' { } export interface ProcessState extends ElementState { - status: string; + status: ProcessStatus; stopped: boolean; executionId?: string; counters: completedCounters; @@ -374,12 +407,12 @@ declare module 'bpmn-elements' { executionId: string; stopped: boolean; completed: boolean; - status: string; + status: DefinitionStatus; processes: ProcessState[]; } export interface DefinitionState extends ElementState { - status: string; + status: DefinitionStatus; stopped: boolean; executionId?: string; counters: completedCounters; @@ -387,14 +420,6 @@ declare module 'bpmn-elements' { execution?: DefinitionExecutionState; } - // --- Flow references ---------------------------------------------------------- - - export interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; - } - // --- Logging ------------------------------------------------------------------ export type LoggerFactory = (scope: string) => ILogger; @@ -533,9 +558,8 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; name: string | undefined; - behaviour: { - eventDefinitions: any; - }; + + behaviour: import("moddle-context-serializer").ActivityBehaviour; Behaviour: IActivityBehaviour; parent: import("moddle-context-serializer").Parent; @@ -544,14 +568,17 @@ declare module 'bpmn-elements' { environment: Environment; context: ContextInstance; - status: ActivityRunStatus; - broker: any; - on: (eventName: string, callback: (event: { - name: string; - } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; - once: any; - waitFor: any; - emitFatal: any; + status: ActivityStatus | undefined; + broker: ElementBroker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: ((routingKey: string, message: ElementBrokerMessage, owner: Activity) => boolean) | undefined) => Promise>; + emitFatal: (error: Error, content?: Record) => void; /** * Subscribe to inbound flows and start consuming the inbound queue. * */ @@ -591,8 +618,8 @@ declare module 'bpmn-elements' { /** * Discard the activity. Stops execution if running and discards outbound flows. * @param discardContent Optional content propagated with the discard - */ - discard(discardContent?: Record): any; + * */ + discard(discardContent?: Record): void; /** * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations). * @returns count of subscribed triggers @@ -605,7 +632,7 @@ declare module 'bpmn-elements' { /** * Stop the activity. If not currently running, just cancels the inbound consumer. */ - stop(): any; + stop(): boolean | void; /** * Advance one run-step when the environment runs in step mode. No-op otherwise. */ @@ -669,13 +696,13 @@ declare module 'bpmn-elements' { activity: Activity; context: ContextInstance; id: string | undefined; - broker: any; + broker: ElementBroker; get completed(): boolean; /** * Begin executing the activity behaviour. Resumes if the message is redelivered. * @throws {Error} when message or executionId is missing */ - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | undefined; executionId: string | undefined; source: IActivityBehaviour | undefined; /** @@ -859,22 +886,24 @@ declare module 'bpmn-elements' { * @param options When provided, environment is cloned and settings merged */ constructor(context: ContextInstance, options?: EnvironmentOptions); - id: string | undefined; + id: string; type: string; - name: string | undefined; + name: string; environment: Environment; - context: ContextInstance | undefined; - - broker: import("smqp").Broker; - on: ((eventName: string, callback: (event: { - name: string; - } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer) | undefined; - once: any; - waitFor: any; - emit: any; - emitFatal: any; + context: ContextInstance; + broker: ElementBroker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: ((routingKey: string, message: ElementBrokerMessage, owner: Definition) => boolean) | undefined) => Promise>; + emit: (eventName: string, content?: Record, props?: any) => void; + emitFatal: (error: Error, content?: Record) => void; logger: ILogger; /** @@ -963,9 +992,9 @@ declare module 'bpmn-elements' { get execution(): DefinitionExecution | undefined; get executionId(): string | undefined; get isRunning(): boolean; - get status(): string | undefined; + get status(): DefinitionStatus | undefined; get stopped(): boolean; - get activityStatus(): string; + get activityStatus(): ActivityStatus; } /** * Drives the execution of a Definition. Activates executable processes, routes inter-process @@ -977,9 +1006,9 @@ declare module 'bpmn-elements' { * delegate messages and call activity hand-offs, and rolls completion up to the Definition. * */ constructor(definition: Definition, context: ContextInstance); - id: string | undefined; + id: string; type: string; - broker: import("smqp").Broker; + broker: ElementBroker; environment: Environment; context: ContextInstance; executionId: string | undefined; @@ -1035,11 +1064,11 @@ declare module 'bpmn-elements' { getPostponed(...args: any[]): IApi; get stopped(): boolean; get completed(): boolean; - get status(): string; + get status(): DefinitionStatus; get processes(): Process[]; get postponedCount(): number; get isRunning(): boolean; - get activityStatus(): string; + get activityStatus(): ActivityStatus; } /** * Placeholder activity for non-executable elements (text annotations, groups, categories). @@ -1235,7 +1264,7 @@ declare module 'bpmn-elements' { dataOutputs?: import("moddle-context-serializer").IElement[]; }; activity: Activity; - broker: any; + broker: ElementBroker; context: ContextInstance; activate(message?: ElementBrokerMessage): void; @@ -1260,7 +1289,7 @@ declare module 'bpmn-elements' { behaviour: Record; environment: Environment; - broker: any; + broker: ElementBroker; context: ContextInstance; logger: ILogger; get process(): Process; @@ -1304,7 +1333,7 @@ declare module 'bpmn-elements' { message: ElementBrokerMessage; type: string; id: string | undefined; - broker: any; + broker: ElementBroker; parentExecutionId: string | undefined; isSequential: boolean; @@ -1389,12 +1418,15 @@ declare module 'bpmn-elements' { isExecutable: any; environment: Environment; context: ContextInstance; - broker: any; - on: (eventName: string, callback: (event: { - name: string; - } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; - once: any; - waitFor: any; + broker: ElementBroker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + waitFor: (eventName: string, onMessage?: ((routingKey: string, message: ElementBrokerMessage, owner: Process) => boolean) | undefined) => Promise>; logger: ILogger; /** * Allocate an executionId and emit init event without starting the run. @@ -1480,8 +1512,8 @@ declare module 'bpmn-elements' { get isRunning(): boolean; get executionId(): string | undefined; get execution(): ProcessExecution | undefined; - get status(): string | undefined; - get activityStatus(): string; + get status(): ProcessStatus | undefined; + get activityStatus(): ActivityStatus; } /** * Activity properties behaviour. Resolves bound data input/output references during the run. @@ -1499,7 +1531,7 @@ declare module 'bpmn-elements' { values: import("moddle-context-serializer").IElement[]; }, context: ContextInstance); activity: Activity; - broker: any; + broker: ElementBroker; activate(message: ElementBrokerMessage): void; deactivate(): void; @@ -1587,7 +1619,7 @@ declare module 'bpmn-elements' { type: string; isSubProcess: any; isTransaction: any; - broker: any; + broker: ElementBroker | ElementBroker; environment: Environment; context: ContextInstance; executionId: string | undefined; @@ -1650,10 +1682,10 @@ declare module 'bpmn-elements' { getApi(message?: ElementBrokerMessage): IApi; get stopped(): boolean; get completed(): boolean; - get status(): string; + get status(): ProcessStatus; get postponedCount(): number; get isRunning(): boolean; - get activityStatus(): string; + get activityStatus(): ActivityStatus; } /** * Sequence flow connecting two activities. Owns its broker and publishes take/discard/looped @@ -1678,15 +1710,10 @@ declare module 'bpmn-elements' { environment: Environment; logger: ILogger; broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; - emitFatal: (error: Error, content?: Record) => void; + on: any; + once: any; + waitFor: any; + emitFatal: any; get counters(): { take: number; discard: number; @@ -1729,7 +1756,7 @@ declare module 'bpmn-elements' { * Resolve the flow's condition (script or expression). Returns null when no condition is set. * Emits a fatal error when the script language is missing or unsupported. * */ - getCondition(): ISequenceFlowCondition | null; + getCondition(): ICondition | null; /** * Build a flow event message body, optionally merging override content. * */ @@ -1784,14 +1811,9 @@ declare module 'bpmn-elements' { environment: Environment; logger: ILogger; broker: import("smqp").Broker; - on: (eventName: string, callback: CallableFunction, eventOptions?: { - once?: boolean; - [x: string]: any; - }) => import("smqp").Consumer; - once: (eventName: string, callback: CallableFunction, eventOptions?: { - [x: string]: any; - }) => import("smqp").Consumer; - waitFor: (eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: any) => boolean) => Promise; + on: any; + once: any; + waitFor: any; get counters(): { take: number; discard: number; @@ -1846,13 +1868,16 @@ declare module 'bpmn-elements' { behaviour: Record; environment: Environment; context: ContextInstance; - broker: any; - on: (eventName: string, callback: (event: { - name: string; - } & Record) => void, options?: import("smqp").ConsumeOptions) => import("smqp").Consumer; - once: any; - emit: any; - waitFor: any; + broker: ElementBroker; + on: (eventName: string, callback: CallableFunction, eventOptions?: { + once?: boolean; + [x: string]: any; + }) => import("smqp").Consumer; + once: (eventName: string, callback: CallableFunction, eventOptions?: { + [x: string]: any; + }) => import("smqp").Consumer; + emit: (eventName: string, content?: Record, props?: any) => void; + waitFor: (eventName: string, onMessage?: ((routingKey: string, message: ElementBrokerMessage, owner: MessageFlow) => boolean) | undefined) => Promise>; logger: ILogger; get counters(): { messages: number; @@ -1896,9 +1921,9 @@ declare module 'bpmn-elements' { attachedTo: Activity | null; activity: Activity; environment: Environment; - broker: any; + broker: ElementBroker; get executionId(): string | undefined; - get cancelActivity(): unknown; + get cancelActivity(): any; execute(executeMessage: ElementBrokerMessage): void; } @@ -1916,7 +1941,7 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - broker: any; + broker: ElementBroker; execute(executeMessage: ElementBrokerMessage): void; } @@ -1934,7 +1959,7 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - broker: any; + broker: ElementBroker; execute(executeMessage: ElementBrokerMessage): void; } @@ -1952,7 +1977,7 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - broker: any; + broker: ElementBroker; execute(executeMessage: ElementBrokerMessage): void; } @@ -1971,7 +1996,7 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; activity: Activity; - broker: any; + broker: ElementBroker; get executionId(): string | undefined; execute(executeMessage: ElementBrokerMessage): void; @@ -1991,7 +2016,7 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; activity: Activity; - broker: any; + broker: ElementBroker; context: ContextInstance; execute(executeMessage: ElementBrokerMessage): void; @@ -2010,7 +2035,7 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - broker: any; + broker: ElementBroker; execute({ content }: ElementBrokerMessage): void; } @@ -2028,7 +2053,7 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - broker: any; + broker: ElementBroker; execute({ content }: ElementBrokerMessage): void; } @@ -2053,13 +2078,13 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; activity: Activity; - broker: any; + broker: ElementBroker; inbound: Set; isConverging: boolean; get executionId(): any; execute(executeMessage: ElementBrokerMessage): void; - setup(executeMessage: any): any; + setup(executeMessage: any): number | undefined; peerMonitor: PeerMonitor | undefined; } class PeerMonitor { @@ -2096,9 +2121,9 @@ declare module 'bpmn-elements' { type: string; calledElement: any; - loopCharacteristics: MultiInstanceLoopCharacteristics; + loopCharacteristics: MultiInstanceLoopCharacteristics | undefined; activity: Activity; - broker: any; + broker: ElementBroker; environment: Environment; execute(executeMessage: ElementBrokerMessage): void; @@ -2117,10 +2142,12 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - reference: any; - loopCharacteristics: any; + + reference: EventReference; + + loopCharacteristics: MultiInstanceLoopCharacteristics | undefined; activity: Activity; - broker: any; + broker: ElementBroker; execute(executeMessage: ElementBrokerMessage): void; } @@ -2138,8 +2165,9 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - scriptFormat: any; - loopCharacteristics: any; + scriptFormat: string | undefined; + + loopCharacteristics: MultiInstanceLoopCharacteristics | undefined; activity: Activity; environment: Environment; @@ -2159,10 +2187,11 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - loopCharacteristics: any; + + loopCharacteristics: MultiInstanceLoopCharacteristics | undefined; activity: Activity; environment: Environment; - broker: any; + broker: ElementBroker; execute(executeMessage: ElementBrokerMessage): void; service: any; @@ -2182,9 +2211,10 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - loopCharacteristics: any; + + loopCharacteristics: MultiInstanceLoopCharacteristics | undefined; activity: Activity; - broker: any; + broker: ElementBroker; execute(executeMessage: ElementBrokerMessage): void; } @@ -2202,11 +2232,12 @@ declare module 'bpmn-elements' { constructor(activity: Activity, context: ContextInstance); id: string | undefined; type: string; - loopCharacteristics: any; + + loopCharacteristics: MultiInstanceLoopCharacteristics | undefined; activity: Activity; context: ContextInstance; environment: Environment; - broker: any; + broker: ElementBroker; executionId: string | undefined; get execution(): any; get executions(): any[]; @@ -2231,8 +2262,9 @@ declare module 'bpmn-elements' { constructor(activity: Activity); id: string | undefined; type: string; - loopCharacteristics: any; - broker: any; + + loopCharacteristics: MultiInstanceLoopCharacteristics | undefined; + broker: ElementBroker; execute(executeMessage: ElementBrokerMessage): void; } @@ -2251,11 +2283,11 @@ declare module 'bpmn-elements' { id: string | undefined; type: string | undefined; - reference: EventDefinitionReference; + reference: EventReference; isThrowing: boolean; activity: Activity; environment: Environment; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; @@ -2276,18 +2308,18 @@ declare module 'bpmn-elements' { id: string | undefined; type: string | undefined; - reference: EventDefinitionReference; + reference: EventReference; isThrowing: boolean; activity: Activity; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | import("smqp").Consumer | undefined; - executeCatch(executeMessage: ElementBrokerMessage): any; + executeCatch(executeMessage: ElementBrokerMessage): import("smqp").Consumer | undefined; - executeThrow(executeMessage: ElementBrokerMessage): any; + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } /** * Conditional event definition @@ -2304,9 +2336,9 @@ declare module 'bpmn-elements' { behaviour: {}; activity: Activity; environment: Environment; - broker: any; + broker: ElementBroker; logger: ILogger; - condition: ScriptCondition | ExpressionCondition | null; + condition: ICondition | null; get executionId(): string; execute(executeMessage: ElementBrokerMessage): void; @@ -2319,12 +2351,12 @@ declare module 'bpmn-elements' { * @param err Condition evaluation error * @param result Result from evaluated condition, completes execution if truthy */ - evaluateCallback(err: Error | null, result: any): any; + evaluateCallback(err: Error | null, result: any): number | undefined; /** * Get condition * @param index Eventdefinition sequence number, used to name registered script * */ - getCondition(index: number): ExpressionCondition | ScriptCondition | null; + getCondition(index: number): ICondition | null; } /** * Error event definition @@ -2337,19 +2369,19 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; - reference: EventDefinitionReference; + reference: EventReference; isThrowing: boolean; activity: Activity; environment: Environment; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | void; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): any; + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } /** * Escalation event definition @@ -2362,18 +2394,18 @@ declare module 'bpmn-elements' { id: string | undefined; type: string | undefined; - reference: EventDefinitionReference; + reference: EventReference; isThrowing: boolean; activity: Activity; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | void; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): any; + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } /** * Link event definition @@ -2386,18 +2418,18 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; - reference: EventDefinitionReference; + reference: EventReference; isThrowing: boolean; activity: Activity; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | undefined; - executeCatch(executeMessage: ElementBrokerMessage): any; + executeCatch(executeMessage: ElementBrokerMessage): number | undefined; - executeThrow(executeMessage: ElementBrokerMessage): any; + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } /** * Message event definition @@ -2410,18 +2442,18 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; - reference: EventDefinitionReference; + reference: EventReference; isThrowing: boolean; activity: Activity; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | void; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): any; + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } /** * Signal event definition @@ -2434,18 +2466,18 @@ declare module 'bpmn-elements' { id: string | undefined; type: string | undefined; - reference: EventDefinitionReference; + reference: EventReference; isThrowing: boolean; activity: Activity; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; - execute(executeMessage: ElementBrokerMessage): any; + execute(executeMessage: ElementBrokerMessage): number | void; executeCatch(executeMessage: ElementBrokerMessage): void; - executeThrow(executeMessage: ElementBrokerMessage): any; + executeThrow(executeMessage: ElementBrokerMessage): number | undefined; } /** * Terminate event definition @@ -2458,7 +2490,7 @@ declare module 'bpmn-elements' { id: string | undefined; type: string; activity: Activity; - broker: any; + broker: ElementBroker; logger: ILogger; execute(executeMessage: ElementBrokerMessage): void; @@ -2478,7 +2510,7 @@ declare module 'bpmn-elements' { timeDuration: string | undefined; timeCycle: string | undefined; timeDate: string | undefined; - broker: any; + broker: ElementBroker; logger: ILogger; get executionId(): string; get stopped(): boolean; @@ -2490,11 +2522,7 @@ declare module 'bpmn-elements' { /** * Parse timer * */ - parse(timerType: string, value: string): { - expireAt: Date | undefined; - repeat: number | undefined; - delay: number | undefined; - }; + parse(timerType: TimerType, value: string): parsedTimer; } /** * Event definition execution orchestrator. Drives a sequence of event definitions for the @@ -2510,7 +2538,7 @@ declare module 'bpmn-elements' { constructor(activity: Activity, eventDefinitions: EventDefinition[], completedRoutingKey?: string); id: string | undefined; activity: Activity; - broker: any; + broker: ElementBroker; eventDefinitions: EventDefinition[]; completedRoutingKey: string; get completed(): boolean; @@ -2518,36 +2546,6 @@ declare module 'bpmn-elements' { execute(executeMessage: ElementBrokerMessage): void; } - /** - * Script condition - * */ - class ScriptCondition { - /** - * Script condition - * */ - constructor(owner: ElementBase, script: any, language: string); - type: string; - language: string; - /** - * Execute - * */ - execute(message: any, callback: CallableFunction): any; - } - /** - * Expression condition - * */ - class ExpressionCondition { - /** - * Expression condition - * */ - constructor(owner: ElementBase, expression: string); - type: string; - expression: string; - /** - * Execute - * */ - execute(message: ElementBrokerMessage, callback: CallableFunction): any; - } export { Consumer, MessageFields, MessageProperties, SerializableContext, SerializableElement }; export const BusinessRuleTask: typeof ServiceTask; diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index 1fbdc22e..a44fb537 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -54,9 +54,9 @@ declare module '../src/definition/Definition.js' { get execution(): DefinitionExecution | undefined; get executionId(): string | undefined; get isRunning(): boolean; - get status(): string | undefined; + get status(): DefinitionStatus | undefined; get stopped(): boolean; - get activityStatus(): string; + get activityStatus(): ActivityStatus; } } @@ -69,8 +69,8 @@ declare module '../src/process/Process.js' { get isRunning(): boolean; get executionId(): string | undefined; get execution(): ProcessExecution | undefined; - get status(): string | undefined; - get activityStatus(): string; + get status(): ProcessStatus | undefined; + get activityStatus(): ActivityStatus; } } @@ -78,10 +78,10 @@ declare module '../src/process/ProcessExecution.js' { interface ProcessExecution { get stopped(): boolean; get completed(): boolean; - get status(): string; + get status(): ProcessStatus; get postponedCount(): number; get isRunning(): boolean; - get activityStatus(): string; + get activityStatus(): ActivityStatus; } } @@ -89,11 +89,11 @@ declare module '../src/definition/DefinitionExecution.js' { interface DefinitionExecution { get stopped(): boolean; get completed(): boolean; - get status(): string; + get status(): DefinitionStatus; get processes(): Process[]; get postponedCount(): number; get isRunning(): boolean; - get activityStatus(): string; + get activityStatus(): ActivityStatus; } } @@ -103,6 +103,24 @@ export interface ElementBroker extends Broker { get owner(): T; } +/** + * Wrapper returned by `ActivityBroker`, `ProcessBroker`, `DefinitionBroker`, + * `MessageFlowBroker`, and `new EventBroker(owner, options)`. Owns an underlying + * smqp Broker and exposes bound, prefixed event helpers. + * + * @template T Broker owner element type (Activity, Process, Definition, ...). + */ +export interface EventBroker { + options: { prefix: string; autoDelete?: boolean; durable?: boolean }; + eventPrefix: string; + broker: ElementBroker; + on(eventName: string, callback: CallableFunction, eventOptions?: { once?: boolean; [x: string]: any }): Consumer; + once(eventName: string, callback: CallableFunction, eventOptions?: { [x: string]: any }): Consumer; + waitFor(eventName: string, onMessage?: (routingKey: string, message: ElementBrokerMessage, owner: T) => boolean): Promise>; + emit(eventName: string, content?: Record, props?: any): void; + emitFatal(error: Error, content?: Record): void; +} + export type signalMessage = { /** * Optional signal id @@ -178,33 +196,9 @@ export abstract class ElementBase { get logger(): ILogger; } -export abstract class Element extends ElementBase { - get broker(): ElementBroker; - stop(): void; - resume(): void; - getApi(message?: ElementBrokerMessage): IApi; - on(eventName: string, callback: CallableFunction, options?: any): any; - once(eventName: string, callback: CallableFunction, options?: any): any; - waitFor(eventName: string, options?: any): Promise>; -} - -export abstract class MessageElement { - get id(): string; - get type(): string; - get name(): string; - get parent(): ElementParent; - resolve(executionMessage: ElementBrokerMessage): { - parent: ElementParent; - name: string; - id: string; - type: string; - messageType: string; - }; -} - // --- Event definitions -------------------------------------------------------- -export interface EventDefinitionReference { +export interface EventReference { id?: string; name?: string; referenceType: string; @@ -221,17 +215,21 @@ export class EventDefinition { get activity(): Activity; get broker(): Broker; get logger(): ILogger; - get reference(): EventDefinitionReference; + get reference(): EventReference; [x: string]: any; execute(executeMessage: ElementBrokerMessage): void; } -export const enum TimerType { +/** Supported BPMN timer event definition types. */ +export const enum TimerTypeValue { TimeCycle = 'timeCycle', TimeDuration = 'timeDuration', TimeDate = 'timeDate', } +/** Accepts either a `TimerTypeValue` enum member or its underlying string literal. */ +export type TimerType = TimerTypeValue | `${TimerTypeValue}`; + export type parsedTimer = { /** Expires at date time */ expireAt?: Date; @@ -247,18 +245,12 @@ export interface ICondition { /** Condition type */ get type(): string; [x: string]: any; - execute(message: ElementBrokerMessage, callback: CallableFunction): void; -} - -export interface ISequenceFlowCondition { - /** Condition type, e.g. script or expression */ - get type(): string; /** - * Execute sequence flow condition + * Execute condition * @param message Source element execution message * @param callback Callback with truthy result if flow should be taken */ - execute(message: ElementBrokerMessage, callback: (err: Error, result: any) => void): void; + execute(message: ElementBrokerMessage, callback: CallableFunction): void; } // --- Activity behaviour & extensions ------------------------------------------ @@ -272,10 +264,8 @@ export interface IActivityBehaviour { execute(executeMessage: ElementBrokerMessage): void; } -// Custom activity behaviour factory signature. -export function ActivityBehaviour(activityDef: SerializableElement, context: ContextInstance): Activity; - export type Extension = (activity: any, context: any) => IExtension; + export interface IExtension { activate(message: ElementBrokerMessage): void; deactivate(message: ElementBrokerMessage): void; @@ -339,35 +329,95 @@ export type runCallback = (err: Error, definitionApi: any) => void; // --- Run-status enums --------------------------------------------------------- -export const enum DefinitionRunStatus { +/** + * Definition status values. Covers both the entity (`Definition.status`) and + * the execution (`DefinitionExecution.status`) lifecycles. + */ +export const enum DefinitionStatusValue { + /** DefinitionExecution constructed, not yet started */ + Init = 'init', + /** Definition run entered */ Entered = 'entered', + /** Definition run started */ Start = 'start', + /** Definition is executing */ Executing = 'executing', + /** Definition run ended */ End = 'end', + /** Definition run discarded */ Discarded = 'discarded', + /** Definition execution completed successfully */ + Completed = 'completed', + /** Definition execution failed */ + Error = 'error', } -export const enum ProcessRunStatus { +/** Accepts either a `DefinitionStatusValue` enum member or its string literal. */ +export type DefinitionStatus = DefinitionStatusValue | `${DefinitionStatusValue}`; + +/** + * Process status values. Covers both the entity (`Process.status`) and the + * execution (`ProcessExecution.status`) lifecycles. + */ +export const enum ProcessStatusValue { + /** ProcessExecution constructed, not yet started */ + Init = 'init', + /** Process run entered */ Entered = 'entered', + /** Process run started */ Start = 'start', + /** Process is executing */ Executing = 'executing', + /** Process run errored */ Errored = 'errored', + /** Process run ended */ End = 'end', + /** Process run discarded */ Discarded = 'discarded', + /** Process execution discard in progress */ + Discard = 'discard', + /** Process execution cancelled */ + Cancel = 'cancel', + /** Process execution completed successfully */ + Completed = 'completed', + /** Process execution failed */ + Error = 'error', + /** Process execution terminated by a terminate end event */ + Terminated = 'terminated', } +/** Accepts either a `ProcessStatusValue` enum member or its string literal. */ +export type ProcessStatus = ProcessStatusValue | `${ProcessStatusValue}`; + /** - * Activity status - * Can be used to decide when to save states, Timer and Wait is recommended. + * Activity status values. Covers both the per-activity run lifecycle and the + * rollup states surfaced by Process/Definition `activityStatus` getters. Save + * point candidates are `Timer` and `Wait`. */ -export const enum ActivityStatus { +export const enum ActivityStatusValue { /** Idle, not running anything */ Idle = 'idle', + /** Run entered, triggered by taken inbound flow */ + Entered = 'entered', + /** Run started */ + Started = 'started', /** * At least one activity is executing, * e.g. a service task making a asynchronous request */ Executing = 'executing', + /** Activity behaviour execution completed successfully */ + Executed = 'executed', + /** Run end, take outbound flows */ + End = 'end', + /** Entering discard run, triggered by discarded inbound flow */ + Discard = 'discard', + /** Run was discarded, discard outbound flows */ + Discarded = 'discarded', + /** Activity behaviour execution failed, discard run */ + Error = 'error', + /** Formatting next run message */ + Formatting = 'formatting', /** * At least one activity is waiting for a timer to complete, * usually only TimerEventDefinition's @@ -381,28 +431,11 @@ export const enum ActivityStatus { } /** - * Activity run status + * Accepts either an `ActivityStatusValue` enum member or its underlying string + * literal, so JSDoc-typed assignments like `this.status = 'entered'` keep + * type-checking. */ -export const enum ActivityRunStatus { - /** Run entered, triggered by taken inbound flow */ - Entered = 'entered', - /** Run started */ - Started = 'started', - /** Executing activity behaviour */ - Executing = 'executing', - /** Activity behaviour execution completed successfully */ - Executed = 'executed', - /** Run end, take outbound flows */ - End = 'end', - /** Entering discard run, triggered by discarded inbound flow */ - Discard = 'discard', - /** Run was discarded, discard outbound flows */ - Discarded = 'discarded', - /** Activity behaviour execution failed, discard run */ - Error = 'error', - /** Formatting next run message */ - Formatting = 'formatting', -} +export type ActivityStatus = ActivityStatusValue | `${ActivityStatusValue}`; // --- State snapshots ---------------------------------------------------------- @@ -427,7 +460,7 @@ export interface ActivityExecutionState { } export interface ActivityState extends ElementState { - status?: string; + status?: ActivityStatus; executionId: string; stopped: boolean; counters: { taken: number; discarded: number }; @@ -450,7 +483,7 @@ export interface ProcessExecutionState { executionId: string; stopped: boolean; completed: boolean; - status: string; + status: ProcessStatus; children: ActivityState[]; flows?: SequenceFlowState[]; messageFlows?: MessageFlowState[]; @@ -458,7 +491,7 @@ export interface ProcessExecutionState { } export interface ProcessState extends ElementState { - status: string; + status: ProcessStatus; stopped: boolean; executionId?: string; counters: completedCounters; @@ -470,12 +503,12 @@ export interface DefinitionExecutionState { executionId: string; stopped: boolean; completed: boolean; - status: string; + status: DefinitionStatus; processes: ProcessState[]; } export interface DefinitionState extends ElementState { - status: string; + status: DefinitionStatus; stopped: boolean; executionId?: string; counters: completedCounters; @@ -483,14 +516,6 @@ export interface DefinitionState extends ElementState { execution?: DefinitionExecutionState; } -// --- Flow references ---------------------------------------------------------- - -export interface MessageFlowReference { - /** activity id */ - get id(): string; - get processId(): string; -} - // --- Logging ------------------------------------------------------------------ export type LoggerFactory = (scope: string) => ILogger; From 79f642283f512767261905771e40b6c0ea3b75a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sun, 31 May 2026 10:46:52 +0200 Subject: [PATCH 20/31] update docs --- README.md | 4 +++- docs/Activity.md | 35 +++++++++++++++++++++++++++---- docs/ActivityExecution.md | 12 +++++++++++ docs/Context.md | 35 +++++++++++++++++++++++++++++-- docs/Definition.md | 21 ++++++++++++++++++- docs/Environment.md | 1 + docs/Examples.md | 4 ++-- docs/Extend.md | 10 +++++---- docs/Extension.md | 4 ++-- docs/MessageElements.md | 19 +++++++++++++++++ docs/ParallelGateway.md | 23 +++----------------- docs/Process.md | 36 +++++++++++++++++++++++++++++++- docs/SignalTask.md | 4 ++-- docs/StartEvent.md | 4 ++-- docs/Timers.md | 4 ++-- docs/parallel-join-edgecase.png | Bin 61112 -> 0 bytes 16 files changed, 173 insertions(+), 43 deletions(-) create mode 100644 docs/MessageElements.md delete mode 100644 docs/parallel-join-edgecase.png diff --git a/README.md b/README.md index f531a4d7..0dc35fb4 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ The following elements are tested and supported. - ErrorEventDefinition - throw - catch +- [Escalation](/docs/MessageElements.md) - EscalationEventDefinition - throw - catch @@ -42,6 +43,7 @@ The following elements are tested and supported. - LinkEventDefinition - throw - catch +- [Message](/docs/MessageElements.md) - MessageEventDefinition - throw - catch @@ -58,7 +60,7 @@ The following elements are tested and supported. - [ServiceTask](/docs/ServiceTask.md) - BusinessRuleTask: Same behaviour as ServiceTask - SendTask: Same behaviour as ServiceTask -- Signal +- [Signal](/docs/MessageElements.md) - SignalEventDefinition - throw - catch diff --git a/docs/Activity.md b/docs/Activity.md index 443f758f..30aa1af0 100644 --- a/docs/Activity.md +++ b/docs/Activity.md @@ -21,20 +21,30 @@ Activity properties: - `id`: activity id - `type`: activity type - `name`: activity name -- `attachedTo`: activity is attached to, e.g. a BoundaryEvent +- `attachedTo`: if this is a BoundaryEvent, the activity instance it is attached to; otherwise `null` - `Behaviour`: passed activity Behaviour function, invoked with new - `behaviour`: activity behaviour from serializable context +- `bpmnIo`: BpmnIO extension if present - `broker`: activity [broker](https://github.com/paed01/smqp) - `counters`: counters for completed runs etc - `environment`: shared [environment](/docs/Environment) +- `eventDefinitions`: list of event definition instances - `execution`: getter for current [execution instance](/docs/ActivityExecution.md) - `executionId`: current unique execution id - `extensions`: object with [extensions](/docs/Extension.md) +- `formatter`: per-activity formatter that resolves pending format messages - `inbound`: list of inbound sequence flows +- `initialized`: boolean indicating that the activity has been initialized (`init` called) +- `isCatching`: boolean indicating that the activity is a catching event +- `isEnd`: boolean indicating that the activity has no outbound sequence flows +- `isForCompensation`: boolean indicating that the activity is for compensation +- `isMultiInstance`: boolean indicating that the activity has loop characteristics +- `isParallelJoin`: boolean indicating if the activity is a parallel join gateway - `isRunning`: boolean indicating if the activity is running - `isStart`: boolean indicating if the activity a start activity - `isSubProcess`: boolean indicating if the activity is a sub process -- `isParallelJoin`: boolean indicating if the activity is a parallel join gateway +- `isThrowing`: boolean indicating that the activity is a throwing event +- `isTransaction`: boolean indicating that the activity is a transaction - `logger`: activity [logger](/docs/Environment.md#logger) instance - `outbound`: list of outbound sequence flows - `parent`: activity parent @@ -53,6 +63,7 @@ Activity properties: - `error`: Activity behaviour execution failed, discard run - `formatting`: Formatting next run message - `stopped`: boolean indicating if the activity is in a stopped state +- `triggeredByEvent`: boolean indicating that the activity (sub process) is triggered by an event ### `activate()` @@ -84,9 +95,25 @@ Get [activity](/docs/Activity.md) by id from context. Get activity state. If `environment.settings.disableTrackState === true` the state may be undefined if the task is not running. -### `message(messageContent)` +### `init([initContent])` + +Initialize the activity without running. Publishes an `activity.init` event with an execution id reserved for the next run. + +Arguments: + +- `initContent`: optional object merged into the init message content + +### `addInboundListeners()` + +Subscribe to inbound sequence flow events. Called internally from `activate()` and rarely needs to be called directly. + +### `removeInboundListeners()` + +Unsubscribe from inbound sequence flow events. Counterpart to `addInboundListeners()`. + +### `shake()` -Send message to activity. Queues message to activity. +Walk outbound sequence flows for shake analysis. Used to discover reachable flows from this activity. ### `next()` diff --git a/docs/ActivityExecution.md b/docs/ActivityExecution.md index f7f4ac42..30485f1e 100644 --- a/docs/ActivityExecution.md +++ b/docs/ActivityExecution.md @@ -16,6 +16,14 @@ Properties: - `completed`: has execution completed - `source`: instance of activity [behaviour](/docs/Extend.md) +### `activate()` + +Bind the execute queue and start consuming execute and api messages. Called internally when an activity begins executing. + +### `deactivate()` + +Cancel execute and api consumers and unbind the execute queue. Counterpart to `activate()`. + ### `discard()` Discard execution. @@ -24,6 +32,10 @@ Discard execution. Execute activity behaviour with message. +### `passthrough(executeMessage)` + +Pass an execute message straight to the behaviour, executing first if no source is set up yet. Used by loop characteristics for multi-instance iterations. + ### `getApi(message)` Get activity [api](/docs/SharedApi.md). diff --git a/docs/Context.md b/docs/Context.md index 9e432c54..2b738a38 100644 --- a/docs/Context.md +++ b/docs/Context.md @@ -47,9 +47,40 @@ Get executable processes. Get data object by id. -### `getMessageFlows()` +### `getDataStoreById(id)` -Get data object by id. +Get data store by id. + +### `getMessageFlows(sourceId)` + +Get message flows that originate from the given process id. + +### `getAssociations([scopeId])` + +Get association flows, optionally narrowed to a parent scope. + +### `getInboundAssociations(activityId)` + +Get inbound association flows for the given activity. + +### `getOutboundAssociations(activityId)` + +Get outbound association flows for the given activity. + +### `getStartActivities([filterOptions, scopeId])` + +Get start activities, optionally filtered by referenced event definition or restricted to a parent scope. + +Arguments: + +- `filterOptions`: optional filter + - `referenceId`: optional reference id (e.g. message or signal id) + - `referenceType`: optional reference type, e.g. `'message'` or `'signal'` +- `scopeId`: optional process or sub-process id to restrict the search + +### `getActivityParentById(activityId)` + +Resolve the parent process or sub-process activity that owns the given activity. ### `getProcessById(id)` diff --git a/docs/Definition.md b/docs/Definition.md index 7bfc479e..58a73a61 100644 --- a/docs/Definition.md +++ b/docs/Definition.md @@ -22,6 +22,7 @@ Returns api with properties: - `execution`: current execution - `environment`: definition environment instance, see [Environment](/docs/Environment.md) - `isRunning`: boolean indicating if the definition is running +- `stopped`: boolean indicating if the definition is in a stopped state - `activityStatus`: activity executing status. Can be used to decide when to save state, `timer` and `wait` is recommended. - `idle`: idle, not running anything - `executing`: at least one activity is executing, e.g. a service task making a asynchronous request @@ -43,7 +44,15 @@ Arguments: ### `getActivityById(id)` -Get activity by id +Get activity by id. + +### `getElementById(elementId)` + +Get any element (activity, flow, etc.) in the parsed definition by id. + +### `getRunningProcesses()` + +Get currently running processes. ### `shake([activityId])` @@ -78,6 +87,16 @@ Arguments: - `executionId`: optional execution id to cancel - `[name]*`: any other properties will be forwarded as message to activity +### `sendMessage(message)` + +Deliver a message to a referenced element. If the message id matches a Message, Signal, or Escalation element, the reference is resolved before delegation. + +Arguments: + +- `message`: object + - `id`: optional id of the target Message, Signal, Escalation, or element with a `resolve` method + - `[name]*`: any other properties will be forwarded as message content + ### `getPostponed()` Get list of elements that are in a postponed state. diff --git a/docs/Environment.md b/docs/Environment.md index 2630bd40..fe708403 100644 --- a/docs/Environment.md +++ b/docs/Environment.md @@ -16,6 +16,7 @@ Arguments: - `strict`: boolean, [strict mode](#strict-mode) defaults to false - `batchSize`: optional positive integer to control parallel loop batch size, defaults to 50 - `disableTrackState`: optional boolean to disable tracking of element counters between recover and resume. State of idle elements are not returned when getting state. Recommended if running and recovering really large flows + - `skipDiscard`: boolean, when true the runtime omits unnecessary discard messages for flows that no converging join is waiting on, defaults to true. Set to false for behaviour parity with older versions that always published discards - `scripts`: [Scripts instance](/docs/Scripts.md) - `timers`: [Timers instance](/docs/Timers.md) - `expressions`: expressions handler, defaults to [Expressions instance](/docs/Expression.md) diff --git a/docs/Examples.md b/docs/Examples.md index f4941b2d..072c29ff 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -7,7 +7,7 @@ import * as elements from 'bpmn-elements'; import { BpmnModdle } from 'bpmn-moddle'; -import { default as serialize, TypeResolver } from 'moddle-context-serializer'; +import { Serializer, TypeResolver } from 'moddle-context-serializer'; const { Context, Definition } = elements; const typeResolver = TypeResolver(elements); @@ -32,7 +32,7 @@ async function run() { }, }, }; - const context = new Context(serialize(moddleContext, typeResolver)); + const context = new Context(Serializer(moddleContext, typeResolver)); const definition = new Definition(context, options); definition.run(); diff --git a/docs/Extend.md b/docs/Extend.md index 3a22f674..64c6cded 100644 --- a/docs/Extend.md +++ b/docs/Extend.md @@ -40,7 +40,7 @@ Example with bpmn-moddle: import * as elements from 'bpmn-elements'; import { BpmnModdle } from 'bpmn-moddle'; import MyStartEvent from './extend/MyStartEvent'; -import { default as serialize, TypeResolver } from 'moddle-context-serializer'; +import { Serializer, TypeResolver } from 'moddle-context-serializer'; const myOwnElements = { ...elements, @@ -69,7 +69,7 @@ async function run(source) { }, }, }; - const context = new Context(serialize(moddleContext, typeResolver)); + const context = new Context(Serializer(moddleContext, typeResolver)); const definition = new Definition(context, options); definition.run(); @@ -89,6 +89,8 @@ The behaviour function will receive the Activity instance and the workflow conte To complete execution the broker must publish an `execute.completed` or an `execute.error` message. +Note: `Escalation` and `EscalationEventDefinition` ship with `bpmn-elements` and do not need to be supplied. The example below is illustrative — replace with the event definition type you actually need to support. + ```js export default function EscalateEventDefinition(activity, eventDefinition = {}) { const { id, broker, environment } = activity; @@ -129,7 +131,7 @@ import IntermediateThrowEvent from './extend/IntermediateThrowEvent'; import * as elements from 'bpmn-elements'; import { BpmnModdle } from 'bpmn-moddle'; -import { default as serialize, TypeResolver } from 'moddle-context-serializer'; +import { Serializer, TypeResolver } from 'moddle-context-serializer'; const { Context, Definition } = elements; const typeResolver = TypeResolver(elements, (activityTypes) => { @@ -160,7 +162,7 @@ async function run(source) { }, }, }; - const context = new Context(serialize(moddleContext, typeResolver)); + const context = new Context(Serializer(moddleContext, typeResolver)); const definition = new Definition(context, options); definition.run(); diff --git a/docs/Extension.md b/docs/Extension.md index c1002540..82718787 100644 --- a/docs/Extension.md +++ b/docs/Extension.md @@ -37,7 +37,7 @@ The basic flow is to publish a formatting message on the activity format queue. import * as elements from 'bpmn-elements'; import { BpmnModdle } from 'bpmn-moddle'; -import { default as serialize, TypeResolver } from 'moddle-context-serializer'; +import { Serializer, TypeResolver } from 'moddle-context-serializer'; const { Context, Definition } = elements; const typeResolver = TypeResolver(elements); @@ -78,7 +78,7 @@ const moddleOptions = { async function run() { const moddleContext = await getModdleContext(source); - const context = new Context(serialize(moddleContext, typeResolver)); + const context = new Context(Serializer(moddleContext, typeResolver)); const definition = new Definition(context, { Logger, variables: { diff --git a/docs/MessageElements.md b/docs/MessageElements.md new file mode 100644 index 00000000..8e79a618 --- /dev/null +++ b/docs/MessageElements.md @@ -0,0 +1,19 @@ +# Message, Signal, Escalation + +Reference elements that resolve a name expression against the execution message. Used by `Definition.sendMessage` and by message/signal/escalation event definitions to address a specific target. + +Each element exposes the same shape and is instantiated automatically when the BPMN XML contains `bpmn:Message`, `bpmn:Signal`, or `bpmn:Escalation`. + +Properties: + +- `id`: element id +- `type`: element type, e.g. `bpmn:Message` +- `name`: optional name, may be an expression resolved against the execution message +- `parent`: parent element reference +- `environment`: shared [environment](/docs/Environment.md) + +### `resolve(executionMessage)` + +Resolve the reference for the given execution message. Returns an object with `id`, `type`, `messageType`, `name` (resolved if present), and `parent`. `messageType` is one of `'message'`, `'signal'`, or `'escalation'`. + +Used internally by [`Definition.sendMessage`](/docs/Definition.md#sendmessagemessage) when the message id matches a Message, Signal, or Escalation element. diff --git a/docs/ParallelGateway.md b/docs/ParallelGateway.md index 65d18684..2b1e3e0c 100644 --- a/docs/ParallelGateway.md +++ b/docs/ParallelGateway.md @@ -2,28 +2,11 @@ Join or fork gateway. -## Join Edge case +## Converging behaviour -There is an edge case where the behaviour of a joining parallel gateway is not clear to yours truly. Suggestions on how to tackle this are appreciated. +A parallel gateway is converging when its inbound sequence flows originate from more than one source. Instead of completing as soon as the expected number of inbound flows have been touched, the gateway monitors its upstream peer activities and completes once they have all settled. -### Case - -If inbound sequence flows are touched more than once before the last join inbound flow have completed: what is the expected joining gateway behaviour? - -### Proposed behaviours - -1. Ignore inbound flows that are touched more than once before all have been touched -2. Collect all inbound flow actions and complete join as soon as the last inbound flow is touched - -This project do the latter. - -Both behaviour comes with the same caveat. - -![Edge Case](https://raw.github.com/paed01/bpmn-elements/master/docs/parallel-join-edgecase.png) - -The success of the above example is depending on how the sequence flows are ordered in the source (XML). If the flow `default` comes before `take` or `discard` the process will stall. The default flow will publish a discard initializing the join gateway. As soon as either `take` or `discard` is touched the join gateway will consider the join fulfilled and continue. Thus, the second `task` outbound flow will initiate a new join. But in vain since no more flow actions will come from `decision` gateway. The process has stalled. - -But, if the `default` is placed at after `take` or `discard` in the source, both of them will manage to touch the `toJoin` flow before the `default` flow is touched. +This avoids stalls in the edge case where the same inbound flow may be touched more than once before all peers have reported. The outcome is `taken` if any inbound flow was taken, otherwise `discarded`. ## Events diff --git a/docs/Process.md b/docs/Process.md index 9ed7e863..ffbeb1e2 100644 --- a/docs/Process.md +++ b/docs/Process.md @@ -20,7 +20,7 @@ Process properties: - `execution`: getter for current execution instance - `executionId`: current unique execution id - `isRunning`: boolean indicating if the process is running -- `logger`: process [logger](/docs/Environmnt.md#logger) instance +- `logger`: process [logger](/docs/Environment.md#logger) instance - `parent`: process parent - `id`: id of parent - `type`: parent type @@ -54,6 +54,16 @@ Get process swim lane by id. Get all process sequences flows. +### `getStartActivities([filterOptions])` + +Get start activities, optionally filtered by referenced event definition. + +Arguments: + +- `filterOptions`: optional filter + - `referenceId`: optional reference id (e.g. message or signal id) + - `referenceType`: optional reference type, e.g. `'message'` or `'signal'` + ### `getPostponed()` Get all activities that are in a postponed state, e.g. waiting for user input. @@ -62,6 +72,30 @@ Get all activities that are in a postponed state, e.g. waiting for user input. Get process state. +### `init([useAsExecutionId])` + +Allocate an execution id and emit `process.init` event without starting the run. + +Arguments: + +- `useAsExecutionId`: optional override for the generated execution id + +### `shake([startId])` + +Walk the activity graph from the given start id, or every start activity when omitted. + +### `signal(message)` + +Delegate a signal message to interested activities, e.g. SignalEventDefinition, SignalTask, ReceiveTask. + +### `cancelActivity(message)` + +Delegate a cancel message to interested activities. + +### `sendMessage(message)` + +Deliver a message to a target activity or to a start activity that references it. Starts the process if a target is found and the process is idle. + ### `on(eventName, handler[, eventOptions])` Listen for events. diff --git a/docs/SignalTask.md b/docs/SignalTask.md index 7057d313..e1f09aaf 100644 --- a/docs/SignalTask.md +++ b/docs/SignalTask.md @@ -7,7 +7,7 @@ import * as elements from 'bpmn-elements'; import { BpmnModdle } from 'bpmn-moddle'; -import { default as serialize, TypeResolver } from 'moddle-context-serializer'; +import { Serializer, TypeResolver } from 'moddle-context-serializer'; const { Context, Definition } = elements; const typeResolver = TypeResolver(elements); @@ -32,7 +32,7 @@ async function run() { const options = { Logger, }; - const context = new Context(serialize(moddleContext, typeResolver)); + const context = new Context(Serializer(moddleContext, typeResolver)); const definition = new Definition(context, options); definition.run(); diff --git a/docs/StartEvent.md b/docs/StartEvent.md index 8dcf38af..a92b6f06 100644 --- a/docs/StartEvent.md +++ b/docs/StartEvent.md @@ -10,7 +10,7 @@ If a form property is available when start event is executed, the event will wai import * as elements from 'bpmn-elements'; import { BpmnModdle } from 'bpmn-moddle'; -import { default as serialize, TypeResolver } from 'moddle-context-serializer'; +import { Serializer, TypeResolver } from 'moddle-context-serializer'; const { Context, Definition } = elements; const typeResolver = TypeResolver(elements); @@ -51,7 +51,7 @@ const moddleOptions = { async function run() { const moddleContext = await getModdleContext(source); - const context = new Context(serialize(moddleContext, typeResolver)); + const context = new Context(Serializer(moddleContext, typeResolver)); const definition = new Definition(context, { Logger, variables: { diff --git a/docs/Timers.md b/docs/Timers.md index 9b62f72e..aabc67f2 100644 --- a/docs/Timers.md +++ b/docs/Timers.md @@ -2,7 +2,7 @@ Timers handler. The purpose is to keep track of executing timers. Can be added to inline script context to override builtin timers. -# `Timers(options)` +# `new Timers([options])` Default timers behavior. @@ -12,7 +12,7 @@ Arguments: - `setTimeout`: optional function, defaults to builtin `setTimeout` - `clearTimeout`: optional function, defaults to builtin `clearTimeout` -Returns: +Instance: - `executing`: list with executing timers - `register(owner)`: register timers owner diff --git a/docs/parallel-join-edgecase.png b/docs/parallel-join-edgecase.png deleted file mode 100644 index 5ba7e6bb53e4d2cf879480fc1ebc3c9f549cc8d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61112 zcmd3OWmuNowk{wlp-4(fhk$^fASoyf5~2c138F~1(xD(7f`D`g(kc0pqBM$tfHX*V zcb)NouD#CLYn{E%{&oI**CpTkKJR?S9CM6&+~Xe8M_Ez&JPrj88XDSpSs4ixG_=#6 zXlNMMvChC>ZhJ_1p`p>D$x7V1Z>K#!h+U!Bb-2B&APWN@s{|H~JGN23$cvQi~{{+Ri1R)!|4oAYlBCPpiU!RUGF z`Y#)jfAa}i)>htsWk}?2m@;n37H(&vbLjugCm21;&iu=b5<_!G!wx3K`|-H*!Jn;c zeE7I0M{9M|i>4W6JEuQf<-FR$Ro&PodStSXeQ>lmSWYK_h8~3bj`g0DFDVyioiE9? zL(1Kw5GHxKFK^DL$c8ej6q`H@+6r0zyL;{fr@?NXf9xhUf_b<*$F;NMdc;oSx}Wc~ z-Y#A5T4FXx!GBiJ9}Q#Ww4%TSvB1`V^+b&IckaWO7k!2yTsk*P|M3RH;5?h(lsgFi zELnyzA=9NHfRcrXMe$v{%PwpCs8b-=g$#p9?p?5UrGxC!P-Q?^9r0gpt(gOBSKfT} zHRz9PVxKNH?Pm@WUiB6}+F!Gp{*ma>V2%7ge5C~C#M@SL*(J?2?x#|2d*aa2{WWqN z2`%e(?{vSsY07`na3wR;7v9_5!rgU$jE2YP=jF1kAxHOr zoIGJBF_mBUzDVZ%@ws4svAxZOr`=f(o2V$P{i`(Pj^1(UXe$cNFtR?#c(|3un;CMBXn zAk6x&`Q5X?{NHhe0{(cL+a(Og&H1;g*^ins9%P2(9QGOK@`ltTips_}x?|Cf$h#|B zsUHcwTpUQ=OWO)A8FG-93%?S%E>&6- z+Q@4*pkB58+s`94fmAsxeT%x4zvNZY_G98t0I)KGP{}KRnF{J)~CEPlX12X@tT3H10*2t;N9*yUf{ zpQLG=e>%x3b$(PZHEk(YRJK$-Efqw~aq28yEB6~=`_;zAw+s_idy6ebG1tMThe++F z6TS2sgXzkuzFI*PuD_6Q`R_}*X~0XC+v^Y^iVJ?bjy5 zz~7XdQsVvPIO~@8ZP0NY|r-EtSOEr!}4=SpD5t+6S<)>Asf2$i`Z` zGs%ZHf(Nqsk#g}JK4;ZJ6_$lb#0uIbKgd+&#@RJ4WLL|1XI`}rTPxtaLUsCYhOr2RO}r6sCLamRocPmSnGttl__-To%t}YkM2a{T@9gAg zm5(3pEs;8NYb9BY1>9(U&;4XPIaJY?|N32(?cD0akibhqQic5mPvz|wih7bCe||+^ z`z?xB-mH9~n94Ow?LxQtkBx;DPaG0CVxIW&`(myS%I`$-AQARG7A3C{W2S0$$XKAz z_mp;`ix^nj3L``jr2M9`q6jJug~h@XsPvCv?9bQd@m= zSiXXhYuaDTbji8=#lm=)nzpPUYZmq>rxvOaGM7o5HLQ%ncDyZKG$~HQyz)Vu>)}qa zUi!mNACc6fQlQ_I95_Y$5?grl*AuHYk*%-ijd}~7S`FDxm9alg0v8&_tvEW|v-*6R z^y@zL^19vWLjp8CY<#ZLW zhMm^Ft#-(BMK&0z*zc~-aA%4QJIrN!A3P~?(OMZOG`t6~+$}%5Zo2)$L>;Nl^|=nr zZ4YcBD$5jtIm~s`Wu2;u`QA?~A3GrLQ1nM2rgS&K`kAXEx+o&EMcnQDV{M`(A|UTM z(O3*F3)M(rNCJzty%-atz5^hcQ0OnvnPjP*OZ8^B+ER9p}*x^qH=V@DU3?H)Ro4d4UU^8kwF?>R5cj*P3?KLkGWOCVbMwCt5xADwhJe4_tqzIwK z(l5f-!8y3fJ4qTxHEvB0Z!q127#Cpp+mlo~Si`KWZhv>SD|4c-Q_+voH;1Q7#Gofv z$J{Aris=(g0j}5OJh~a*CHGTj>(_O1xwS;7DzjxCCreI~ zGt^kpI(6opg)lP(prsQ}`3*>G5_OC-z1f2=vr-AlhGs!teCJETK6!Zuj(7{XL5wbQ zFal*N9k=*`E-2y5Y3HFj)Ji^Lg$XTH+^Y|wF*lJV$X%c7X>p zM$SMaGb1~#hpbHVaE^*@o)`1#Go7hHJ1NV_ z7Q()DexxnnaxouN;1KJ7es#KjYWKy~vUA{AY@uEq&ciCFGJB^A5-m|GohHs~5Y@FfnNIW95oP266{y^y@&H%FRHE%o z&SQRM&=zNEf}PmZtuL1$tLuC#s7m-w$ysl;^|}{{rdL7?MR(s1mcNvr=}74W$U=4T zSFx!^U}nb#MSIw91pd)RW1!S3&F&HBE-xwYNxv!ngHdTUk?eH}v5AA(Q6?Dt=njQErYm4p$UfcSJ>3rkc|1&vXVjD8T?fv}@JY0?DsQ?QSj@ z$6c&+{t8g;DL{h`BpmN8lzbbzp6>+ct=`R0BayUW&~7ZiYN>MTqsOC42U`Xy-@Vh+ z_TvO)kU8}*DtBiyCjju+xSsXKhYE}?;mGA+Z}=#1hMg-K_v><}?1>W#(?KF7`XUjG zEOHGwaHzf+)LhQBQ{|g|#uLafB2p6OHp@e8d^tSW3usHKX2ny&@v7cl*juWO00)iU zn7Mdi*k#Z34y9>dA-B$u^+cFjGX&-dVKNRudW)^Wmo4yeib-_@rWCi(+-*)Dl`WgChl-lR)f4}`78WyXwmlLQo) zNx8Iz8_?|+%ck^yfAvvGkt0ceRFvUQ!7GPDe0d}necjO9ta3xu{%~jNiNg)^A>p#w zj7+CKW0WTvhBndrYX*UUSp=C)oCz|jh(llf1MX@da97%G6LG!>oaY^dYPs4{Hlvv@ z#Ybo3yraB3leo4zBAn{jqpo!85B{$6`xeCOE@Zd-cx|bS$uo#rgbiLQ6ykPtgS0ur zO8n8jG-ug3;hMGc++L{CP4XLY@vest*&bx*=RCT(H~(n@?D=BmGQMh|*tRX{VQ)u@ ze88LsvYyggw7bJ8%6FnJyBuuv4C2#s|EJKQ{Ml-E9j8P~xwVgK+qKDh!HpX7ctNiP|P$o$deNGI~P*D%sna#}g|7x8!%|{4{ zEMSE`UfDQW_Q%}tqH%fdV!AosYxU*)4GTIuiIM%awji=< zJXkKo~=>Mw`9~hd4O2 z=GAFj1bh+D%ypjwn14fidIOM5%V|kD~O4|T<*5$ssq9Cy&0d$FJ&mo#sk7_ZAte-I3UR?G3d$>aq&(H}15!)6Q~BYVAm6yZYsVC}!lFDu!cw{s&Ax1p(RO zgPU3Zj}&>*cAeMfxe_r4bX*UZI#ZQy6dQUgQqQfR=;d@|dZ1byn=t1!`gt|e9*%Lq zgN8@-{^Se?ds{aSb*ewc*Rex&p8l2$kK|y|VXixS6>!9t{l2B@BTiJ2XAXT}iQL0B za&A2jf=Ou@(f9$)R*-BL??GF^pGo>_<&ML;A7h4tiMlS0PTBV9$pJ9u2Y<3IVGH6 z{gv@Ng6kOW#3L>wjk>9wCr`AKa!bxLc;hSfCqcO};`V@>+ey0Zg{evT@}K+}>m%@0 zj{}7&rH+GQO(+KALtz0E%m6Xk)1^A6t$xj1KS}d(0P5x=6X})zI3I0OEkY-06O6b_ zguSI#Jo)o0R>(l_#}so~*ZROq?DnhU`66N=SBi-`!8+=UH3!Y~ zG8unMPYp0tf2~}~$+m9mBtWUcBFaI-$I~Hl~MG;XP1yEP*0S(1TXD@w#Cl! z&Ja0t2q5bKk|`#KYU+e9!nbe-s-gMKc}jZX+3sw1@i*tVL%zJoqGE0$T=olGWEi1? zjiRQwa{I)Tv~CEk$UkjEe)2eWO!zAE7q1IJ8V{g4MQXc<7Ylt4qu>F0b&YqSuHvVI z^ByInb?D>NkEm5Gr>32xvhResiBBvQEhcQlJ8HUN2>)6 zG1F{Ged4_6q%usbR7n|kKfKAeDuqmBhfZ(DAbiNVKZi?3zQ#A% zB5f4tFy9=iMaZ@}O}Zgh49}CW(7B0SghTQaJ(l^;!KO8Yca^AA zmb z{j~YrTfno@yBl+)B_fk=8NP@y0P1-KCyqFe|8G>Lf=oEiFL0jTO-%Xp_T<$xhNWQ_ zp|`}{`pXEJEgeLylK1$QOX=_77N0n}5h3)$!L7mI4!V=wazdzOwJ)*;up8enoUErO z+v$pJFz4^!L~v^L$($L66fMQWfB(Joj6d-dfJ8pTvBhKg{yO$U*uo|`ODfpH;6$`x zs%Kb@GdVzb) zJp3Gul^(q_sd{5O+xr-H*v)3_}9PjGY8A5sE2+= zaFps9Qcg|&1+qwK!%jAK5|(Lyig-&^V{j)m&;VqdV%i1l!{_~WGlNUyB} zIe=7zBhlhs35NCDNGyit$kmX~C?5V$eT%evtqcusBHqAJ5r+(NbV}H6IU!3u|8~?3 z^SDH#XQ@3I59F(W0s25V*m4N`O>0&y)ps)}d9SGF)ok00H@@Y8`b48IQRT#YcmQz3 z_)t$F;Fc9@`I|0|I@K(;`#?x-)Val;-1zmy!Tu2atFpREnuM4>Xc)Q}`{hTjWKmQL zLzU(C(^VvqDj`do0m|)AfbW#t&+kAzUceLwY;t3*CvE@=NF`24BSk5f*#0CtBCuTK zv?V9vaIe7OKDyN<#^HNM5OZo*l)gQ;2-HPN(_?@drHoh*FJy3}HBbGiYbbP#`wCfQ zb)R9K1RPGJE0gq@7C3|D64+4JAai_2(l|Ie7EsU!gngFuyI2(P+FqZMg9J9Z4r3r! zBF^qN_Si(yEqNT#^&jG^K<<(sEdEG*t?7EOaZyL>zSr@7{8Km)qh$r>y5sBfT9`3G zc64Q|fwJkb7P*N55C7L%;ng3fZ>M2lY64WU2!+aKeFmv)+}xxQ?4_T81t6<}tLBE+ z5RJG4KI`(%RJ=SG>yj+E*5oX5DzKNAZp!NBYJK|Zhx{`B6)?|d3Udee*F)lw=r31( zcNUsszL%~dmlJ&DwsiWHQ}v?)eIF+v?hEWz^u~h1A#+7*$U+-I8n|c@>+|!&)jHbt z6C@8y%wnBZ>PQQoG~lJH<;KN0%%<1JLlfaPAnb_EqR?i)N$6P!*+We^k(pb?^IO1b z-21xG&&F-*?*dbeWm9p{PpGUXTi+@~^O48TX*WahU2LDVX$bs&{V)J>Ry7^xqIoFL ze$GSf8ve8;oIF0(vYy-u7AFstgJj9`q?5YuaS?1!reyjBNHUGLXd8#AtnSi24ntdO zWRsnRGgXef7jSyV+_v;@O0&{i&wxa7IfM=fnA`d8Oq__LmGDx<+V@ak24tZd&`D7R z#{*%Og%7vKk~A16RFSUT2kD@2gxi?R`|E?b7iey3BJ3OW8qzO?Eim6dXlBoSCrxcH z!CA3fOSPv3eS=7$mpN}4k89ZfJt;Oy9J05M#I};uJiXMM_uZydCpMKY%BUyI! z*OMS}@$Nib@kodUD@VI}9fVABWJgDTh=&kwUFT6x(sAIa!+4%HHv-1gZ+^$R`jtrO zeZ#aWF+%nXJV2Fc(I9jY>LF2IVp6}5@W#)3^=yL}r*X*oWu9XQ6*9e{PHi$&Q1OZY zUO#b-+F_dR$%I9|UY$Nbn$_tKLCpZDT8%!aQ8_-P#yj&^|sC|+FjkB%zP1?i{-BT2(8xXt|TGCLltEeJCo7%azo2j>(h6iMEhYAF~8U898Kd;fPBZKWhb$rDG|ki9A4ZmmO^OTUX%aluc4t7v)p0_nTMOF`8PJds{(N zfrz+TbLztT)LgA{Rf_A+@k;~;U#f=|CLRRw+Gle4;D&+W%9u(Tf@rv$ch|Y+L?9>R zPGZF#r8&-XWsZ1hPKtuJHm~%l1!!zsaLZDr7rXEP^s2}G^27~yoPo^_^ zMqGJFPpWBgYv3ki2r-BsPhCD{zFQk_3bk<+0EQ94Oal8vM%W<_`GnSvvb);qj6%4ba5ztO(@7oSKB%uj0ma}RZPLWSs+p@T^03;a@@`nw zI&@|hTZ$ejOwL{;N-TgbHmh1r%t{Yf1!Z6biytda;mU{T61me01Q{zZQ1Zp)RDa@f z4#2ZAF$Ac3A!(cLdDKb~M3J5^@>BTBVQ5>KUu8#K57*+8GM$SCUi6!;wq9#vtT?ki zVV!77DHTX%Sh3B~8*&d4b@nLxI~|vur|n^1%18!>ZwNbEBs zxwNm4>Nr_8%Z?7H9)%DqIy^tw3EK0J8VnOGk)A+sAd)#h)C*uq;9LzVr3duK4%v;6 z#glg>LqqJj>@yl2=k`b2aVSJ>0kM;U9qAHWj=o_Y4!hhGX%I)g#gnd{p9Ep&+xC2* z&|)yO(3^#Gp0_6zxE{HTEk(t2GuoOxg>2PPYWZX>7}}ni6ud_I`yycr43ONON)aKa zdqfmgbx3*70V)Gd50ON?)^`1WBF4k6d|vYPCewD1*GkOH^!AG1h^Aa%#8d zM79PPK>s0=lV7n?PiX~-E4pD?ewFQh+T;D$WQ&Bw7ecO;`~EFKy;?b_q5H_TTX2H|#Z&5fbofj}qr{A4 zkd3}V7>Hym=qg0(IKbK_fZF9dx(RZJ8F;^)t%2fT?;*h?$E`&k!w$wZO{m@!nb?j! zI}bcNPa*FBUNB7Wwzvvq|~;d^jglQfc`tD z{d|4{z3L3o2De+$m`<^AI0Wfg3K&@GfqeLtx6o3I?$WmSd^$;1TY;Vi0tEDJFO@+r zf}yV~tP*-uH>x)w)wdwM_Ne9aVWir2x6Dv8AHCOZ?oKm&;2dn=zkj{=QdJPQtggW% zS@toi&gVnBP0=@UA8sKT99l8j5*kr% z-4Sh)5z}FniEX0Lka!>Qlh?HG{`DqJsLdF3srq>6ZN5WeM{-LFj|)^wJn}vWy@pi` z(fo0cXeD^%St#y)+%kz;&4zeYA}-&6zZ?rJ(p#hn0G#rrx657b-Cvi@s}G(9?nLOg zu*M3#42ND43nZF~RXKY=atx|Fv$CKS34_M91Y^+HgO85*Tw18>llwpN%_}#;^8+O8 z2nACUu9FMvH{x4!jsCD?^d!P#ID2faQZd+J+%xX@04>O%Xd&~r{1~wb;bVRyg9^y-)e(TE`eFj0xxHoS=Wd}yURUYoJZT6FVNr@J zJym2qr8v|3$)MFpTST3xUBqEM_$;-Z7=+Mwb7ICOyM!nK>&dSQcypTsyH-M4l2p0V zv(L4dvL_O~s6%eOJ`?Gc4K)lvPO7yfK;dd%eW#XplY$<6aN1dY`0}j^5ri2xu>=4S zXC1a@K+D0;3XxaQs54v#_S)sr!(C6eBRJBMfirIzr1e4Hrjj6r&I(QS{7d4BPoWej z0LfQx{u8elr`0BvbQPvCr2wgZSW?ufG>;O_>L5}Du^$?YvM-- z_Ii?l^z{FY;Bmi#lx-J(7Ez(@5lKsL!WeBNVERPv@PkabrdHlQ3(mO=8H3YcZusz8$b7X*8$4s5k zQ_Gf>;M||>uv3QZID0lAm_V#18pBNXnf<+>G=go>zfYqd3@6quf02z;Z5~z{D!&$1 zm{7GcI4p#}txvoV4*N^U(3*6xG~g=W5duH8qHfh(Jb6U%IdiEnW;vV^(|*;P2kZAf z1R!0zk9Q(N?mGG?9s-^phnnl!1r2DfYdXxN_$XS>TbDFMV7*GVpr`v&slavuM14`;uMh2ef3*(@Nn1>E@Jq*VBMAy=i_r&t$iEUL|X{Vs6gt+XSq=*2`N!|%T0{Ooq5;&6|d23>=uY6!Q#u!#0cNS+UXftf>{Jv|$WY6r-r9#2Knrl1yTj6_rx$qsCXkJQSk8nX`;%UsFDO1Z#srnF-)zbu zJ_P?AM>H?bwHvt2hbpieL_1FnSXDO{(!~7L*B$~@J>O=Tq6UZNHgaf26YxW(Fkv4; zWO3%?>(`%ZKhkzukt{=02$Rv~;bqoS^|mx1r9DS2{A+t2lGa-gdNup$oYIl?@RLW+2;_Y(1}XpG^n0oGBAW;j1xanQ zEK4jS)Gxd~Sxt5v5t>#$R~{8!Hgk@uq2@JuhtOGBTtn^vu26_rE9vMw7d$^#cz60k z+2))NOI)za!EPPZlN1d_^khn%kDQ|`CIh8+K}qqJs^NZ6moXyF>_`+p+Z4*8bmt}V zeixqh6&fRx*&wvv79mFJ~;RyBS)MsQW zd*NMT1F}MKwyy(oB2V{=KS}3`FZ0s+gb8$)n~JIcGx;&!7iSuh8`Tf-hAu7;x+q2x z$LRzgA{M!}IFWDGAbFrhpqEv)xbvBFWRIzz6ls_Rq!PuGa3;RDd9Vy4eLKgw8)YS{0CwemOpo`U<{q z7lF{zH3Y?(h%cxp;7Bv5rYV0`$4+Ng6VKETZM!Wsmh3<7if_iUL0lK;(&_u#BQytP*k-pK0SDw`b=Y+gVLOjS z3S`%9LTgb;8^E^`E4(vmH>F29AGoBP{@mRQ%r-g$%Jg@Mf}#@6Dap-dC~2Li(*Dil z8T2jeO?!Z@17AmYg3dO7#=K+wx^30J1MnMFBT~B2_F%CK1Oy^CTW0O zSn8`P+u40OWpTDyn5m&g2TiB{|?d z0A%~M@;m5nTf9l4QM+3QTf-4Qwn23E01?W>Wnw=Y)F`!E`OUo{Nt1atIf}U3!*RQ1 z={mJmEQL9jMz#*o+NiT%k2a62TIQfiL8ag=Y*^i36 z^+zvA|m}XTebH-?;D#7*uJHRqOuj1VU~s<>4rkAnUwD zIiUOE{L^9}0r>$$@{~j6jNdxs3Ipm7TocAW65Lm|Snqw5fia8Lw)Hx5P-o}_Zp<83 z?5-9cb6M=_wp~TcMYdfl5T25OI1ngK?Wgs~HR}p%yJqm+pZ{iLa%PuV`kiI{-=F#< z)r!1=KIH6ocP*{>_DvUMH;sa_i;}$w#H0q)6tTqJrYttL_S-Gwwk>#-hhJQ4f_?9P zY?!oxtf2i}nl=ps_050rT5h$hao}fXJ1rC84 zQ4PX@jr|CVL};j-h^WOS2dH$S8(L$9)C$cXC2jp0EHT&lDmOIkYkT3DLY5au3P+cB z@u-ELS8OY8S$JUg8e|T&JWAlf9VaJmA@=EYK?rrY|g=NcJP) z*ne*g`UEwAd-CalkXAXt$9NJTV+D+n&g^M>0b&PTYEq_&?bGCogKW2SjKc4=o4*mq zZj_MKP3;R9dZ~IuZJz11d~?R{SDfRbz?wX&Br9jTi!g3kew-j90T`EOA$+097Iywo zw1IX^+?Bj+KNZW;63)@`_PQ`DmASn4G7)fy<~hNjw|bGGbznOL z)w+RA(_eCp%yv2#%S)R&b&uV3v)2H74o`0ZDxm9e86!27U+FJ4 z)V4wu5+*$onuHX78)DN;N%$-%J3{~nfk6*4R|OWP2A5E>AIiXgJGt$i?;UYcTc zMRxRlA^%19pMZx`C+pggazGeC-=zNneIsCDmwn~vaI5+fpn@(lK!^GO^`0GpUL|^U zTMhbaIaRwxV-?F`wLZl)SiHp4;^6!M8Yr+w0c;7F4Me@~CXJo(Teg`fIAn!*Q}2kF z8OH%sutJ)(PkvS=*=kQ;xO2FX>smLcdON6xLt@t{w1QW@XvveaWCso8-uF^S( z^k3zxkbx3^RRa(JssruvRNJ%3X^kdMMv<3wAF?i`hL}f$<5Fdh%vI3YU7Jj?rU2oX zed`yXuQ(n_+sU4s+)lp8?RkqPR;fXAJ0OJX`4|EI1of6Y)L~26GxU_A8KNbd6ztDPL>>TPsy)2&x3zfZ&4(~Apb@xW`X^brxWGt5bBusBeW23GdxeS~Mi~OqEvqJ`dcQs^_7744Ay8{Xdkw%K4UgVetg$7O*F0Fl z+~p!y6Q%YR=nk*IXk7Eg_CSbtkx`egdZfch4Z6Un2a(meqm>4l2v~3b{yqZOV0?`I z_x5yhrdeo0zr6=3l8Q$m6{oZyj6PD~lj|jAD z?>m7iIf+ZVGf4-=K%RdsgAT-7=#ka`EP=VZCtZeiTIo5&fkW{x0D2Q_l`cztAnM+I zSi!jMdbFqWWNB2{9u(5aTIDYYR^SLWugfvt%+#vYNlVK|&P2T}e(v-}!Wadc1BYiW zbsGn3*3@+KaxKt4_5ywo@4+lWk{lktEJB~0yzIue6@)Wq zO~sA_h9cV49C(A3S{e>`t%yW%FTv#bpl5_TyB{KEHflN6ypt{TRn(=e0UdJh6%WDG z9MYJQfuXx^=sLwFkw_T;6P3?g6m+g`K|Lp>NxWNtg2GACiNnEMU4d=3`#eB-Y{+ts zFwh5;5?_CZATK(3)gz>Vk;LvOWHXI#y%J|X83_op**n)2IA@je7p7~*Q9t6Y8-}cO z6aq;TtwFB75I)~}Y!RSzn4x?3i9E?{?kW(|WiT|zPk1H7fc)^Q>M{9Fs3#?R? z&Jxqf(_PbjLm;0?(QgWA;(2Nl1Jysd?W<6N#sajp%PptG*1$5x;P_S4+JfL6W`xU~ z;-*Q-OtPb`ITaFBkzI=mp9T>gp@G?RqZtLlZwZ)8liVWZ)F{q+8;q;8K4XcBSO%lg zLlp7jSI`lD0acY$g$1Wg1+y-1diq8kJG?*8QwQ%wf_dH3xPm(w7vZHCis`-0?mK@xHq8)CJ)h_ic*o z*QZdwALYIUS|W0a=@Dzz*+V!&NZ(FUlck+KFmyw13W41nKC#v??guWx!Eg&l7Jn($m-G->U##p)$Cg>WsJj(8b%0>E(!29{sNLzETmf8^SjjB_>~yja3`8020r# zk_={M+d31wCe`v$?&*y0Fw!tpic$^zysK9VrGsqZZBMIMWmKOv^t+R|Lj4pOXK}O! zQ`OW4XZ^lvJ1+2k$bpVP6HH{$&zg25`;aRsatU;D|Bx`>9%>v7o8~tf*zNc6ICZuI% zd?}&9z7*PO_a?A%D$a2{zk%9sdAQ6v722#U$uBE4TqqP%Yo%a!Qsbv_}iGw|~3POqOur08T-8*@E3>Uq27 z7Ggl za&N}|tY%?@InoH=ytJU>dqmch1j2P$AZ_&ajb4JFACWqIEAoZlNXb>#*%cmDx(l^! zK;^9sNr@;-Bj_+sQ@;Z=8`SRw#aIiRant!r4nWzFRaYItcbkxbhp&ly?88h7067Rl<0l^eV8%Dys z9vy@|8Z_o!H(qLw{i)N_oouk};!nwE;{A*0I*jhE_bdWu7ipo?1bkNCFUspILIL8g zPlZd8WM{~)JtNB``rx3De zr9*QQ_yIy@;}2eZVaa)izRNJ>Mv!0q%q&9A?l$j!DWuL8V5ve-&FgB_qR^BRSouoy zZ7lU9oLj3*dExCs5SP%odXa5ZR`(!^`Hk&_l})?zZQFRYOs9J|eFkS8b*Xp!V-^8I zMuFKnJjSkL)`HnI@etJF3|MpFQ_3@_F==nt;3AHqsy6(_H)padLTKg%9%|}CPU$5c zeVNwAk0Hd}5!Vf46B%c%+e8eqY7oXY|KPQm#>&X+3sF9X3Wc+{k%$JN7~(FD05p*4 zfB$f}u07a&J2V&MXuPV6Z{%P?M?#I-xV=)A9s0-2A8nbIzxogbtZk&I?dq`)%ISUe zCRnYfG=Fb90K=U1EpKl_4NtY}0R5#2pjsjz?+>eFsdKMMK33g1V{c@yOMTkjX-<0i>RlaNf?_lP7?u}^u_k-pPmIg zr@w)k9;yZrL4N*H{zV1GIk_oip9o@vIUN8LP*3M@2=t2)!&f24x}Q_$59WBkHQR4Tc0pR z#;HZ+m{>LQ^(3uH@|cx)eJHrd`>S1D#}?LLx+e^mvs4UPoTgMC9aqEI)xHZ)K&R)1 z>Uuppzu zp*~LsQ`N@;IaPOe?c*3{qx+}sCT;J)(R;-JY6Jc!3Q7w^kEweN%hh}^MclO2W0DJhe=1on_}+qq}+WsU=u4NO!4 zFl+`*x`x-gzIF16?;?H~}h{V-}ddu|U9a1u1Ozpla+tS+tl3 zVrURu8&xqXs1*U*!QVjOubmw&r?Q=0GQ^`gB}J;`=?H^al&;8788kbc1~zR)^#&u< z<=2}B?{EqzaGE2tGqx+h`m^t<2xvW|I`~}*(oPhYr5%QVFg3gLwVBkOHrqYnRTS3> zA@Qr4&Bk0a0%ekHWI4hEfv^lVbi&4F}j-nd267$MxL_X8AH)pin6GB>;xa#(-< z^&&QCiHcO5Sv4yvJ-$#PI=y5d90)RBZL9&FYyvSrfcVB!GnAG%>X;TpRFqsjeu{^a z_YKTsM`4K?0J;gRGrFo~HhV5imDyA8e2%yYVd1}6RE`pkwE63+&bv145rq?~kl-1B zKIg_mlwVUY#4yT)Q(u_BeT@SF@%Gy-O{Bl#k2c&B}!8WJd(Lm&nQ$yP+*$)-i z$w&#NIz)Z9v++4#$xj$&u4(6kltPO@ZU3F%vcrV2pzNsf1k5dEB2()1esk-d=0KYJ z8LEYr1c_|EU$KSh{pZHG3VkqJ&N|`lKNO+Pj#c?XQRkvswTpAQMoA9Ryk3QCJ7lBz zOk4Rnpk>jdy8CfJmnL>((|(-62nADDYqgz9=qza2f%RQ!_j}TR|>Q8=+M-fM3 zW^O2R;IMJvX3#uo!fA+f5D3|G{fRA64?)TVqIy2~8wz4cZV)YURtzvP;|-$hQ%%MscRh6CI&pbOG`IcPg+ z0LO!ObL#;3ivZJ0x4GUN3mL%$E$8f}VqcCU^NXSY&0_bVELd%GJ?z}?11e!0_FrMv zNknFkMowRPi6o{ouGS&$e`e#%rtkNZM0oWyPCH|3+Uae=v_ZXGKcpCGF_vhM7?!8T zSoxNjTfmt1#D}1pgoBUhD)u4qb-;ZF*TSbOU#H%Qq=%GsO=)Jhx>|UD`HK}q%t)Qi z2aQwlu2p4n{Dr4IHxp&v(ob3EIK;dSPYS;WoKxHHX10#{6EN>Cz`kY%^GYjL@V2Vc~_W;F){l z;RgJ+fw~;D3Mvz+oR$!`B)Xh;P?MIdydvC5FHhLEFq9DReq|XT$N=XB;bphTWW3?m{J<0!>w22k;_Ypt z<+d`=TtL?XsLBY#hD_LXx>)1%fCE?m1rBsb(*pQ#j^^foIysdV+z!HL4?U-Vl0t@39uxFf}%O zEX)Rkx#U7Gvizw<`UaTk_a7^0ivoH?ZX|dwXd_urzX5JtXIgDL*IhpagQ>yLIeG|0 z!80nD0-0)pF1-JdsLgaRG28t{VV%7Yjf%um*EY_t{#@-4##!ZWe~F2YKk8EV0GR@6 z{m^Fi;b;=4h`B!(gU^9unp2ts#+erO>|aQ?3&`HhVzAZ-O4E_3F%ih+2{Ij%@@)Ei=$iQXqMyf3c3xi?L&?)BKY&HN}b(C2f zu-;Ab@V_Lax;ozU#IY^%4=DLN=ZakjX8Z9)X$s7S3_E8pm!?$5b3D;0C z)rgxWyb;2W&4%lGfZL`^%7vpGMkoG;tVvf$74KRQhNWS zu^GjAz5Ls>k;xWmmj;b)mxRHUNa9lPjJN;$cd7A?tfqmMlc3QhokbX)I+~OJ62)3URX}%D>`IX zLeT1Ql4I2_gR3-levw{=zgdB+aMIA$fs2DsAUT+?iP)KULxXsSg~L|M;@PjX~lY z@CZ383x1F+7H~ohhg`6769}-K$M`cqf0rU7oyJ~oY9N1_!`a<6m6!>-Bs&^x1g!1J z9PJ$w(BS{`EbJionAO@eJ|+CH7JR)&I(Qqr{~CPV0fyqQ%c2W~)+XXZyk|si{DW(S zB(MJuRzU=-SY=I((PQ)ig%>p`B78oF%%_d8!KCI(z_=+i5RuypORmca3yDuiH8 zMU$@t2(o9w=ygboy{h}_cueo6GB$=8B75w9OUH@%iaj{nb?Y^|V%x#x8sXKkv$On)&9_-e%e`PD`TmG=i8WmvE2VWF296hsN&Qm>{f z$faH=H3*VJ`E+oj-*Oc^a4CpR1j1Gjmi}1cv7!vQ1_9QH3Q3`IsyUUFfJ5iz(A%ZvDmx^e+`&_Igfb#ROS z64}CvYpb2$ zPkL!$z0(yPyL~vsjfAtC;8;Zfe2$Y9K6IA8ZGmbGV5B58=z=ssOgz)t#=e}IPMFhi z=KWj^D~g-%5J{Xn^^$1+JtW+UZAa8o@G4GJY5d25z7h%Mk-KJ?Y4+g0ef#~#J<%6O zmrzNBSCO_{_#;4Wp67Y!*9pnVv*X}&+k;3!?n!WZ7fJtG-B@s^X(&tPR@8>SgI!*w z#iQQdaO4sxFKDEIQuGZnE2SoZ^$!LAcXseCdBy7wH*(gX)H=eB1G9X?8o^OSB@g9n zcY>qyjtFYp&JzUP^=pYw6LX>8Qszj*WR1t^6VQr8n|;tpuj;Jd|A95kqY=9jNBRn? zw0T&;7FdAO-aW2%5?n_cRIWGdM~^HLmFlkWOEkk$zECxQ z&$EyA-)B z@TH$2ju&KzeM)lKmkUcv1oc4AMb4GC5y~-D$1abKZ`aHTkZn@>1%AwjPK`+D`49EAW-pGQg#?#?+@TSpDVtWLyQD`7uZ8%NP+-66^0 z-=EeU+4cTEK<*3kaAm*vkGMmBv7Hd-6+I3jfc2r5|FOH&sYfFNYa5g+`WYB)ewlNW z6E{@=tpcT7PzWuKL53X4iF9>)^S}J%T{@q;z*K5>)i7C`oJ5H8Wi+j3yoe| z7K&@|kOoK@)={c7x%MpQ#bbnGCM$=gerO>lMmVi}S1Nm8gI#srv zoz8&a#70uJt9{-LC)L3jfi-~OCn8Xq9YhZ0(k=ZC94z-&MGYX1tVhJRSaH^c4`_c5 z$8U*6$k+i^jEEXhBcZ#fR?(JvYEM#S$sO@US%2MIjWfEw* zIEs}m=Rd4~l|4Z4E$W`pSlL5lW#1y99QBqqd*d2gpE8WQ0({5j=o#zgYJzE&^Mj5 zYMba%1iC+M*Iu)pi7>SfV-=kY1wtO+D$Z)hNw#u%ou?JhHMJ09dq*sZ@(Q%a2d8ZY@eKgpLkA4KHKJO#;B&`Tw9 z#2b#o)e-T{TCr#sp>%5fSIG%8jX<0cUdj#E$Yu^Rq!x}(;^J_TIjsAz+#S?uR4Q2< z2NKcC&u9c6bmc^5Hbomg`N>g%?qgJGUqaJD>F{yPNZ`4mT7`uV0qi-?Mf50!nc=)^ zYpGUqgd-E9O5;1e6fzgU)?7<$%0Yi4*;_DGnu^2mI3I0Dq!jK+*yHP$q*7E+9i`qn zA?H1J`KJp5C*&mQzV&VB{v;BcQy&IfchS`AXhMSRFoENX1D`M+ja zl>wJK@B-Rs@T<@Bm}3)411WC1@EGiP43&k)AbCY}q5umsc?>{Ukuhcy35uCDf+~27 zt3K?^g&;`Wgn+{15JYI&5d7-l(w<>GL?!mc(C1t~fMb897#Ol(9l2@-PY_s9!Ny?7 zG&t}RsP(ruzXpI0R5;4YugK(|qx)Q`BG7#f*9h$m?Sl=KU_afExa2Fa9i*6V(~H~u*kkH4| z#JZ&`qB%wg&KvB(1H2h2X*v@SUQV+&0aB``LF zpJ;*B6od3+&{ivO3QnUGBWB6Ei_lEAF#Hw-Qy<;qUIB`|%4u9iS&WN**MiI*Jo8Y+ zhSXiKY$K{t{^QOwOE%%WcQW2ji3rGLdActF?QU?QW}=P|rCSu2rQAtCDM2%?lsc8! zmoz0_W@(7yZ!1-4e0=!T3(2HCaUOZiWN%5M1lA|fr;E7|u4_S~E=HxaKpgswU9h&;?eA>{Fg9OY5 zu%KV7joqQkC&iKbGw}>^*+v+2R2*t92Q2`z;|gS9qt0M7L%A=>!+O_EvfUct0-Gg1 z5m}$gB~)bw{d4Om3#$WF2u=OUk>1`w4=c9sGS^mru!JuKO=Dkp9%U&vkZO;DhV1khPYGz*QlXXxRE9xqva z-A95JZe>AIDqt90+DLT0OE=nH0Bx(AzE80q(O+=?^kU}i0`C0D3+8l28RkU$+noN3 z7P5{1`1RFW1tHXS9ZwgR7BF@O~M_PgfDcdQ1)c zOmQrbzze%2n((fVAsc@zX~YYzR_^y7?G?v~VmH1R$_l6TSHlMApq13CHjIkICt%=$ z1MuTv3*%`_jHrqEJXI7Y)YKUMsuO9eUqyYqmg!jwn`TCLU72yeibF0&m#(+ zMA8}B=6;J+4OnwkDqr{7F;*obMO3M5f<-GTdJ?~G!It|yasQN9?B)~umpuWLB?WSo z7Ka7*)37n<#%(_U>J6*28Db_Ii1?mHS3xYxZ!xjyZ8S{03fA^c-_gr_vUh$czfK$5 zZRlvE0_)d%KDX=Y%GHyPkhciK&B8B!lp%JvhYEIJux)tL4@f{B*Uodkl`p~=!~;zo0}`8FP_22tv`g^!=VmIlWV zRN3Gd|ERLD(YO8BZ3-SIL`gJt=@3}mK%+{OA-In9Ype=VPj&Y74ahLo-G|Qvj^=vr z%+5+Uk(0h?vgwelerCtZK0<-|0Yfb7Qcc<=z=-dlY?rug6G3K_K)5zH^OD~otYaPZ z8O7$~AB`*MgQXC0-UMXi=dFlxS`)m<>;BeUSBV=afiE$+jOHE`lq}r)MH;;PdTyZ4 zVc}5zru3dIR>RUm`Z4mE`jwW{57V0CJ@x%qfgj;S^w z2N{}pUh@&7b+Pe8$BMAT0|P1`mvkReqyX|piT#8Ep8(Qng6A1%&5;HO`#OEx-0L#A zxSd0MRHbq8T}^6&gqw1oP)9u`3y|+nvF8pZZb_SCocQcau;G;v{SF~Cm@FbFwCh^X z+s{P&g>$_Li!jqnAc-?ez_a)aaA^R~Bc#Khe3$Y)J?ye6*yk+mkh}L}HXQ;s=x32y z^y{!_V%28&59uv8kLyKm62CJ{Fd?Xity%$uQZ7)E4f`HZuG>BQt3Z6}r@<2}E-y8F zcqEZyUj7Ao{5P@50v6%2;Bx z=1{Oo@9Wz(Xm~hDKqDkR>tLa_zT(8*6WqyUID>$;%IF4wtQ@W>$2NLhbXB&(F_R*8 zsP((EdxImy%LTfn$uYxi;Et-R6ere;B->8!UCM1=aUW~TO}wg3w;Y9Dm-*Kk!Q9Wl zXZyH+|9xvM!sy?0vSZWt+H}%gpksGKbf1DlFX<=!6A3cH0$OL<+BcD zD#n;-74>(O7K;oU5{b31SiKizQ|}~@!3AFp6*J)LDRv{$-nn@1#Z=qk;$`VB??KCe z%92o(S{xfudw0zD;bktIIgv?n^!_u5VIb2Z>F`Bh3zP;{ZaBQNO0fWqXbE)m1(nz5 z?TvfRLKj&H9(4*ClwkKd)@+*+8EAp_(*=LEQ>?kFmDhUhc&bvgi35U^rN1JPvV;TT zz^m<_GHOxWm#hQi!l&Wl_mhI`8-zk4eX`l!40<;tsXvH2|6DxnsSnlS6wuhAYxbz1 z95W!2U1;I;_ zi4VD@^WyaGJD$?lm}bCF+Du%xuB`GcpmnjV19bH2h-_?n#JYXY+w?yY$}Q0b`aOAs zYDN9e=Wvunkv{@`deOc0{M+xDmqz~7-XYFJf*-7C_=#H!!OuJ?WB%otk`*Na-9&_9 zgJLW|AD!Mmho$0oc4pc!)WE)v~%ob2<5(qHG>O4;3F z?oRsl7<}3JEM(0_gAD5{n*Q3_n#s>25;umg<$icWFhcW^=8j`hMt7EJv8q1{Nn93s zMR@PdU-5Po^Um)F%#fZg%YI3ZO77554zrpXnrR0g8*`%5kz-w*@9fU^_IjDqn zP{g>LqFe1(T%SQim92vRGf45-#J!6smfyCRnQDY zp2)oC3OS-{y)vL1IgK`gjp5DoHZ_LPsd=RXNAuSZe1L~M77qt#YGAcLj5c;vs8srXVGk#5BM9Eu(d7MM-C+hsO( znzdmuaZ$=7>X+pjhl<}0DVUaN`tCJAZCgfk5MViA>uXxA-LME)b@GQ5m!pC=Qz=&u zQAHs`bc&MH&B?*SL?!0efxzI&_HI#d1BlpE!{|T5its;QSl?|uyV`o`3<+gQhywfa zeIq2&s9|y3nBJned$1*wt3@02P-{>PrvH$M$!%HOsKk1DE04%5A`fhZy};ymdKQ;gw8ZhMu@OGYh(PjF=!(c(hbXN;cc@Re>b((OfQ!GR#|>Ik<9M7nx^tnw`RBJj z9^`RHCc?In_x~-9dM+8_s4OZ}X%{-6R-}nSs(MA5B;Gg-dz5DPWmI4Od>lFf$Gbjz z#$>Y>9;E>@xdw2gNewehPL>%$Tq^3{3R_!J^O#iI(6;8)>-nE?M9|dab+ED3@ zqao3qN~ITha-v;}b1g}s6QGh?Xv+LtoJi_Ze}BK71wWrm$lOG-4;p=+8&$qB8_6Us z)fJBG($Rmthlwj9fmWy{;2euj__n~d{QGNtR{Z+X!q_nZ)JS9uAPPd3dync#NGI6< zk6>69ht}<;V~sV*4fTKJBgmqUFvzb^E`6&rLd=qebZupNgDv2)7SUqSK+ltaZ@I?S zcHib|grw;fpN)TIh{?nI9;HhAXlK8$42NffYz(aU7|AR1P>EgWAfag>rzCgF2h=5> z!%YmoQaMT-+~1dGrir~0uh=K5N1nr%<523qyd~Xn==QJ2jD#!P-l#HJ<26*R6YKtC zV{|nfj)LBoelIw5bgbeQQhXtDXH0X_LKK+n4v47S3(VZ;Y0x~n@G<@@*c2`9+%+n) z09^cUE5pwT*dMYY$r|%ttC?RUsQOW-@A$7zE!n+uHV8a##Hb3&N80y9?INetSB=Vm zgd*H~Bd{dtOa`|V_5lg{`Ty&sb#AN^A)!3?FBErD!FT$9dud-czlG8sT>0V2NyOYx z-r>8hv10+fL7o%ewnUoc)a;Nq^Rb2al<3HHzvfj0Uc-mJhNl?;O7Usrle>Z`CV7YN zBmD9?R!`u9BNstwj!I8Vv`CZ>;nA>iFcL|e(8#X`Nt86GV+L(IvAqYQI9EmS} zKlH+rr;sQAv))UTj}S^A8?0vsDBsfVy0g-4wq(^@)CK$bc9(_9p z9(^)5a}%i={P*6vBA0#-1vO$PhSl*9Ml^GNwOQ3B@%_JUUqgQWXLJ3JH%D$3hKN98 z;tVQqMoByAuWP9Od(GX1$eQa(A0uY}Tj%{XPZ?dxMZ08`j%`O0ZCCc zC;a=ht=F>{{C#cF-)4qG3T7q{m$1M1N(tn#k`?YET|8L$Jcg?NuT&6OGCo{h*`rMl z!aML^;+5JTRP=d(>hTpI_Z_f0O?r9UMSMzAh`yGF`YHX(g@z=mY#);?SXh8n2y4I4 zlTW#w?TT3XFuo5!BwOyLkyr7(sK4WQq^Q%&xJ2t=+l+*mF!@UTn)FN3=wwE zwD?j-5DLbBpNht^k~!0VYWS@fYGrgvqC&)6e|HRoi^+;_WY3M^hy%zKcpK4yN#tjd zfZ*7@SwGMFcfqh27a4(?J4iV@3P}@E9mE)!n2@4lL_PXzCcI+B>t&$X_}0_6=`kpy zT23SfcbyxDJOrs7Du^usQS8q$u_*cOyvO;bGqT1wOC1C z0bGr#YJI~lER#Q3CJgfsK!fz^MiW$t$V@AaEz3w>^7r-?n5DMJ;k3QsI2|vpf#%mF zyvN((o`vi(%;$E>SE!u`BMnV@-xS$}p+V5pTR-9Z{6Eh^Cu~&tqNNIR*Rlw8HDI+A zkT;8{%Lx?XZAKzWS1enowrPDpnT`l7Ca*>CEQH{Kfrqu{KR%4^fsb*f{{fNJ-iE3ii&f~`0Nj>1mB&!kark+5uoWPO0srJO%yk z{^w;6AVwv?!ioKAbxW%jJExp0H=KjWY}f$aYj^~l?1d=2oL`og5KsSpoJb$jO#cai zF9cbQgwBVkEB<%D2iZjuZb4+tP|*wupL?^-+LPlJKzVd6-)RgFvyo3jM`VF>c!S4 zht9zc1Tuon$DpzoW>k6HXd2Z^(y~%NurGbLD(L4?5tkOC(?3>bMva&|96hOR8`Fun zAcSbXJS{6BWfhh)WLe^^YJqYrXU&b~Ak0;lzWOzH=g9ycGy;Vi?a|bS^CEvdc$N)B>L*R$Q+*fU}H`!}PsDr4e=)Dv;`tRwn zmuWFAOqvLNn4RTSbT4oj?%15|;fPkQK!`4EF#K52Dha&qUc94;G0l05Vl(ve{u7kb z^D+ki%dvMyRARHF03%;y%$Tp;mT{|F>Hl<@DJCSH&U@osb3R}hL|xXCnU#Mn&?lUF zEQ^y*);8$KPquAaMMub)I!#pJ;_WV%V`rq(WC{Db7ViA-F#Y25OOO6>4|KxCK3y$U zS#0_vy_Xu$J0+*;`}Nt;lp$z>f{Urp~KSkqC80;lZ(3NUB;R~f`!al1HVM33C#IPJRHVK4@IGy8#*qOX7+`0!bLK0s-*X31Cro9XX5{{cz<*0(ZeNyZvRrVO*`ZBbJP%7np0ivd)BV_ivj?Qn4lOW=K$}7~w+-5rp5g=M@Ip2sBXJhF4Y0e!I#cd2rL+(wXC(VC}Fg zF6&ru0>AfFrK>MY?oKJ2$-F6is@dq`<-`iC(AQr5rQL?0_9dwDwLYNVqyv;)(u@Tr zW*h+4KBsmkMi%^CS{6q&6=Oy_)Mmcib4{f2pf62)t%ygsg&KuelfCSIEOS&PG7L!+ z%H3a1q9S0abz6o{&LNh-gzk_Dw-5JQ9?FAE$#{&@cSwQPXI$ zYU}h1UwGl)_*$d?AFG@H$^?Omv+qml4$aF(Vwb>aTkqWaI(T4^=%u0!7kAxv2{~K; zT;;2FrT*;DzV}DL%|tZ>XM@Zu(Ifb-mh@4}j|$z!$fMMU7`|)-s8@Trmq)V+bYR7S zju>xQ+5hj%PM^LlIKF9HX?2FT6F)945Cn%&EuR?#vt*Mxv^gQzWg0P9I8kG;ooD7% z5XKN3t?4$>eg9{#>NDaZLW~lc%eE;BbwazciX1sZvM;BxFPy1LsZMI}N}?fwK_D-_ z=hX}R>!%KkH9X4UE6;dbDgnClq9K-drQMAU@DWusn-a=U96d5Zzq-GfV9P*y%6SOg zxH~^FS5@sm?jhg)nZ5r$Y3Qi+AJ-v>ii7|Xjn&g}RxHj}f9z08-Nm=D)-rTa2R_te zIc~{2C86YM1m1-(6jL^C9w#$IuS%C6y(@L&pYMc~CG|8}iA#PmgXChfKn=D@%c?44 zo$9IgQ+GV|wxb+uvp?+CoNm~N@~;X{!@2)_XBt6jhsSlom(G!xhRPWW`)aEp8IhuC zT&b_Z^Wau{%~zB;K0(&Viu2!hedzOcOg7*{rLrKYt86D4pi~=?0IRssexyHoPxw;I z<`bg)o?m?(@1Ayx7t#1TrG!q{&&Qbj(%LP0r4Winz}d<3DQ06Ir*Jw7CKQIP6wTEe zcoO{RpWW-rCE(38%drtvBRaI3KCtMCs=tf~)N zdF{M+32=OW49KT~=1TnBX8v)KeP2Q7_vHY&j4p#4EB@atTUYH}P#0dfG_amy`J-u9 zm@w*O0mu6BnOz^;vqj|#pU9frALkN9|8resT3mOlG-=lV>$)3RHFv7$9FBTIj*{Qc z3z@2#I@Q}-XM%kyXhD=*ivnpl4C#(15hby~z}9bwgPxCvL`cEyo?6J$J&1$y;f`Sihn%20fyjdMv@;~l3Ox0(4 z>nht@8w9(9Dl?}GyY18 zLCk&0QDBffCAu$@S3kwitniN^2!v?(OyAmt5c%VZBiTXJf3W~<7)Y#(n!}g6cxh-3 z6=D-?d}rE0Q9{Ah2(u!OHK&IbK*p1(VGk;Km#^&)t0LQufc#v}J@B4Gv7>g1bl;>T zTT>z6j&LMEiH6d=eZm+4K`P1uwT-9eIM#eCL*J#g(FF-7k{AOR$cJuagP?yL7+vY2 zG3PeBsIfKOag`tvuftyyRIk*L41KmxbLu?6UW0aBC>kL;z#{dOgrApM?qy`cUW$g@ zO(K&Ck)?HT_Og>)PRU0UmE$7pR|$BGkub3%*8*|hjW2ntva;5t+BYD8U9WqfOy{-urL4^dSGEH>U ziLCOF>d#x}2G|C=&b2DnGs%c>XsSE~LPG>k!Q5%GBb?(+%_srtp~THOm-6UTyi8wp zV!VLMP+LRW^_}dsWLn8h6&7l|+Anw8KHy(}-znrJZuD&X&mdl^6Vzm`MG%rN97f{g z3@*ItWno$zH4Hd0PP_xJw}01-pPD@1#pt;pCcn{p)(vwgBJ!jiS+p_Gl(g4;Jxnef z(&1;#m0(Hnd2{@*8;-d!paV)bnZc<4zMe|NqA^)!loO*^>-|28>P87LD@`XHJuLt7 zGoS#G=#X%m>d<_6nO6w~m0bBb7gc4O`o$kFn2c9akTno19{_8dg)(Tuf1>5CNY2A= zfkZp*T31sr53Q8=L+HV*Qt~W$h+2r#N!CQ2Qo_~u+=qeXq{WZST88OTll49CR+0A< zNq^DXLYD51x8njaK2)?vXG*zYl<2k&|7f@;GJ^1c5EUD^VApP9ET71iK3hjG`Ja@1 z))*U44CS+p?DeZV(4`H294n?D`!vga?R+VpW^3u$QxFIKB?R5m$3Q zwTBhv?hdI4l=c!fc7tx2H>N)n#k#&Zu-_r{SQkniPf;xhmY$;_3SUV}-yIOA6g)%& zgv=*+3Yd=7XQKi1dY1dj&=d$?I;p$;<{$IJmuh1Z@Gg2>t4=3;qY{`^F-+RI2?rj)P?^#nWk)V$0FZWFaPG&gQJAti$HQ! z+PZ`7a;eznaCjWYAUv2n_rVq&W@TR)THOEKeFR@us56v5O&zZ*MCkDp@P|*R355_{ zLzfRe<(ngA?eyQXYIr`pKgPR=7n$&TdKP78jmx8a+6texk*JWsNIqfWb@`yF;5HX% zAicmpkX}N-kjCD(<@yYRYU9{DD;;fhAU?Isx=T$KvAM0Zb79=I9#qTZ*lGZ_lk1B7 zrREN9=g#7r35eXBsjbNAwr$GOkuVx84FnQlcfw=_BQ5qvr zxzqsPW#Hi3GY(m%fy-BItSKo#1AHS?2cwF~H0R*rCJdxMnzkyNxOQE}g_r2R>>sEl z?)d2`D~8~B1gVEwaJ-u8XXwN?ZJmZ(w>4}EwEd`rb(fb@8eC8zbt)3MD`M*9S zs+RN3q%hmrs?TdS*nGi5zRFrhN;hqT6AX*K-H^)Q7=sg)#&UOvWYN8G(4-AT8lP-5$v4$|}E4rLL=yHadFr zbS8jG8d7EBMv&~iHZ})98E031Yd}(7(xkcaQ6eoh_W8>ju8y-^tZOEy>BVZTdilzA z8BTO(zE$cQxEvH%J^&EXwjQ4?b2|kz)x+OW&gMF>hqm8$pHovekbF2?^!CE0oil+x zqcjg0j?T$AQkyEjr1nA-I8O6Wm*G5y>D2OAXXt>h8Qf+#A9dx1qu%&Sn@Em@#2C9# zLyn+d!m0w|WIA>U)KFX0*14~20_K~q_zs^#>eT&%SK{vl8uC+xqQJ#{>c~k9E^xXA zYk1$rx&M9i=@Vlr?zi8eBQka;(!2le;k2u@iI^myIZeIWQpDdiRRfRzxy9J>RkNvO zc#}`tE92#|!xtB?aIxIhC4CMR&|B~HiXW32nTT<=*{wIJ;4sCm>$XuD|Bpu}~p(6e@xohE>;1dvj`HA=58B?^T_!Ux=Rs(&xWELV() znkKzgZE~6x70>$VZU(qp(&c=cy#!N*6ZzrTI`gQ&Y$M3{r}gn`t-1kGj;BNw3+{!n z>FX*+>TCu#-g=6{%Byl>xrKBZ2p7NZtb73?{>9B3R;SQFwZwo=jT=zcWi)K8%0JhL z>mH6e&q)`>9tAGP*p|{g9%FG}1#9T*R?J3^Hp;FeCmUp+Wtb$-B=sfLVH|gLo01&s zW3(+1jcX%Yv4_3UQ z53s6uMK_0CEFE6OtT-N$XLB=he6n}qZ4g%RZBRWwO_+{=;aI+9Se5Xl@WFF-1#f5x zlB>te56R!b3i($nkRNS$*EfJewr|}B0S?6ihw;7!fMF6&s*zdV{_rMTA`<+UV&`LX2$N?;=BpKCqXi*Xhw zJSoa?Bm8Mg`9?7l4De(DfN|ppdX|7@UAWfj#%$3$Gy3jir@>TfDRe{|Zxcx>9;t)P zL<&(eBgVqWgo~DFbrODekIq#owk!4`iBj(Ae55v)D-rT^y4^s_YC_1n=qHDhc@!)n=A0Mz>#ff>fwzPF$;G{e?BciR1^}H^=77D z#2*|#hb&#K92y%Dmy$R)4L=n(8a7_#pV0G@)tOx#*BcXBBQ1j=;|+4t*ZGzCT3>-* zbE3wGyV^hTsD-}q58H?eSy_F>MF+UV-1@_Ev4Ji~Kll{3jJ=AeTB(d*zihppB5ZDa z%@eX+{Y;j|41@gUSu6Ex#V&406AS6{c~d8=c4)A-J@FKxbCsS_;8I_pt|_@(bidIw zs4}dI)~&h?CWiC7A3)+Dcwj%487hgTqg$HxYTpJ)LPPQ(L|pDCYD~2&Fk7@i?VXG1Vz0;gb(h@68+Ii-Hj4TeIt<*XaDN0R z@(E_MrAVi(+^e*2O&KL=i;+v_67%8A%=P0pH0~vTCMYfv+RRTO=Q@(5+mQ5jSD&dd zs*KkgBIBGA)kkyAXB~Zy%FM~t2}!0}eO}|kg_`{s{iho%KNgW!0zKrF2P?+M2T9C( zaM{(MY-(gp2IQVKtqlw`E#ul}@n{RcPSYJJc=feJ4Kc5(<8?IbU zJulsz=CfsO_>Mz75x0`!>1fnc3=Zj+F_^I5IcEG*L!&X>Fge1nas0dvzSq1d^Tn$X zM83Sb`qG}!{LDqSx#lU$*Ju2b3B+=&{x*Ewx-S@{j`BHBVc>FV4$eIHP?M}((0A{(wJ4p zZJmzUw#NJzje{uW+@Uwm3 zE}bOhIJy!1`o+m`ib|hDI-9jVG@AsUeV)` zzLja){N4UKhC)r=%!6Yu;}lEt<{SnjJF?8;511Q3)N1O=h-#8YXw5o^ab70r;?SDd zcKf;c^R3D%MDM9V@$2Cg=Df)s*ZcT{IcTcZcena%x$=dkNHuozOpwoc8kegw%MS{v zFShLBk}o^`v4*}!r9@NfHpd7QCi4Va9U2s`nxcVu`ayfjR|Ekz=x5cco(uhS#?}i} z;9D#tRG$^??w#JMsbzKB7_LIGYy62gmEvwV3HPr#w;K`i5{=j)GwzNP<6pNbo~YJ$ zaz1a>iqCF#kXf}!*d{B<-^mQK9e_y__!%u4X z`A66t20x_5UQY-x$-EqcEPOn|%U4#1Vesv7%F@#VNyE^mdVeL~CG{mh1k&!7UOI!Q zi|b@W8yd;yFaBmE_IUHt)VxZkip=JQjTW%j??`U@hdjdbLR_pkhR7 zfA=A*YN}?Qci4aUfmV*Had?%b=a|14q{=tECGe0?7C?LMOD>a|$*KG^+>+C)p&Q^#d^sK;GvKCI6J@=l_s_l+cqshO2LIJJI^ z+fy|fZb(v+Wa5!h5TDR3tQfpa^U@9ARBA4deT`R&NR_kzKRmn*)x!a(XLA`p~flq ztF&mF+t==>p4K*i71lueW4_LhN-#u*s`#Uw+!BsYDY@<}%B5p_9Sx*uH$IoNX}%5; z!ZW0R=e2b|+f?|yd1IhFXIF z<`&kd+t7qr90I?SBo%4$DO?2ub)ER?safmZFdB*ZPk})Sw3qIK>)w@ffb-YRF47La z52W?&vAc&;`X)e?G59eri}ko`Vcx|fevCOoM==8vgEw?&o4c&fP+r;OHNG&wFVI0X zQQ~A{c2vU&%&L|eSRszEl+Z#zqT;zZC=oZKu!dw5niAc%vqP88)MIn)m>sGOf23H( z(guy?2x&`;@q2qS)sIBO`I?rk&lo)MFx@G+C5e6-wXi_%vq>e;;JU13d>r#fyw0Tji3SG70IDdBZlbNNla;GeQ;KWMVow&nl<+>y2)=N_#R6MY6D!5=qXZO_3 zR%2z1O6Z??NrVF-ux&>Zvp=xhHtDTK+g7)*$~S?VTv;_8sPxVZyxEdbeAo?bdv)cK zYaGGLi4b<-E{B1X+&3-7az^J9ya0f@Dtc=op;)uwq{yZZF*CuzCcWa;m<;^uXe@^~ zWyb-(@q$w({l{&(#H3ID!0PI^SGa*SMRc?7>}{$ZbSZTFN7BzMHCoZoM&l1JoD6i_QV+4c8t@4d&E_Y7h&>wzG5&VQB*22bJh=v z#U8U<`ue4AI7rnJWvwZ)rSD#zf1hu6eJn7*yVz)av3%FrwQ(t%eebPs8W0TWq^7uD zC_fiU>3hpTIU6m-U0)n6_>(CuJA8}yYKcdl1oTdCYrZur=WRcg6I2Yf9|Zq8YyKl< zlBNFTBnK#CzUwU>%70cuA75^AIns>$VCH7hPgzLt@}d_Rlo^zISEifVrAS4)yh$ng zHLG8yAn(eXsrA7mQ>WlIs&CwHXLh5-_ki|cQ2gx(CLJRay({szJvWxzd`nG{xr-)8 z62FD1I7P+@o<92*uYIbrY9{2(4TZ9USMb5Fbz?xT@5Ol3Gxne)gk%dc*H zV*B!J@e%qyiHmtb6XUxSoBdm=M%tb2dTH5M>%raKO}IKQ{2FeYnt2q&qwc3|z9vh; z{~o7TDg{i${nA(OB9fO|BZsNZG@HcRQN399B-0~oSJ8p`KseNyihir;8LKJK3}g$N z5=_{OGp5+CnME8hGFj}TC|sx8Q2l*;>LMRolE@pr8nsKyLZNYO=T?eyszv^&^y!uH zFb~nku8d4w>|0$8FDw6=u70^Y9c}M5D>Qe`4sqB-g)Qu;=I}>eot$pq5`Tsab$;hd zJjvm5Et?-2TAse#1D9v^zkn#92uf19?g#dIJ;9?z$Ho=K7WJKQ&NR-6Bz#|FJ$~b~ zbMJil7}8Ej9~0cKockupBN@2hbqu@D zkMu2dn0ca|;?SWTy|cc!*=STKmhu|#^w@9tyU%N+DXo<f}}kt!Ry|AG`@4Cj7*3O68qk+dx9H`9konhI4O#kx|-2BU>7y&0XO*!<#vZ-S7t87@|mPDs`Q9o6ZMxpc>48X_PR|6 zO84KJxbeI|eLlTmpWKXsFfElbqp(6ki&`M^S}&1m?S^5Y@#>uB95&MjO8d>b8h1>U z6dW9%IH|W6pwhQpym@xd!yD5zdwxOMTjq5|{jULj?K4-i`&wuo)ILRxKd9qi)ri*~%d{N6 zyH1Ekf{G`I-l3So3q@?GL(~D+;%|2|95FI6$A)rKD7kD(J)`OctmOJGizC8wDz}*v zCG%2E+eg-%2NZ5Y(e|rp@|e%``3ogX=;YSnf~Ft=3uEKmom};E6XQ3kOaNVJxpupi zx^r~1q`+58stTF{($*wX29uVqIv@_Jnk-wj`y%s)>dG|@H|F;%7fPCyv6Z}tYWeV zO(WM=QRY2jxvN`zG0(`wCO4Z!-=jYKhDTI}&Y=?; z0SbTHUOuJN-dE#$R-KFruNv4fySlFFQK17}pYJCCS@T^6A#C!Zt?@;G`tC?>rgNW( zT=}WW1LiDuu09&?_9!LK8F$AMC-jq{%eL8@{q)B4RhVO%)Oru!z+BZfciyhjcTGkc z8KyTUv{d_$!MZQ@kO3Yc9k^_%UO0neRY(z%xcVd%YcokV5(0L3dQG z%o)q?O1z{fo+VXNcP5@G+gUB)Ps>23_)QlT#s;wJwC-+?^|>AII~K?L#l%RyEI5?l zlSs59rXsnEcD!W@1)_}uaYLg+Yh~q}L8_%1#X;`EVORl1`S7teM*S7oo+AILYI zoa1cL?qeBV7k#m)V?Sy3%w1#~GWZ zlgWKy|CZX(vHaUVdZG`}d!qM6dMP@$-<(gLNo0Ji=nL=tB4mx)`pslUpB94G_2%pu zLz+fz;D9%x*Oty?T^H9i-K=ULn&Kv%AZ9VhS0$B|!2A~rK#@Dvu@P+4hL$c48a8p# z;2jw-pHnY&{IH{8v7D?#G~JsUj{%tSvfXF!V-$80f!;z*;mwfLB}ev7IvQU|3P#;WT7*fwQmu+h0~&^ce;I`(@@!s8a=xkfM>>xl>AaG1<$vYNmi~a zG{kro(QyjKS4C=MIA^@o>=3^u>`%Jt=Rjsp>ZthfCFbPt<70LLX6&W{Ws7?k1Vs@S zSux)7DW`6{qsK!U6Mb<-?tM{~IxLGjP{w>w;?%P~JbG?t%gC?C(q-deq~~?IBDTCT z$9EVDL(q-l)h)~~r*j+o+k3r#?=jF?rrVXjN7`#yp{agua<-m5=R7C2mkyv)$K3lU zZ2OE;j5@i}A)}1g?xl;Gdt8(hTmBvx2?qDHZ!mZogEj@BY3f&$)UNUU2UA$uKR5*F zrgQoVhaN890{(i!`Ap(p6m=kV;Pc80Q7rrU&0TZeYNFU#%XV`H!}NkI>KfEOk2`M7 ze0<8|;?K<+KxF0OF+F$Gijh9kVAaHLBp6)|urTMpY*`gvb$7HC4{xAxdc5XEygJ2h z7yuOU=qp=HF=m|C*~2Kmbx+;HO7K-Ac@O4XrE*pNhz}Qi>eKv*T9m-bwxE48n|^5` zgn%9h*KhsVK*m`1`cE-RD6pAquaH+_|$u;=tIr?l>LF;EXi70U3T&(8-(*kV~(7h2s7lF8J&VGD{GfhmBHid zzLKVz)BW^`(!bY#dKX!L=g=%vKB$yy>wcZv7?vz%@oW7ID6K@@=Z;moLe-`lLMvPu z1275YfOZFDS53K5`g<@}5?(g+JJ&hRw)_4U?e-X`{V^JC^3Y8;Uj8;3CiWI~>GPbBGBH3HX$zYB z-F@Lma&KiDJf5b-Kvsv@vQtHb7`YJ&jQK5l1|DPiTP_oW--}>mHg_5Krl+SbmsFnf zrCPkC##4UNR-zx$%k$|PJ-ZCMX8(YZ9@BfLC%kc@m#f2AuIXlTD@`=-iR=Zq|J^rK zJyOliq7WD;dh1>!G$FKsHos@_<(OB6$ffojRZabA8-6<(>NP5}L-EHp%5vGdZ-c~K zg9mNiw4^svlGW~?_FsOS9XNF^^Cvy(pnJw&=>(pohIe7>(x|d0&01oMwwYBtWG!^P+4y#W^p90ISjadC>NGK9c2 zP)+6f{@zAI?rI^ee`+oJ?sn+_tD+Fi%1=#DY$S)05-@j@bu{g_u9}oFyJLddr<-K+ z?wa;E-20>Wd$DInMZn9a1Mka_8_Vsvp}<6+eh%}OB)jx_ix9R&W(P=!&%)FLiJd_4E--mK(2nk6RgnU>7j7(-)MGUlZ~`S|#%se9>pJZmEWnmWmNPOvYn zi7I|FxBYM8X|>U=^r38@5k&>mh|)FwN*ATH3D_En7gA-v~3r^C64yKUERoYmbM*LEA~4O@-x7a zhiJn#dl$_FIvo;g+r?Y#u331di+L>nI-OeAiX3lFLQ7FNJ7V8)pQw7jPvjV-ZGQLs z%#EHW*Kc}^Ja}TXs|Q61@02{I@TN~s^XrsOWC-m&W30kl99X!)%|uDv)mU2o?Aec4 z;sVIEZP?F*`PXkwpO(MHR>dkkCo_co>@sZC@Sx>7Az(yBFLedQzX}Rg7-Mvs$WJ$jS4vy$8F!!#^a_iH zof{u}Q0aZukCJ)hQcccOG@7Ebb5@XNrP@bE+#TON^}OKQGrv^6J?)W|1TF)ac*E8K zrTcr*^b1`Lq`t-bgjZ+^CWGKn5W4!!+^JVttMzLy<{sn)vJo8xQHb3*%|5Dcc{I~+ zZ*pO3rx@`aW4j`Fe&gX;Onj|_m-Ii%kKqtS>;6E|dt)pq8FoJ2?VPX9_ zpVeM2Y+7bjeMzgrdrp`6=bab_HpPV3+OUewbVH$A%ICfJdVo8cU$86S2GgF_xJvA! z&uDyIrm>{YCcUB#yC)zGhS9rA5dj4hv= zG;Nr>SiP6+)=FE(02xKCpx>Mi-)R~cfT;ND_s&Op2i(G{IxGZx?6&oM<~~7fF}I$A zIoO{8`IYI~>cuk&u>~3P_`uineMJueBS`M&0rJpT32o)3iNeEXS|0!vehLSW%x#8= zRG}*qr+2CJra;}pkhgJb!MDYal!cPS@@P6|)!B|2804?U3=%RL%}DHWxZ;}CW4Fk> z1O9w=b*~9K`>gY&`kl%RQ<{4Zz2IaEh&%TO4G)_6Gj8Q@j>%uEg5<=r6!rJc4wdcy zR@m24mxKa~iGsWX&LN|G+gG1rSonjcA!!n(BlV!h#b7+R4fT$gZ2q%GL}xyNbZ9pt z3ew2fop>Sj+U|C9s@vfx%BgQoaxQ^J$yuJ>kvMv{F?hA8@2|JjX)>Mdt5?0ouPjC6 zrV#0+Y}>CV2oJhplc|99ri}elzqCdzp#KuVr|9lBIV+r$xRbWXeog3=_B+5l5)kdI zSV-2GEM!yT)x`)nqAXr6=ivA^yU-gO`rqc}oz~hvqH69zeH_5N-k9L5mvWAnqjMpKtw4FwZ-;pHF1w{n}rw^>Y>|+PciUT!|C* z_u-?p7LE?wNl5I4811G zcsAkX$8;7F!=Xq(cZ^8ZR(f;kBn5QmfRR+)|3H@wD>J8WrQ}W-+~m=+;-wwSpK`vX zD;f4)r_(;u3%nk^vz6adNM<4l7^=tKr3Wk=++T0cOm_~$zOU;@UPEe+_s)C`pN4$O zPUe`aX?<@wfsYD-V}IftQ)%{M-G@ru6}*4*qMNi2uf%IHlx`2$;4tc96gA!cbE|GG zr|S!oS969BxpsSW6}8$ooC_>`d`hGBNuiO6T+Fq?fDKDu-MYPTbik=T_UxMi4#{ry zLxWsXC{(Px{IY+Nb&PY4HkYU+nUy#`EdDkzK~qp3$490BE|?SjUvo-PxWyrgPxvdW zP@O4Sr}HJ|kLwpFHlN6fC<&`VRuloNR4+`MHwD(|-nbt{iqR8gbtCkz()W*_HwCBd z#XV<_92zoX>?ts0BU;YU>7M8*eJ&Bccf>J4^D&#OWK7j+n=OuAy~PVV~^mqow@Q&o96JvmsD4 zSa2w3rXB>ko=pRm?OJ@1$G|Dg%k+`|Lbq$rdz?nz1Tv6pQw`VQj z?ohdYfxnU!(&uADHDH<31DQFW;BEp2c7xGo14s0$f30GGPUTfgVJOMA=EMV2{3D{8 z(X}GR+F+R_`q3Lf#Vh$D^X4&tlA*}`wt2tb`M#c+>Yp5p!~T3kU)qJq-|5WP{Q?Ji z?82(vDcN;IvujxaRr2nI$gZpK)s0?u6T{y5>dsn3{@nDoI}?K^_-m*8Q*TC>Cx4kG zQ?e=L`-3FJ$-jO9IASt4M9dbX3>M;z%3b_k!g8ICYI}t!mi?$#cAkta^$_j;A{_=a z>J!Z+XZssJM_4-!JQ8s}>;{4M+ULiLpM%+x3O#0ru6N&m&WIP}N6N|;C81<*LP%swR*Gy=8JStxgbL9%lRYXk`(su{*_-eo z%3jG{d5*K<{@%}X{{heQdOi0~?mi!v>pHLVJjVNYAMc~4WpFyMQXYJ^CFukj21WA5 zhie(8PC0pTinBf5n7=IKTJZZew>~jH`UG(9;Vw}xll(>M9Ri@U$r{}m4ooMN1c}q1 zFxO%&Eotc#FAkf}6PT{S&T$YvCyMJwM)ypNt2UT<`JDsYfwWCU60PR)%pQN8ol3Eyco#*H^2;PhNAugm>WN9 z`)vR#gu~|j1Q~awgVSU_Z$E$S+^>4CI_IDTM&_yxkv<1qz%-4-hWLZ7_5@jc)GyT4 z;Hf#(f`gLQ5sCz=KQI0c?;o$%!YHioL9{96y<)^az~jE0HvzClc-V1?=-N)%O0&_Y z7l(X<3l9Jz@)Y7DdzHs#l0(Sm1F6()P;`@bZfy>7O;uEu*T>zpCWdc6b8{Wj>9=|r za+d1BIBgKCKjWRRIA+rkcb>lg{QL+KZ$1QEuC@NOe(QVW;nnffN4BOQ-I!J>li#PqG4ojw-YLeaor;g zGMZAI=Rn_TP9|hPP!sp2_mhcwd)0%}^(K5&!KTWGc3`a)C|$v1xaw6g#mD8 zDW-ji*-9`t`ID7T`uyE0u(Fn?lGCs;MHo9OnZNT7FJ5bL8pjSoPgjgSJmCuW^NeRcHF}+T!)qd*?|lAP1YvaD?d; zXxD=r4Xkn*i{qs;p8x}V6>qYNfIk?9nv1y3l#z4t2B0*80QXl_h}o&Xhn2mD&9d=P z<(Zlf5IHV?+lYt0Bj<35ngfvg_&Y#}KoP6)48+kGPLq}<1}HKu^HFZQLVLBH*^M8l zt?ljkg8~B9uJc2{?W+f{LzU&bbM^=t&xq)JmKDt)w9!W9c4_{K_2fZPZBlo1U`fv% z8u-%!3uEudr8do=z+zy?xYPsNv!A3xwk3Ie~&>Bnv*uAxl3 z;{05s2F|v;AgF)ByaO)(?eIftp;XD$ISjZuAoc|~LrBVcSJR*lgb$YTzhG1=I~;<% z&M@t69uG8dZG-rPCd(nTaZXK5Cj3>pp=6fcdU<5^Y9_1Mr89?iSARNA9+jL)c}4Zn z^jL0}#9}@T5L`#2F;qp9%^5NcO4^;aI}aaMCVB*%dW_Q~Wfu;%&;*(bYgY~c`mpr< zyde+WG@eXs9snjSn`&)|Z*eiPXnL+^>>)K0^5^Kr)ASXA=Avj1yzxvUR$#YNVf}lp zl)vM|nG&HrGWAT+>(2(i%Y`<0iAo`KECZBtR{s5LP>)oI6Gap+d)}p`9A~U?8c zE$xB9D0ih34{W_UqBhUp)Hnd=fMvt3Rjp03D!X`uNQLc#l?3L(RUP8#H>P|ly|{hA z4sU>NBOCIKWhN=U@rc5|O_){2xZaQAX02GXE}gN4Vv^W6rkW5`fR#{h&FlT{XExRr zzVR5!-nfMe<}kYqn91S1?Irm!`|VG0WR%+smX$QV6cc*$&05RElJ|I~Cjg=K;8+sp zknm4E7>;=h{eeS%ckoWRQ%ewg^XS!S(zZ69e~|(Qo|jy z%roJjg7csvG09Hd48$OmV8<@0;)f%W?vBQleoS z*!vG{rKP7i`9$|>ID*ta^tb5eomgZc(-Ip@3z&|jp76gu%+*U*i^5tDTe$~=UFX^|0=ee?*zYpaxEoV>6}Yj5 z6X6svs@C?z`SUQ2$D7c4SxZY&8n^(Pjg3p8L1=QDcGHqik^4`J@3oTdOF3nV&nMM_ zjs#6XgXd>ZGH5TqNMha?d150-@DJXD^5H5soJ!!aJmj8HHXSi%dqp`noLmJNWoVIB z=5yE!bi`>(5;bCeP#{$SEm8SOeGZtROzx%i#nyqFBjfl45E>hsLY)huvkYz&IAFyveH9>h5#X@=p#N=?eGNkIG$6%Jb;DPllR13 zk+5;ft#)mf(;Qn+`M&@Fx!Igg8z8KpA#%|mcJ!JfE@pida^^(NX)DQXxipZEAG4L? z!J|C&_)}H)BYlxIQ!Zl44}=?a(tDCHzJz{qwJod|^EVf+0z?p?sw(w@@)XkAeo%q6 zOPM$}0o}%|Mb{7T_+#7wE_!!k6e8~Mxpcc(1yZFVC(}3eKs#8j07;l9xn^|=%Zf!@ zFeO;kpdoseR4^*5A4meZWK-bqlI~$M^+nx=18JWI`R5+I%0%Ip>1~0e6&voCPV&_N zGKFz3);~#B&U}LYtB;b?uBgRR1tyAxyl2Ix&`3b;@{@4b$dQnu# z*Ktps^wL=JYs0^PS6TzF?2z?x#BfT45ofe#!KJ0=Es&NdL4cBBaP#flU(7T-8x1KO zH5Rlyb|Su@vH8H?mkOhBP&1es884IyN6gdW$mhnxQQDRQYT4m-=zc@S;@MXY0NwMX zj*(l+=&^@%!u8s=Og6G%Y=H$h+tnseq7}dgV%_NyaA4eIk;HKj$1fas`7WKsd&+f6 z4?zPUuOo?A3xOn)z$_`@_yJ0@%7A#u74hU>LX+JQg>s^KAN4dY_z^1M&YA-4U|Yhs zA?FbK#1&DKF%3h4fn_6jFqKTZFEJJo-o;+?&%KsdKDhCy2y|-%j6HhrZ$N#i*1HAh zUhH38Og16qx&Y`TcLyjm86(aWBn7#inONdqFx1p6gjlkyAD?A0CAa6w>H2O3G1Yg_1`3ZPqUGfV zX7e*hK(1n%gX-bzKaLi@70mh|lN!r)Vf9=yh=9LtAh1vs&_uc{e4Su#RP z!>NCPFa3^2fJ&}$Yaf;JE`wT~WH?SSlb*>yu>%a>8;?AVxu#F00~%3*q%ec0n4)*8 z^0?|dg?b3;PCyUI%~WmZXL}0GSvT}rGKruo^=6~2WJh5dTjVR~5$4!&gqM*5=}DAJ zh_8s&NzOke2!h25T6<=1ms_pp)zPXhU$-~T#sgw9VcK@&E*F5OWP7EbM>GNw_jLez zk|FC0&sMD^t^n-rHDC;l*u#R0_To76dcem0Swn05fPt6x?f3c@4RL2>KUjicSJFp-(32ykPp);xGG zJ{a#EI*~>M+js-Bi8R8HETWsh{RUmp(O?q-JeC}idt_b)t%ZY7&}yoLlZ!V=3vqRSZ$M9Hh;(i}ir7t2+U=v8R?t zJI=$ z-KRIED~Cz|vQ*aDOJ2KnL70tDmFU*D=$A0CAsl3{PTw>}QJ7Zh#V62i*tCFiZ{Z$D zjh-eA_kh5`j8t9f{MC}%DY^Vve;KAs-?;t#@r^V%HX1jB zz4vZnfp|^WoAeS2L4J)tmRQp_0hF{>e+Oy^X_;YGzwCh2tz5a*(by9F(AT*X3uSa| zsPUWMVh}9-l$V_2aw@NJ4Ja~l5wEq{XEX^F@Luz6(S>?M+RxJg-aI?L2@N9fWew<6&19~6#-eY8DjoK zJ7r6ViYK7p(9ci{;2jU5jL%LBm9};y{{W{cr{1s$UC!;ZJ%7oOpE8D&*N5;)=uTlC zDY>TrOCB^q4JbvG*PZw+qz)E(#~p^A)E07>2l>|&4N#$|EC9t49xcqSD`~!2Yh9u{ zvouXOQ@BYG-t?8rGi3vh_^|=NukS!@vwyo1Vr8KLma3IdEyD@uq3XYKMAAk*LMlxM z>2{&kqm3J56pUEet2+DCL6P4u5AZs=&n|{~YUi1Bp|7cT!;OK!V*9Mb(jMFEheDP5 zLf#NMzJq6<<&W_B-C3pWZbPzdN{3*K_Mox9<7-jOvH}9N0c9@KFNVg@>k!~(%>eCE z>lJvx1vudi(Cu&%2|?4Qqkeklsmq_kd17p;`3=^fN^#_V{iIa<5)wOp7+~**d*B2A z^;%zP16*$+>u+=qLTIU4F%KFtcU6%WdZB6Fbr@a;Pbrz8qQQGf+LKftzM z3oBI&AQj9(=q+w_jv+Bzaszz6+LxdU&a* z$uS)4QL4lY_!ymY+e=z#eu-ckzc$`Q!nG4Q!d;qVTokSD4^*{wjgNHI?+#P}IPdg1 z_ao;poH@V(Gm9I5YIt2&*w||7#i(l;=SXGSPT2yLNvLrs>S!9nOohpNTr@Q$YAUQ# z+2YbwMKr+y4M0HEk4aJ`Xgp;j#C*Oj_#CP2W*e2uNm(joPe>&qEiX`EeCihTgeg_6eqi6B1Bz>H;B?A@Ko|G6~SpQUHU8) zPC7%@3Zgg_cWhte+(P|gAU$GoZ`>zp7PZ@a2M{s>6mp}=tDm?NLiZ#)D1p0v>o|xN zVotgZX(64*W2CSVc4*K}R1Ah2=EIaA=r%|?R0@4W$D;s%vpBvb!nefMiyL&vdi$iJ z^mIg2Jmc=V`R*K`JS?@z0qZuiGya@`RZW^!a7u)Hf%Tpphf<731hy>()tH zwx2>Gmk&KtsYW66e2OI39Jo|gf5>0D>ahhOS`e!jNUcQ-?{m5_17<53^6bPo?tp}e z{mbB#>Eiey-xmFNVv^zG#^iY>kHa4K}6P)M-5m*$y+x}X(slBmB_jMylL&|qkJPh^tLs~9hiC==~rL~1eHYAf034g%M zi+ZFk2|khJ=i^BUTtZM?GKqQYmumIgSENlydUJOPrR@)tg~e?@h5{Su+~S3na@tn; zSWL0jvlO+%*b6d_*8!f2Fo1f48dfB06NMN`15;K;Y1#*G-M>BF%!4p5)Q;}3%=aq9 z>jib#A-N)jVl*NLQkW>#3(#%?;ag7~ac%Zf0ZH3~x#G_s%pAW7>XwsKe?Z?`&%_kj(nz!~_jr*+DZCrLEcCR)fl%rkY;{!JBt0(?kx8N$_41+9|X zH<;Hmj5p@{CwW+%3Q&vgb->bU3kxAKcC_J+9@+#8mjb{*R)OhCZ3Q$W?SmBfruD!U z#IKRZALW)ANGTVCsZ0SfQfjti-Uv`7Le-C;2?{8$m`p_i0$}!^!8M{P?gc}643ts* zY{n!VDh}dgE~XA3VYc7yRmlY;#cBo3Y7c#e>cKlHqKAxrk+@Jb61eREVpz8gm0Eh+ z4tV1ep_Q#p?i$(lF^{ZZeWt@EYx=i1a6GpN0kmJ$#}361%vPjTqM z7TUxtsK`>i->}!^fF^>cphi;(Hhw|&3t zXfjo6rQ&a44p1n5n)`f*aN=4E+p9Y=41k@q34PqUg!_bAn_IHY9*VfNzurfW7U@A! z$gE@N{318muyUG>K#gYmvYZr!Zn1qrF5f2*&aqfu+2FYM>l@SxCGLOL?f!;~mq8rB zk;8Jr+Ur*dXnp;SuB)Pf7b?tW#r*goF2Z4Myt_P5?nR5((%CXzc&Yphd_T*TVeBE zV18Uug(jE)){Dmdhyhh>j5Z)g0qk}%wAj~{T*IUUGOB!i`hh~us|vU_EYQIBk}Hkg zT|gI9o5-=E#pW%q6i!CN$qk|)xD9{lj6lnw%)R*WGdCc$jd?A-6#RTSR$ZKkhz6oL z!ee|y=bKQ48}YAELus}mRd2Gr+!dXSe7R;4Nm-aWxZygD!~`?wyXlQ0L*~x#TeLDU z4~?gl`*#SDdBW1e;IXjJP!k&ke(E#uSXHis*Ccf{$jUmru4I*r(W&u}EUM$w(p*L9 z)2V>{n~`k}yRVn&G*ny?qAnb~>pP9RxjG*KspViVX?L@(X_hO0*um3B2LOU80ok_D zOiTYuASR|plC`;yPxqbNO~A`gYu(DWs$AQ4aLj4Tli*`sz%hCG@f)Q8VSbRWydM)D z+SqEGUAvJLjJl&@@^%RgKgLXc0S8OE0u>SdW@6&{V>^?o0lfRVY)qG5<}le3AFEHc z@B7>b>I%Rs<1*!8?P{V%1@}(Bu!M) zL0D47dutjiF%z;!*V{*D-1Xw;He)ta@^&CbdIm~WN{C%Jzi}l|E=YRj zC}nTji!kP|37`@OFO=cjzSBsm_D|+)q72+#O4=6`(qDHDKnTdF3$5F^$1^Gxc3{EQ z+7+nYBNZ(WgwsT@DhgfsHZ4=Mlq0AM@5(~40NVVd(A#^qse65C&y|ov)z6<_1yYP1 zBBVhX&S%UEJ6ir?nC2w2_S@H zIYA#;7Z|p;)0O#Pr!PI)w~ycqtNqt193+nE2@P7c5f#hxH#tDn390qeUNG5y1yvT& z7?rhh5D@evLNcCfhD=ZVcnD1^rH(IwcIV%7%9IJ3ZY?m0v-m{({Z2sNRH3}-Uf%;< z2cr<2pDy$d_3Yuf=3HP0&Lfn^RLkdIGKh~nVWU{pJ6_>Y`+4vX}bbx3Fk`f?8lf|sgY+z$#mA~>SI&#s5w5whJk?Ta22 zz4xzDpu_tshRPj8FLB82nbA7?2Bn4UzPx?7g>VBlxegTQ%h4c#*<(=xI?DluRiCTE z1MGX_XpjQ*->*w=H3}hS8Zg_Fb9~0`zJi)B49p;~Rwlr=ADI-~{hqHc4{UmUYXc;; zc?P6YdmS#>LYw$!R&sS@)4sf-sohH-n0Bvv3XS&}8TVy?s}kVNpoNv?UpRyYH~d-I zs&H@vJR-bkN$AmFv?DB{pz?m5HixnorX%c%pI(T_MB^xSU2un>_wEJu`H>TmOWn7> zbQF~O@f6_CnWP58o&#m&(>XSX&KoBsg`Fz|o}<%?AAksSWI93&*Z^D`>VOj+Al|8fOSN@eyph_y@#df+YuPy5mNwLFl49JJfLe{SNbF33Jc znaAaVnsg7Sv6j=MNx~`R#1ZmH<{ z;fUYi56WBi{7!oh=*JE(km2_@MI=)_cdP>!cc*8te4qZ6E}wnIQRl6$erMLCQuZ8X z*E?@9>_2JBZpLY;YZ3k8Mf4*p!DmmN3#MIS<}%NyqUPaZ7Cxvdz-9b!Z2$2^igjG! zclQHDSVbzg{5Jmg@71F3iKFlNpzq}g3&Qu@3BL0c zLL8@pWXl$eL-+l2-N6H8QkyViK|0=C=Cr?w~fiSflXef#g{>OJ|@XDl$ ze3Oacw>gOj0=e!^s`>u&@jutJr6DJBUF;BY-M#z0kI)a7smY0S@H%4u<2P||vD{45 zb7N`dbAO-vU%yG7&dx-gMUX1-?|((>1OI~2m1ZAkQg0a`{JmoT+jlfHrP&QAF8=o| zIpz6k6vxE9Dxvy&tv`$Y_Y(1m@af6O|GuS(n>Y#fqEeEMY=7?JU%%-qEf1f{^JD+> zmRg(O4cU6TkNx*52E(VpCYb-erI-T&AFx|XjsLxhhvC!1@16epmPCmO0!!B?qyBpp z|No2qyQTl{ezEa+xX=%GNx)C1Y~*lk>_tYMmhnEu#TnN7=eHkU4BI_hUvCf}>MWg< zHXOg!5U+I$sXF^xNXXpyZxV<1Ky(!D7CXlkxDB?Bp{Xcs=|0Eibk_@c@hYjsYXA4i8ehAQ3%j`6VHc3mE zA6Fx`0~)DTS^AdzvFHpi5e9k@5RgyM`2i(`cv#3Pz!mc4_|aDH@f6|hIW3fT0W9ou^8>V z;DyBhmsW}@%g>AhE}{rTK?OaTIg)b=Q!&u5X>k!Rg*yU%+J#aweN z&=!r>hw?54gxNcQCKC1Q$9<_}pwgU~1rTPk$6~jaRO!veb#wReZOq!=9{H9+8%+Zv*fP;Dm5jT_O7<# zxFvCNjC{T>cM=OtdlA=|F~@9+Phi1Ca)?xVj0CZ@>ks}6pDA|+VzElUZK+LGo5#p}$h+&U(G~j5&7qxFU1DJx#hOS%a>J96kxsqUkdlf2GB_pK<{+ zI_~!UNlkWi;0K4M)v|F(o+bftLjVjd!DeMo4(YIa0^uw*+jEqQ$N1Zuw^{Yt7oY2k zQHKrP*U30L_qN8-I{$V_w&U?Vzc|6`r!6xKPoqs3XeMmWO+EQ`dnrw-sbV%242=mp z1UdIdw4j~sV3c%5Wa!~sw-EcEZ;iLDv@e{f7&~lCB>_SP?v0pp)L|9NTt1bHvGdpY z+ySMr431xAlUi5Kz2$J|2n!QPj;%1TP@fD4{YmBK(NjA3qGF{WI|ZWk8^${NK+w__ zPb?!^1#{p?C+Y6wav@LS%!e^gc_#zZ(5PNIU*Vz6z+7)AXW|SumwuZl6}LcFJFX=BFN)1hdlsbcRI3jAK$dFnl6-kAU_uAHRs}9iku|zeF{*Lq7eh?KXl9Xk<&C?&o+s}P zT2Q=1?Y=d`&_Z&qX5B5M)e%;6?h5|}h3a5`3(arbL!OzM>}3GFa-VL}&o~1cj3>(t zfPgdsv)b!E*KXLl$(AZ4{D9)*(@gQ^{?&@r@}(ek&x*6uO8fSaaw*H5znnPS@ks9$ z#Qf}GJJ7DuST85{mMm~u_S?^Rz+sIFzbFn~%Ol&%225sYEog{}7P0vk*y%@^M~>N) z+i)Mh!E)_mNm-5P;7m~NijNxh1P-nwoaA$d@d%tQGvPMg(S1l0gBg_|S`~S{p;rda zdbf$-%p%PRyMXdgy=|-E+ebEPMJsaC?dZ>&yVclk-_aC2`K$WE08D8q>%}S2U4QU% zO~B~6e&jhXckSrJu5Nbfuoo2+tcoFg{55S&o zXGEiQv>W%tZ{mTKnDrFRq$CpMGN*}Y4W$=*=Nl$}e3WDc zGfx;P02b|kI9gR)u;!+@Zn_zCVXEwO1;|jpzcpB&VBcA{J!3AVPY-H73TD9k6a=Iw z`-~^(x!hO|oOb2S;^S$XvJoW?G_xHQBw3H77-4W~J^zK(3E6Jbj&xz7zy>a#q%3>9 z$tJy-zA~U|95zfGyX~36tLMc&&|mAl9;6v!1KA&EEh1aFcUszZsY&f-PJVL~|Gbk; zOF7BmLA~uwZ*H0|P!TM}AGipSK`Sd9z8EGFSzl>qNC@8%SSIn>C(*oBhnvKX*o!4U zbT`%HG*#8_-*3)>1N~%0y;^uXL6e={ zIIzK0FHHP1h1F`;wZ)RMgAQVmaCmpN=Y7%uFs|$wPPAQ+7+eS&iPR|ObFSNsP;T9q z&eJH4olm_YGt4fgGsv9G4K3$W(eEf_h6}zqPVf?tr}IJ3qEMbtlsv;kL0^G;1H)n86+`hyi|=TV*)=2-02($B|j@t z^+5b)Qy?obDGE4g#!LD94UJ;mRxau} zl`jr|SGTHAKkaW6HP;+vPyXPy?7iv$q&!A_SF)^USZot5Q zcLHJ+Uan>G0ykv97JVF!U(|VJ6?BEP) zSC5(Aq<^%pqzHRY-;H5ZOg?kunVR_PVN0kZsJEHtHHoNzE{`&>*^RZ6iY~ydo*g?b z!Q!)8I;0BvfesE6y=IS8Vd*%$ZQ*7w3<))#VVZ}fYl54Q;%YefuE;Qf{HMl2Omt2b=YP1R5(U+DvW!0E=MXO=?i zL+X77cXkrSb7eggiDlIkiu9WFT=zfZ){BT(H0T@OV1$ZgH?^=UGkGZgDvHHW`0V1I z@hS9hY1_)6$9z8Yd)#w94bxkkfL%^gw}>eXl^K4Uh2fO{0mSU~)81Qa)T^E8FLbo4 zr^X?eEuQFOr_K_^K&sIW(N^ydx?I6Eh;O;V#*fX_@Il^u?h}UcZBMlu9m z>(usIom4ZaC{bWiwS2~dX8m={@~Q!EP;LWn>GjoTMd0rOrckWemaR(| zeDzm4@mpkuwa>lZ*xN&edk>PZE#|lid)gS#5^pVLN+yl-OdkfpQV7=scb6e!r-Fan zNn^n=AcApwLeZnMj_3Y|w)L{b<_7Jpv030vs8I;o<+mx+%%A+U{eiaP@e9vS{b}cx zUpoP`PAeq^YLb?a3aV&koz%-PG0HJHuN`*6PN3N`EjGLvg3A%t2xD)zXt4Gxj^M~q zkO%cVX9u+m+b~QevcsW$$6W`WTq_zYJMP#hpsO5I23GXj8b{j8OG4SmVaCEq66VT@ zyE77$p?#adqRtJoUSve^a+n9ZR-c;m7tH(0^2+1w3 zd&IE%mxiayYodwb2!XHy>oZIkT~ znQItug(>bUt)bEHG?2PGdG>1)8NExdsjlzw1PA&`C{2YpUVCA0eIeq0L6a3xOQb+j zs?m=J6wK{)=T>s9{mbsW4im3}?y>Bs7GO0PKQDT)A5Keex-FEFCxKMXTl?U#g!Xks z)iIDSV2kkqPY+72*NTlysEAE~%46YaWId{>+L}b{ONC~$83FC1RZH>@Y zDuD=~Nk`r_s-m)PJEsh?z;CX(l%lxZ05}%59F;p#3bo(p9APPr3m2>F2Y!w@haP-* zxEgg>1~2^V=B74+lu+B{WENH@q*Yv-1DHjxQ*S|hDh{Wwd=jPzwcyTI=;8f9c?wW) zGA22}#5V7m*nNH#U9$-D(h$?t1R<{1LWpsOn3PCzNb7oo@vqxW!PqjbfcKhuBXBI;gDZQAZnF=h zk2z$#3|set6!DF&@XJTSfL=6ym1W$}&@+#9b~i}!KH&Pikv;nqZ=A-EXcksqay(*T z!Jcz38)BliV4)7PtQ>IdxT+!GFj6hUlqF%^n=>g-MQlo3^5uQShbbGEI7A_gv%1 zInO&RK?HJUYMQmC{v;xwL>&9A-e%I>OU@)^z*#YSBpKec07dlAA`Ky`qwd6a^^fNj zdFLh=cG`dnjvEj=E~BhsMUiFN-P?04DM6rH)%;lGmyqI6=aRMk+dEw!Ind|v{;*$3M@mos=RN)Zhuz)E|4+Wzo&B!V WXT}a6B5>IU|0&C>$z{oy-2GorTW|gV From 255b477d23ba785a48de72bb25d18071a7eee4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Wed, 3 Jun 2026 06:21:52 +0200 Subject: [PATCH 21/31] handle link events as any inbound triggers --- dist/Context.js | 43 ++++ dist/activity/Activity.js | 133 ++++++++++-- dist/eventDefinitions/LinkEventDefinition.js | 67 +----- dist/events/IntermediateCatchEvent.js | 3 +- dist/events/IntermediateThrowEvent.js | 3 +- dist/gateways/ParallelGateway.js | 4 +- dist/process/ProcessExecution.js | 11 +- docs/Extend.md | 13 ++ docs/ParallelGateway.md | 6 +- src/Context.js | 44 ++++ src/activity/Activity.js | 109 ++++++++-- src/eventDefinitions/LinkEventDefinition.js | 55 +---- src/events/IntermediateCatchEvent.js | 6 +- src/events/IntermediateThrowEvent.js | 6 +- src/gateways/ParallelGateway.js | 2 +- src/process/ProcessExecution.js | 11 +- test/Context-test.js | 74 +++++++ test/activities-test.js | 1 + test/activity/ActivityExecution-test.js | 1 - .../LinkEventDefinition-test.js | 82 +------- test/events/IntermediateCatchEvent-test.js | 107 ++++++++++ test/feature/Process-feature.js | 4 +- test/feature/link-as-goto-feature.js | 194 ++++++++++++++++++ test/feature/linking-feature.js | 78 +++++++ test/feature/multiple-startevent-feature.js | 99 +++++++++ test/feature/parallel-gateway-fork-feature.js | 74 +++++++ test/feature/skip-discard-feature.js | 3 +- test/resources/link-multiple-catch.bpmn | 108 ++++++++++ test/resources/link-multiple.bpmn | 129 ++++++++++++ types/index.d.ts | 13 ++ 30 files changed, 1235 insertions(+), 248 deletions(-) create mode 100644 test/resources/link-multiple-catch.bpmn create mode 100644 test/resources/link-multiple.bpmn diff --git a/dist/Context.js b/dist/Context.js index 9aa75100..af45ef9c 100644 --- a/dist/Context.js +++ b/dist/Context.js @@ -312,6 +312,49 @@ ContextInstance.prototype.getStartActivities = function getStartActivities(filte return result; }; +/** + * Inspect an activity def for link event definitions. + * @param {import('moddle-context-serializer').Activity} activityDef + * @returns {{ linkBehaviour?: Function, linkNames?: string[] }} + */ +ContextInstance.prototype.getLinkEventDefinitionInfo = function getLinkEventDefinitionInfo(activityDef) { + const eds = activityDef.behaviour?.eventDefinitions; + if (!eds) return {}; + let linkBehaviour; + const names = new Set(); + for (const ed of eds) { + if (linkBehaviour ? ed.Behaviour === linkBehaviour : ed.type?.endsWith('LinkEventDefinition')) { + if (!linkBehaviour) linkBehaviour = ed.Behaviour; + if (ed.behaviour?.name) names.add(ed.behaviour.name); + } + } + if (!linkBehaviour || !names.size) return {}; + return { + linkBehaviour, + linkNames: [...names] + }; +}; + +/** + * Get activities whose event definitions include the given Behaviour with a matching name. + * @param {Function} Behaviour Behaviour constructor to match against `ed.Behaviour` + * @param {string[] | Iterable} names + * @param {string} [scopeId] Process or sub-process id + */ +ContextInstance.prototype.getActivitiesByEventDefinitionBehaviour = function getActivitiesByEventDefinitionBehaviour(Behaviour, names, scopeId) { + const wanted = new Set(names); + if (!Behaviour || !wanted.size) return []; + const result = []; + const rawDefs = this.definitionContext.getActivities(scopeId) || []; + for (const rawDef of rawDefs) { + const eds = rawDef.behaviour?.eventDefinitions; + if (!eds) continue; + if (!eds.some(ed => ed.Behaviour === Behaviour && wanted.has(ed.behaviour?.name))) continue; + result.push(this.upsertActivity(rawDef)); + } + return result; +}; + /** * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. * Returns undefined when the activity has no extensions to attach. diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 736d1b04..8602e4da 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -45,7 +45,11 @@ function Activity(Behaviour, activityDef, context) { /** @type {import('moddle-context-serializer').ActivityBehaviour} */ this.behaviour = { ...behaviour, - eventDefinitions + eventDefinitions, + ...(activityDef.linkNames && { + linkNames: activityDef.linkNames, + linkBehaviour: activityDef.linkBehaviour + }) }; this.Behaviour = Behaviour; /** @type {import('moddle-context-serializer').Parent} */ @@ -80,14 +84,7 @@ function Activity(Behaviour, activityDef, context) { this.emitFatal = emitFatal; const inboundSequenceFlows = context.getInboundSequenceFlows(id); const inboundAssociations = context.getInboundAssociations(id); - let inboundTriggers; - if (attachedToActivity) { - inboundTriggers = [attachedToActivity]; - } else if (isForCompensation) { - inboundTriggers = inboundAssociations.slice(); - } else { - inboundTriggers = inboundSequenceFlows.slice(); - } + const hasInboundTrigger = attachedToActivity ? true : isForCompensation ? !!inboundAssociations.length : !!inboundSequenceFlows.length; const outboundSequenceFlows = context.getOutboundSequenceFlows(id); const inboundSourceIds = new Set(inboundSequenceFlows.map(({ sourceId @@ -96,13 +93,13 @@ function Activity(Behaviour, activityDef, context) { this[K_FLOWS] = { inboundSequenceFlows, inboundAssociations, - inboundTriggers, + inboundTriggers: undefined, outboundSequenceFlows, outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows) }; this[K_FLAGS] = { isEnd: !outboundSequenceFlows.length, - isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, + isStart: !hasInboundTrigger && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, isMultiInstance: !!behaviour.loopCharacteristics, isForCompensation, @@ -111,6 +108,8 @@ function Activity(Behaviour, activityDef, context) { isParallelJoin, isParallelGateway: activityDef.isParallelGateway, isThrowing: activityDef.isThrowing, + linkNames: activityDef.linkNames, + linkBehaviour: activityDef.linkBehaviour, isCatching: activityDef.isCatching, lane: activityDef.lane?.id }; @@ -226,6 +225,11 @@ Object.defineProperties(Activity.prototype, { return this[K_FLAGS].isParallelJoin; } }, + isParallelGateway: { + get() { + return this[K_FLAGS].isParallelGateway; + } + }, triggeredByEvent: { get() { return this[K_ACTIVITY_DEF].triggeredByEvent; @@ -273,6 +277,35 @@ Activity.prototype.activate = function activate() { return this.addInboundListeners() && this._consumeInbound(); }; +/** @internal */ +Activity.prototype._getInboundTriggers = function _getInboundTriggers() { + const flows = this[K_FLOWS]; + if (flows.inboundTriggers) return flows.inboundTriggers; + const flags = this[K_FLAGS]; + let triggers; + if (flags.attachedTo) { + triggers = [this.context.getActivityById(flags.attachedTo)]; + } else if (flags.isForCompensation) { + triggers = flows.inboundAssociations.slice(); + } else { + triggers = flows.inboundSequenceFlows.slice(); + } + const { + isCatching, + linkNames, + linkBehaviour + } = flags; + if (isCatching && linkNames?.length) { + const known = new Set(triggers.map(t => t.id)); + for (const source of this.context.getActivitiesByEventDefinitionBehaviour(linkBehaviour, linkNames)) { + if (source.id === this.id || !source.isThrowing || known.has(source.id)) continue; + triggers.push(source); + known.add(source.id); + } + } + return flows.inboundTriggers = triggers; +}; + /** * Cancel inbound subscriptions and any pending run/format consumers. */ @@ -417,7 +450,7 @@ Activity.prototype.discard = function discard(discardContent) { * @returns {number} count of subscribed triggers */ Activity.prototype.addInboundListeners = function addInboundListeners() { - const triggers = this[K_FLOWS].inboundTriggers; + const triggers = this._getInboundTriggers(); if (triggers.length) { const onInboundEvent = this._onInboundEvent.bind(this); const triggerConsumerTag = `_inbound-${this.id}`; @@ -447,8 +480,10 @@ Activity.prototype.addInboundListeners = function addInboundListeners() { * Cancel inbound trigger subscriptions added by addInboundListeners. */ Activity.prototype.removeInboundListeners = function removeInboundListeners() { + const triggers = this[K_FLOWS].inboundTriggers; + if (!triggers) return; const triggerConsumerTag = `_inbound-${this.id}`; - for (const trigger of this[K_FLOWS].inboundTriggers) { + for (const trigger of triggers) { trigger.broker.cancel(triggerConsumerTag); } }; @@ -595,6 +630,20 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { persistent: false, type: 'shake' }); + if (this[K_FLAGS].isThrowing && this[K_FLAGS].linkNames?.length) { + for (const linkName of this[K_FLAGS].linkNames) { + this.broker.publish('event', 'activity.shake.link', (0, _messageHelper.cloneContent)(message.content, { + sourceId: this.id, + message: { + id: linkName, + linkName, + referenceType: 'link' + } + }), { + type: 'shake' + }); + } + } if (this[K_FLAGS].isEnd) { return this.broker.publish('event', 'activity.shake.end', (0, _messageHelper.cloneContent)(message.content), { persistent: false, @@ -614,7 +663,7 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { /** @internal */ Activity.prototype._consumeInbound = function consumeInbound() { if (!this[_constants.K_ACTIVATED]) return; - if (this.status || !this[K_FLOWS].inboundTriggers.length) return; + if (this.status || !this._getInboundTriggers().length) return; const inboundQ = this.broker.getQueue('inbound-q'); const onInbound = this[_constants.K_MESSAGE_HANDLERS].onInbound; return inboundQ.assertConsumer(onInbound, { @@ -630,6 +679,12 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { const content = message.content; const inbound = [(0, _messageHelper.cloneContent)(content)]; switch (routingKey) { + case 'activity.relink': + if (content.executionId) this[K_EXEC].set('initExecutionId', content.executionId); + return this.run({ + message: content.message, + inbound + }); case 'association.take': case 'flow.take': case 'activity.restart': @@ -672,6 +727,56 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message case 'flow.shake': case 'activity.shake.start': return this._onShakeMessage(message); + case 'activity.link': + { + const linkName = content.message?.linkName; + if (!this[K_FLAGS].linkNames?.includes(linkName)) break; + const executionId = (0, _shared.getUniqueId)(this.id); + this.broker.publish('event', 'activity.enter', (0, _messageHelper.cloneContent)(content, { + id: this.id, + type: this.type, + executionId, + state: 'enter', + message: { + ...content.message + } + })); + inboundQ.queueMessage({ + routingKey: 'activity.relink' + }, (0, _messageHelper.cloneContent)(content, { + id: this.id, + executionId, + message: { + ...content.message + } + }), properties); + return; + } + case 'activity.shake.link': + { + const linkName = content.message?.linkName; + if (!this[K_FLAGS].linkNames?.includes(linkName)) break; + const linkedContent = (0, _messageHelper.cloneContent)(content, { + targetId: this.id, + isLinked: true + }); + linkedContent.sequence = linkedContent.sequence || []; + linkedContent.sequence.push({ + id: this.id, + type: this.type + }); + this.broker.publish('event', 'activity.shake.linked', linkedContent, { + persistent: false, + type: 'shake' + }); + const outbound = this.outbound; + if (outbound?.length) { + for (const flow of outbound) flow.shake({ + content: (0, _messageHelper.cloneContent)(linkedContent) + }); + } + break; + } case 'association.take': case 'flow.take': case 'flow.discard': diff --git a/dist/eventDefinitions/LinkEventDefinition.js b/dist/eventDefinitions/LinkEventDefinition.js index 91afe04a..a910b1a5 100644 --- a/dist/eventDefinitions/LinkEventDefinition.js +++ b/dist/eventDefinitions/LinkEventDefinition.js @@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.LinkEventDefinition = LinkEventDefinition; -var _shared = require("../shared.js"); var _messageHelper = require("../messageHelper.js"); var _constants = require("../constants.js"); /** @@ -36,40 +35,6 @@ function LinkEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - if (isThrowing) { - broker.subscribeTmp('api', 'activity.shake.start', (_, msg) => { - broker.publish('event', `activity.shake.${this.reference.referenceType}`, (0, _messageHelper.cloneContent)(msg.content, { - sourceId: this.id, - targetId: undefined, - message: { - ...this.reference - } - }), { - type: 'shake' - }); - }, { - noAck: true, - consumerTag: '_link-parent-shake', - priority: 1000 - }); - } else { - broker.subscribeTmp('api', `activity.shake.${this.reference.referenceType}`, this._onShakeMessage.bind(this), { - noAck: true, - consumerTag: '_link-catch-shake' - }); - const queueName = `link-${(0, _shared.brokerSafeId)(id)}-${(0, _shared.brokerSafeId)(this.reference.linkName)}-q`; - broker.assertQueue(queueName, { - autoDelete: false, - durable: true - }); - broker.bindQueue(queueName, 'api', '*.link.#', { - durable: true - }); - broker.consume(queueName, this._onLinkApiMessage.bind(this), { - noAck: true, - consumerTag: '_link-catch-listener' - }); - } } Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { /** @returns {string} */ @@ -141,37 +106,7 @@ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessag }); linkContent.parent = (0, _messageHelper.shiftParent)(parent); broker.publish('event', 'activity.link', linkContent, { - type: 'link', - delegate: true + type: 'link' }); return broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(executeContent)); -}; -LinkEventDefinition.prototype._onLinkApiMessage = function onLinkApiMessage(_, message) { - if (message.properties.type !== 'link') return; - if (message.content.message?.linkName !== this.reference.linkName) return; - if (this.activity.isRunning) return; - this.activity.run(message.content.message); -}; -LinkEventDefinition.prototype._onShakeMessage = function onShakeMessage(_, message) { - if (message.properties.type !== 'shake') return; - if (message.content.message?.linkName !== this.reference.linkName) return; - const content = (0, _messageHelper.cloneContent)(message.content, { - targetId: this.id, - isLinked: true - }); - content.sequence = content.sequence || []; - content.sequence.push({ - id: this.id, - type: this.type - }); - this.broker.publish('event', 'activity.shake.linked', content, { - persistent: false, - type: 'shake' - }); - const outbound = this.activity.outbound; - if (outbound?.length) { - for (const flow of outbound) flow.shake({ - content: (0, _messageHelper.cloneContent)(content) - }); - } }; \ No newline at end of file diff --git a/dist/events/IntermediateCatchEvent.js b/dist/events/IntermediateCatchEvent.js index 0a34cf10..acb5bd90 100644 --- a/dist/events/IntermediateCatchEvent.js +++ b/dist/events/IntermediateCatchEvent.js @@ -17,7 +17,8 @@ var _constants = require("../constants.js"); function IntermediateCatchEvent(activityDef, context) { return new _Activity.Activity(IntermediateCatchEventBehaviour, { ...activityDef, - isCatching: true + isCatching: true, + ...context.getLinkEventDefinitionInfo(activityDef) }, context); } diff --git a/dist/events/IntermediateThrowEvent.js b/dist/events/IntermediateThrowEvent.js index f7bae9ef..6b6d2f9c 100644 --- a/dist/events/IntermediateThrowEvent.js +++ b/dist/events/IntermediateThrowEvent.js @@ -17,7 +17,8 @@ var _constants = require("../constants.js"); function IntermediateThrowEvent(activityDef, context) { return new _Activity.Activity(IntermediateThrowEventBehaviour, { ...activityDef, - isThrowing: true + isThrowing: true, + ...context.getLinkEventDefinitionInfo(activityDef) }, context); } diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 25c9dcce..8f69ba9a 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -66,9 +66,7 @@ function ParallelGatewayBehaviour(activity) { this.activity = activity; this.broker = activity.broker; this.inbound = new Set(); - this.isConverging = new Set(activity.inbound.map(({ - sourceId - }) => sourceId)).size > 1; + this.isConverging = true; this[_constants.K_EXECUTE_MESSAGE] = undefined; } Object.defineProperty(ParallelGatewayBehaviour.prototype, 'executionId', { diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 280f8d8e..505f8863 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -477,7 +477,7 @@ ProcessExecution.prototype._activate = function activate() { startActivities.add(activity); } if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); - if (activity.isParallelJoin) convergingGateways.add(activity); + if (activity.isParallelGateway) convergingGateways.add(activity); } if (startActivities.size > 1) { for (const activity of startActivities) { @@ -592,8 +592,13 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { type: 'shake' }); } - if (result.settings.skipDiscard && convergingGateways.size) { - result.settings.skipDiscard = false; + if (result.settings.skipDiscard) { + for (const aid of convergingGateways.keys()) { + if (this.getActivityById(aid).isParallelGateway) { + result.settings.skipDiscard = false; + break; + } + } } if (!executing) this._deactivate(); this.broker.cancel(consumerTag); diff --git a/docs/Extend.md b/docs/Extend.md index 64c6cded..b4717077 100644 --- a/docs/Extend.md +++ b/docs/Extend.md @@ -173,3 +173,16 @@ function getModdleContext(sourceXml) { return bpmnModdle.fromXML(sourceXml.trim()); } ``` + +# Replacing `LinkEventDefinition` + +Link catches are wired to their matching throws at activity construction. The wiring reads each activity's `behaviour.eventDefinitions` through `context.getLinkEventDefinitionInfo(activityDef)`, which discovers the resolved link Behaviour and its link names. If you ship your own `LinkEventDefinition`, the wiring keeps working as long as the contract below holds: + +- The moddle entity's `type` must end with `LinkEventDefinition` (e.g. `bpmn:LinkEventDefinition`, `myns:LinkEventDefinition`). This is the only string-based check — once the first matching definition is found, all subsequent matches compare against the resolved `Behaviour` reference, so any rename is honoured. +- Expose the link name on `behaviour.name` (the moddle default). +- The Behaviour signature is `(activity, eventDefinition, context, index)`. +- When throwing (`activity.isThrowing`), publish `activity.link` on the activity's `event` exchange with `content.message.linkName` set. The catch's construction-time inbound trigger listens for this and queues an `activity.relink` to drive the catch's run cycle. +- Publish `execute.completed` on the `execution` exchange so the throwing activity terminates. +- When catching, publish `activity.catch` on the `event` exchange and complete with `execute.completed`. `Activity` drives the rest of the lifecycle. + +Shake propagation (`activity.shake.link` / `activity.shake.linked`) is emitted by `Activity` from the `linkNames` exposed by `getLinkEventDefinitionInfo` — your event definition does not need to subscribe to or republish shake events. diff --git a/docs/ParallelGateway.md b/docs/ParallelGateway.md index 2b1e3e0c..4314b27c 100644 --- a/docs/ParallelGateway.md +++ b/docs/ParallelGateway.md @@ -4,10 +4,10 @@ Join or fork gateway. ## Converging behaviour -A parallel gateway is converging when its inbound sequence flows originate from more than one source. Instead of completing as soon as the expected number of inbound flows have been touched, the gateway monitors its upstream peer activities and completes once they have all settled. +A parallel gateway — fork or join — monitors its upstream peer activities and completes once they have all settled, rather than completing as soon as the expected number of inbound flows have been touched. Peers are discovered during the process shake. -This avoids stalls in the edge case where the same inbound flow may be touched more than once before all peers have reported. The outcome is `taken` if any inbound flow was taken, otherwise `discarded`. +This avoids stalls in the edge case where the same inbound flow may be touched more than once before all peers have reported, and lets a single-inbound fork correctly wait for parallel upstream branches before taking its outbound flows. The outcome is `taken` if any inbound flow was taken, otherwise `discarded`. ## Events -- `activity.converge`: The converging parallel gateway is collecting inbound and monitoring peers +- `activity.converge`: The parallel gateway is collecting inbound and monitoring peers diff --git a/src/Context.js b/src/Context.js index cdc33eee..ad5662a3 100644 --- a/src/Context.js +++ b/src/Context.js @@ -332,6 +332,50 @@ ContextInstance.prototype.getStartActivities = function getStartActivities(filte return result; }; +/** + * Inspect an activity def for link event definitions. + * @param {import('moddle-context-serializer').Activity} activityDef + * @returns {{ linkBehaviour?: Function, linkNames?: string[] }} + */ +ContextInstance.prototype.getLinkEventDefinitionInfo = function getLinkEventDefinitionInfo(activityDef) { + const eds = activityDef.behaviour?.eventDefinitions; + if (!eds) return {}; + let linkBehaviour; + const names = new Set(); + for (const ed of eds) { + if (linkBehaviour ? ed.Behaviour === linkBehaviour : ed.type?.endsWith('LinkEventDefinition')) { + if (!linkBehaviour) linkBehaviour = ed.Behaviour; + if (ed.behaviour?.name) names.add(ed.behaviour.name); + } + } + if (!linkBehaviour || !names.size) return {}; + return { linkBehaviour, linkNames: [...names] }; +}; + +/** + * Get activities whose event definitions include the given Behaviour with a matching name. + * @param {Function} Behaviour Behaviour constructor to match against `ed.Behaviour` + * @param {string[] | Iterable} names + * @param {string} [scopeId] Process or sub-process id + */ +ContextInstance.prototype.getActivitiesByEventDefinitionBehaviour = function getActivitiesByEventDefinitionBehaviour( + Behaviour, + names, + scopeId +) { + const wanted = new Set(names); + if (!Behaviour || !wanted.size) return []; + const result = []; + const rawDefs = this.definitionContext.getActivities(scopeId) || []; + for (const rawDef of rawDefs) { + const eds = rawDef.behaviour?.eventDefinitions; + if (!eds) continue; + if (!eds.some((ed) => ed.Behaviour === Behaviour && wanted.has(ed.behaviour?.name))) continue; + result.push(this.upsertActivity(rawDef)); + } + return result; +}; + /** * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. * Returns undefined when the activity has no extensions to attach. diff --git a/src/activity/Activity.js b/src/activity/Activity.js index ab1cb0a9..33add07f 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -39,7 +39,11 @@ export function Activity(Behaviour, activityDef, context) { this.type = type; this.name = name; /** @type {import('moddle-context-serializer').ActivityBehaviour} */ - this.behaviour = { ...behaviour, eventDefinitions }; + this.behaviour = { + ...behaviour, + eventDefinitions, + ...(activityDef.linkNames && { linkNames: activityDef.linkNames, linkBehaviour: activityDef.linkBehaviour }), + }; this.Behaviour = Behaviour; /** @type {import('moddle-context-serializer').Parent} */ this.parent = activityDef.parent ? cloneParent(activityDef.parent) : {}; @@ -72,14 +76,8 @@ export function Activity(Behaviour, activityDef, context) { const inboundSequenceFlows = context.getInboundSequenceFlows(id); const inboundAssociations = context.getInboundAssociations(id); - let inboundTriggers; - if (attachedToActivity) { - inboundTriggers = [attachedToActivity]; - } else if (isForCompensation) { - inboundTriggers = inboundAssociations.slice(); - } else { - inboundTriggers = inboundSequenceFlows.slice(); - } + const hasInboundTrigger = attachedToActivity ? true : isForCompensation ? !!inboundAssociations.length : !!inboundSequenceFlows.length; + const outboundSequenceFlows = context.getOutboundSequenceFlows(id); const inboundSourceIds = new Set(inboundSequenceFlows.map(({ sourceId }) => sourceId)); @@ -88,14 +86,14 @@ export function Activity(Behaviour, activityDef, context) { this[K_FLOWS] = { inboundSequenceFlows, inboundAssociations, - inboundTriggers, + inboundTriggers: undefined, outboundSequenceFlows, outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows), }; this[K_FLAGS] = { isEnd: !outboundSequenceFlows.length, - isStart: !inboundTriggers.length && !behaviour.triggeredByEvent && !activityDef.isCatching, + isStart: !hasInboundTrigger && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, isMultiInstance: !!behaviour.loopCharacteristics, isForCompensation, @@ -104,6 +102,8 @@ export function Activity(Behaviour, activityDef, context) { isParallelJoin, isParallelGateway: activityDef.isParallelGateway, isThrowing: activityDef.isThrowing, + linkNames: activityDef.linkNames, + linkBehaviour: activityDef.linkBehaviour, isCatching: activityDef.isCatching, lane: activityDef.lane?.id, }; @@ -219,6 +219,11 @@ Object.defineProperties(Activity.prototype, { return this[K_FLAGS].isParallelJoin; }, }, + isParallelGateway: { + get() { + return this[K_FLAGS].isParallelGateway; + }, + }, triggeredByEvent: { get() { return this[K_ACTIVITY_DEF].triggeredByEvent; @@ -266,6 +271,34 @@ Activity.prototype.activate = function activate() { return this.addInboundListeners() && this._consumeInbound(); }; +/** @internal */ +Activity.prototype._getInboundTriggers = function _getInboundTriggers() { + const flows = this[K_FLOWS]; + if (flows.inboundTriggers) return flows.inboundTriggers; + + const flags = this[K_FLAGS]; + let triggers; + if (flags.attachedTo) { + triggers = [this.context.getActivityById(flags.attachedTo)]; + } else if (flags.isForCompensation) { + triggers = flows.inboundAssociations.slice(); + } else { + triggers = flows.inboundSequenceFlows.slice(); + } + + const { isCatching, linkNames, linkBehaviour } = flags; + if (isCatching && linkNames?.length) { + const known = new Set(triggers.map((t) => t.id)); + for (const source of this.context.getActivitiesByEventDefinitionBehaviour(linkBehaviour, linkNames)) { + if (source.id === this.id || !source.isThrowing || known.has(source.id)) continue; + triggers.push(source); + known.add(source.id); + } + } + + return (flows.inboundTriggers = triggers); +}; + /** * Cancel inbound subscriptions and any pending run/format consumers. */ @@ -411,7 +444,7 @@ Activity.prototype.discard = function discard(discardContent) { * @returns {number} count of subscribed triggers */ Activity.prototype.addInboundListeners = function addInboundListeners() { - const triggers = this[K_FLOWS].inboundTriggers; + const triggers = this._getInboundTriggers(); if (triggers.length) { const onInboundEvent = this._onInboundEvent.bind(this); const triggerConsumerTag = `_inbound-${this.id}`; @@ -432,8 +465,10 @@ Activity.prototype.addInboundListeners = function addInboundListeners() { * Cancel inbound trigger subscriptions added by addInboundListeners. */ Activity.prototype.removeInboundListeners = function removeInboundListeners() { + const triggers = this[K_FLOWS].inboundTriggers; + if (!triggers) return; const triggerConsumerTag = `_inbound-${this.id}`; - for (const trigger of this[K_FLOWS].inboundTriggers) { + for (const trigger of triggers) { trigger.broker.cancel(triggerConsumerTag); } }; @@ -573,6 +608,17 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { this.broker.publish('api', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); + if (this[K_FLAGS].isThrowing && this[K_FLAGS].linkNames?.length) { + for (const linkName of this[K_FLAGS].linkNames) { + this.broker.publish( + 'event', + 'activity.shake.link', + cloneContent(message.content, { sourceId: this.id, message: { id: linkName, linkName, referenceType: 'link' } }), + { type: 'shake' } + ); + } + } + if (this[K_FLAGS].isEnd) { return this.broker.publish('event', 'activity.shake.end', cloneContent(message.content), { persistent: false, type: 'shake' }); } @@ -593,7 +639,7 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { Activity.prototype._consumeInbound = function consumeInbound() { if (!this[K_ACTIVATED]) return; - if (this.status || !this[K_FLOWS].inboundTriggers.length) return; + if (this.status || !this._getInboundTriggers().length) return; const inboundQ = this.broker.getQueue('inbound-q'); const onInbound = this[K_MESSAGE_HANDLERS].onInbound; @@ -611,6 +657,12 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { const inbound = [cloneContent(content)]; switch (routingKey) { + case 'activity.relink': + if (content.executionId) this[K_EXEC].set('initExecutionId', content.executionId); + return this.run({ + message: content.message, + inbound, + }); case 'association.take': case 'flow.take': case 'activity.restart': @@ -645,6 +697,35 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message case 'flow.shake': case 'activity.shake.start': return this._onShakeMessage(message); + case 'activity.link': { + const linkName = content.message?.linkName; + if (!this[K_FLAGS].linkNames?.includes(linkName)) break; + const executionId = getUniqueId(this.id); + this.broker.publish( + 'event', + 'activity.enter', + cloneContent(content, { id: this.id, type: this.type, executionId, state: 'enter', message: { ...content.message } }) + ); + inboundQ.queueMessage( + { routingKey: 'activity.relink' }, + cloneContent(content, { id: this.id, executionId, message: { ...content.message } }), + properties + ); + return; + } + case 'activity.shake.link': { + const linkName = content.message?.linkName; + if (!this[K_FLAGS].linkNames?.includes(linkName)) break; + const linkedContent = cloneContent(content, { targetId: this.id, isLinked: true }); + linkedContent.sequence = linkedContent.sequence || []; + linkedContent.sequence.push({ id: this.id, type: this.type }); + this.broker.publish('event', 'activity.shake.linked', linkedContent, { persistent: false, type: 'shake' }); + const outbound = this.outbound; + if (outbound?.length) { + for (const flow of outbound) flow.shake({ content: cloneContent(linkedContent) }); + } + break; + } case 'association.take': case 'flow.take': case 'flow.discard': diff --git a/src/eventDefinitions/LinkEventDefinition.js b/src/eventDefinitions/LinkEventDefinition.js index 71dd4b46..24830cc3 100644 --- a/src/eventDefinitions/LinkEventDefinition.js +++ b/src/eventDefinitions/LinkEventDefinition.js @@ -1,4 +1,3 @@ -import { brokerSafeId } from '../shared.js'; import { cloneContent, shiftParent } from '../messageHelper.js'; import { K_EXECUTE_MESSAGE } from '../constants.js'; @@ -25,34 +24,6 @@ export function LinkEventDefinition(activity, eventDefinition) { this.activity = activity; this.broker = broker; this.logger = environment.Logger(type.toLowerCase()); - - if (isThrowing) { - broker.subscribeTmp( - 'api', - 'activity.shake.start', - (_, msg) => { - broker.publish( - 'event', - `activity.shake.${this.reference.referenceType}`, - cloneContent(msg.content, { sourceId: this.id, targetId: undefined, message: { ...this.reference } }), - { type: 'shake' } - ); - }, - { noAck: true, consumerTag: '_link-parent-shake', priority: 1000 } - ); - } else { - broker.subscribeTmp('api', `activity.shake.${this.reference.referenceType}`, this._onShakeMessage.bind(this), { - noAck: true, - consumerTag: '_link-catch-shake', - }); - const queueName = `link-${brokerSafeId(id)}-${brokerSafeId(this.reference.linkName)}-q`; - broker.assertQueue(queueName, { autoDelete: false, durable: true }); - broker.bindQueue(queueName, 'api', '*.link.#', { durable: true }); - broker.consume(queueName, this._onLinkApiMessage.bind(this), { - noAck: true, - consumerTag: '_link-catch-listener', - }); - } } Object.defineProperty(LinkEventDefinition.prototype, 'executionId', { @@ -114,31 +85,7 @@ LinkEventDefinition.prototype.executeThrow = function executeThrow(executeMessag }); linkContent.parent = shiftParent(parent); - broker.publish('event', 'activity.link', linkContent, { type: 'link', delegate: true }); + broker.publish('event', 'activity.link', linkContent, { type: 'link' }); return broker.publish('execution', 'execute.completed', cloneContent(executeContent)); }; - -LinkEventDefinition.prototype._onLinkApiMessage = function onLinkApiMessage(_, message) { - if (message.properties.type !== 'link') return; - if (message.content.message?.linkName !== this.reference.linkName) return; - if (this.activity.isRunning) return; - - this.activity.run(message.content.message); -}; - -LinkEventDefinition.prototype._onShakeMessage = function onShakeMessage(_, message) { - if (message.properties.type !== 'shake') return; - if (message.content.message?.linkName !== this.reference.linkName) return; - - const content = cloneContent(message.content, { targetId: this.id, isLinked: true }); - content.sequence = content.sequence || []; - content.sequence.push({ id: this.id, type: this.type }); - - this.broker.publish('event', 'activity.shake.linked', content, { persistent: false, type: 'shake' }); - - const outbound = this.activity.outbound; - if (outbound?.length) { - for (const flow of outbound) flow.shake({ content: cloneContent(content) }); - } -}; diff --git a/src/events/IntermediateCatchEvent.js b/src/events/IntermediateCatchEvent.js index b6f8f19b..2ba23aaa 100644 --- a/src/events/IntermediateCatchEvent.js +++ b/src/events/IntermediateCatchEvent.js @@ -9,7 +9,11 @@ import { K_EXECUTION } from '../constants.js'; * @param {import('#types').ContextInstance} context */ export function IntermediateCatchEvent(activityDef, context) { - return new Activity(IntermediateCatchEventBehaviour, { ...activityDef, isCatching: true }, context); + return new Activity( + IntermediateCatchEventBehaviour, + { ...activityDef, isCatching: true, ...context.getLinkEventDefinitionInfo(activityDef) }, + context + ); } /** diff --git a/src/events/IntermediateThrowEvent.js b/src/events/IntermediateThrowEvent.js index b02857ce..4616b9ee 100644 --- a/src/events/IntermediateThrowEvent.js +++ b/src/events/IntermediateThrowEvent.js @@ -9,7 +9,11 @@ import { K_EXECUTION } from '../constants.js'; * @param {import('#types').ContextInstance} context */ export function IntermediateThrowEvent(activityDef, context) { - return new Activity(IntermediateThrowEventBehaviour, { ...activityDef, isThrowing: true }, context); + return new Activity( + IntermediateThrowEventBehaviour, + { ...activityDef, isThrowing: true, ...context.getLinkEventDefinitionInfo(activityDef) }, + context + ); } /** diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index 56b64209..844a328f 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -60,7 +60,7 @@ export function ParallelGatewayBehaviour(activity) { this.broker = activity.broker; this.inbound = new Set(); - this.isConverging = new Set(activity.inbound.map(({ sourceId }) => sourceId)).size > 1; + this.isConverging = true; this[K_EXECUTE_MESSAGE] = undefined; } diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index aeb0a681..6ab8dc37 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -482,7 +482,7 @@ ProcessExecution.prototype._activate = function activate() { startActivities.add(activity); } if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); - if (activity.isParallelJoin) convergingGateways.add(activity); + if (activity.isParallelGateway) convergingGateways.add(activity); } if (startActivities.size > 1) { @@ -596,8 +596,13 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { this.getActivityById(aid).broker.publish('api', 'activity.shake.continue', c, { type: 'shake' }); } - if (result.settings.skipDiscard && convergingGateways.size) { - result.settings.skipDiscard = false; + if (result.settings.skipDiscard) { + for (const aid of convergingGateways.keys()) { + if (this.getActivityById(aid).isParallelGateway) { + result.settings.skipDiscard = false; + break; + } + } } if (!executing) this._deactivate(); diff --git a/test/Context-test.js b/test/Context-test.js index 7ddefbbf..394b4c85 100644 --- a/test/Context-test.js +++ b/test/Context-test.js @@ -515,4 +515,78 @@ describe('Context', () => { expect(activateCount).to.equal(0); }); }); + + describe('getActivitiesByEventDefinitionBehaviour(Behaviour, names)', () => { + const source = ` + + + + + + + + + + + + + + + + + + + + + `; + + function getLinkBehaviour(context) { + return context.getActivityById('throwA').behaviour.linkBehaviour; + } + + it('returns activities whose ed.Behaviour matches and whose ed name is wanted', async () => { + const context = await testHelpers.context(source); + const Link = getLinkBehaviour(context); + const ids = context.getActivitiesByEventDefinitionBehaviour(Link, ['LINKA']).map((a) => a.id); + expect(ids).to.have.same.members(['throwA', 'catchA', 'catchAB']); + }); + + it('matches activities whose ed name is any of the wanted names', async () => { + const context = await testHelpers.context(source); + const Link = getLinkBehaviour(context); + const ids = context.getActivitiesByEventDefinitionBehaviour(Link, ['LINKA', 'LINKB']).map((a) => a.id); + expect(ids).to.have.same.members(['throwA', 'throwB', 'catchA', 'catchAB']); + }); + + it('returns an empty array when no Behaviour is given', async () => { + const context = await testHelpers.context(source); + expect(context.getActivitiesByEventDefinitionBehaviour(undefined, ['LINKA'])).to.deep.equal([]); + }); + + it('returns an empty array when no names are given', async () => { + const context = await testHelpers.context(source); + const Link = getLinkBehaviour(context); + expect(context.getActivitiesByEventDefinitionBehaviour(Link, [])).to.deep.equal([]); + }); + + it('returns an empty array when no activity has a matching name', async () => { + const context = await testHelpers.context(source); + const Link = getLinkBehaviour(context); + expect(context.getActivitiesByEventDefinitionBehaviour(Link, ['UNKNOWN'])).to.deep.equal([]); + }); + + it('accepts a Set of names', async () => { + const context = await testHelpers.context(source); + const Link = getLinkBehaviour(context); + const ids = context.getActivitiesByEventDefinitionBehaviour(Link, new Set(['LINKB'])).map((a) => a.id); + expect(ids).to.have.same.members(['throwB', 'catchAB']); + }); + + it('honors a custom Behaviour override — only activities resolved to the override match', async () => { + function CustomLink() {} + const overrideContext = await testHelpers.context(source, { types: { LinkEventDefinition: CustomLink } }); + const ids = overrideContext.getActivitiesByEventDefinitionBehaviour(CustomLink, ['LINKA']).map((a) => a.id); + expect(ids).to.have.same.members(['throwA', 'catchA', 'catchAB']); + }); + }); }); diff --git a/test/activities-test.js b/test/activities-test.js index 71a56687..5a305691 100644 --- a/test/activities-test.js +++ b/test/activities-test.js @@ -986,6 +986,7 @@ describe('activity', () => { const assertMessage = AssertMessage(context, messages, true); assertMessage('activity.enter'); assertMessage('activity.start'); + if (activityType === 'bpmn:ParallelGateway') assertMessage('activity.converge'); assertMessage('activity.end'); assertMessage('activity.leave'); expect(messages, 'no more messages').to.have.length(0); diff --git a/test/activity/ActivityExecution-test.js b/test/activity/ActivityExecution-test.js index 984423ea..a28ea815 100644 --- a/test/activity/ActivityExecution-test.js +++ b/test/activity/ActivityExecution-test.js @@ -138,7 +138,6 @@ describe('ActivityExecution', () => { it('ignores complete message if not postponed', () => { const activity = createActivity(); - activity.isParallelGateway = true; const execution = new ActivityExecution(activity); diff --git a/test/eventDefinitions/LinkEventDefinition-test.js b/test/eventDefinitions/LinkEventDefinition-test.js index 70286e0f..efe25742 100644 --- a/test/eventDefinitions/LinkEventDefinition-test.js +++ b/test/eventDefinitions/LinkEventDefinition-test.js @@ -105,60 +105,10 @@ describe('LinkEventDefinition', () => { expect(waitMessages).to.have.length(0); }); - - it('binds a durable named queue for link delivery so messages survive stop/recover', () => { - new LinkEventDefinition(event, { - type: 'bpmn:LinkEventDefinition', - behaviour: { name: 'LINKA' }, - }); - const q = event.broker.getQueue('link-event-LINKA-q'); - expect(q, 'durable link queue').to.exist; - expect(q.options).to.include({ durable: true, autoDelete: false }); - }); - - it('responds to shake.link with matching linkName', () => { - const catchEd = new LinkEventDefinition(event, { - type: 'bpmn:LinkEventDefinition', - behaviour: { name: 'LINKA' }, - }); - - const linkedMessages = []; - event.broker.subscribeTmp('event', 'activity.shake.linked', (_, msg) => linkedMessages.push(msg), { noAck: true }); - - event.broker.publish( - 'api', - 'activity.shake.link', - { sourceId: 'thrower', sequence: [], message: { linkName: 'LINKA' } }, - { type: 'shake' } - ); - - expect(linkedMessages).to.have.length(1); - expect(linkedMessages[0].content).to.have.property('targetId', catchEd.id); - expect(linkedMessages[0].content).to.have.property('isLinked', true); - }); - - it('ignores shake.link with mismatching linkName', () => { - new LinkEventDefinition(event, { - type: 'bpmn:LinkEventDefinition', - behaviour: { name: 'LINKA' }, - }); - - const linkedMessages = []; - event.broker.subscribeTmp('event', 'activity.shake.linked', (_, msg) => linkedMessages.push(msg), { noAck: true }); - - event.broker.publish( - 'api', - 'activity.shake.link', - { sourceId: 'thrower', sequence: [], message: { linkName: 'OTHER' } }, - { type: 'shake' } - ); - - expect(linkedMessages).to.have.length(0); - }); }); describe('throwing', () => { - it('publishes activity.link with delegate:true and the link payload', () => { + it('publishes activity.link with the link payload on the activity event exchange', () => { event.isThrowing = true; const throwEd = new LinkEventDefinition(event, { @@ -184,7 +134,7 @@ describe('LinkEventDefinition', () => { expect(messages).to.have.length(1); expect(messages[0].fields).to.have.property('routingKey', 'activity.link'); - expect(messages[0].properties).to.have.property('delegate', true); + expect(messages[0].properties).to.not.have.property('delegate'); expect(messages[0].properties).to.have.property('type', 'link'); expect(messages[0].content.message).to.deep.include({ linkName: 'LINKA', referenceType: 'link' }); expect(messages[0].content).to.have.property('state', 'throw'); @@ -216,33 +166,5 @@ describe('LinkEventDefinition', () => { expect(messages).to.have.length(1); }); - - it('on activity.shake.start, publishes activity.shake.link with the linkName', () => { - event.isThrowing = true; - - new LinkEventDefinition(event, { - type: 'bpmn:LinkEventDefinition', - behaviour: { name: 'LINKA' }, - }); - - const messages = []; - event.broker.subscribeTmp('event', 'activity.shake.link', (_, msg) => messages.push(msg), { noAck: true }); - - event.broker.publish( - 'api', - 'activity.shake.start', - { - executionId: 'event_1', - sequence: [], - parent: { id: 'theProcess', executionId: 'theProcess_0' }, - }, - { type: 'shake' } - ); - - expect(messages).to.have.length(1); - expect(messages[0].properties).to.have.property('type', 'shake'); - expect(messages[0].content.message).to.deep.include({ linkName: 'LINKA', referenceType: 'link' }); - expect(messages[0].content).to.have.property('sourceId', 'event'); - }); }); }); diff --git a/test/events/IntermediateCatchEvent-test.js b/test/events/IntermediateCatchEvent-test.js index 5086293a..13bb9910 100644 --- a/test/events/IntermediateCatchEvent-test.js +++ b/test/events/IntermediateCatchEvent-test.js @@ -319,4 +319,111 @@ describe('IntermediateCatchEvent', () => { expect(event.counters).to.have.property('taken', 1); }); }); + + describe('with link event definition', () => { + it('exposes linkNames on activity behaviour for a single-link catch', async () => { + const source = ` + + + + + + + `; + const context = await testHelpers.context(source); + const event = context.getActivityById('catch'); + expect(event.behaviour).to.have.property('linkNames').that.deep.equals(['LINKA']); + }); + + it('deduplicates repeated link names on the same activity', async () => { + const source = ` + + + + + + + + + `; + const context = await testHelpers.context(source); + const event = context.getActivityById('catch'); + expect(event.behaviour.linkNames).to.have.same.members(['LINKA', 'LINKB']); + expect(event.behaviour.linkNames).to.have.length(2); + }); + + it('exposes all linkNames for a multi-link catch', async () => { + const source = ` + + + + + + + + `; + const context = await testHelpers.context(source); + const event = context.getActivityById('catch'); + expect(event.behaviour.linkNames).to.have.same.members(['LINKA', 'LINKB']); + }); + + it('routes a throw on a secondary link name to a multi-link catch', async () => { + const { Definition } = await import('bpmn-elements'); + const source = ` + + + + + + + + + + + + + + + `; + const context = await testHelpers.context(source); + const definition = new Definition(context); + const end = definition.waitFor('end'); + definition.run(); + await end; + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + + it('a throw with multiple link names triggers catches for either name (one in process)', async () => { + const { Definition } = await import('bpmn-elements'); + const source = ` + + + + + + + + + + + + + + + + + + + + `; + const context = await testHelpers.context(source); + const definition = new Definition(context); + const end = definition.waitFor('end'); + definition.run(); + await end; + expect(definition.getActivityById('catchA').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catchB').counters).to.have.property('taken', 1); + }); + }); }); diff --git a/test/feature/Process-feature.js b/test/feature/Process-feature.js index 6c51cf86..aa9839e3 100644 --- a/test/feature/Process-feature.js +++ b/test/feature/Process-feature.js @@ -626,14 +626,15 @@ Feature('Process', () => { assertMessage('activity.end', 'decision'); assertMessage('activity.enter', 'join'); assertMessage('activity.start', 'join'); + assertMessage('activity.converge', 'join'); assertMessage('activity.leave', 'decision'); + assertMessage('activity.leave', 'start'); assertMessage('activity.end', 'join'); assertMessage('activity.enter', 'end'); assertMessage('activity.start', 'end'); assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); assertMessage('activity.leave', 'join'); - assertMessage('activity.leave', 'start'); assertMessage('process.end', 'theProcess'); assertMessage('process.leave', 'theProcess'); }); @@ -839,6 +840,7 @@ Feature('Process', () => { assertMessage('activity.end', 'start'); assertMessage('activity.enter', 'fork'); assertMessage('activity.start', 'fork'); + assertMessage('activity.converge', 'fork'); assertMessage('activity.leave', 'start'); assertMessage('activity.end', 'fork'); diff --git a/test/feature/link-as-goto-feature.js b/test/feature/link-as-goto-feature.js index 15de65f8..ca7a44e9 100644 --- a/test/feature/link-as-goto-feature.js +++ b/test/feature/link-as-goto-feature.js @@ -238,6 +238,200 @@ Feature('Link as goto', () => { }); }); + Scenario('two throws share a single catch — sync catch processes both', () => { + /** @type {Definition} */ + let definition; + Given('a process where both inclusive branches throw the same link name into one catch', async () => { + const source = factory.resource('link-multiple-catch.bpmn'); + const context = await testHelpers.context(source); + definition = new Definition(context, { + variables: { take1: true, take2: true }, + }); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes', () => { + return end; + }); + + And('both throws were taken', () => { + expect(definition.getActivityById('goto-a').counters).to.have.property('taken', 1); + expect(definition.getActivityById('goto-b').counters).to.have.property('taken', 1); + }); + + And('the shared catch ran twice', () => { + expect(definition.getActivityById('catch-a').counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('the downstream end was taken twice', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 2); + }); + }); + + Scenario('two throws share a single catch — async catch queues the second throw', () => { + /** @type {Definition} */ + let definition; + Given('a process where the catch completion is held until the next tick', async () => { + const source = factory.resource('link-multiple-catch.bpmn'); + const context = await testHelpers.context(source); + definition = new Definition(context, { + variables: { take1: true, take2: true }, + extensions: { + asyncCatchEnd(activity) { + if (activity.id !== 'catch-a') return; + + activity.on('end', (api) => { + if (api.fields.redelivered) return; + + const { broker } = activity; + broker.publish('format', 'run.end.async', { endRoutingKey: 'run.end.async.done' }); + + process.nextTick(() => { + broker.publish('format', 'run.end.async.done', {}); + }); + }); + }, + }, + }); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes', () => { + return end; + }); + + And('both throws were taken', () => { + expect(definition.getActivityById('goto-a').counters).to.have.property('taken', 1); + expect(definition.getActivityById('goto-b').counters).to.have.property('taken', 1); + }); + + And('the catch ran twice — the second throw was queued until the first finished', () => { + expect(definition.getActivityById('catch-a').counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('the downstream end was taken twice', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 2); + }); + }); + + Scenario('two throws share a single catch — pending throw survives stop/recover/resume', () => { + /** @type {Definition} */ + let definition; + let context, state; + + const asyncCatch = { + asyncCatchEnd(activity) { + if (activity.id !== 'catch') return; + activity.on('end', (api) => { + if (api.fields.redelivered) return; + const broker = activity.broker; + broker.publish('format', 'run.end.async', { endRoutingKey: 'run.end.async.done' }); + process.nextTick(() => broker.publish('format', 'run.end.async.done', {})); + }); + }, + }; + + Given('a process with two throws sharing one catch downstream of a user task', async () => { + const source = ` + + + + + + + \${environment.variables.take1} + + + \${environment.variables.take2} + + + + + + + + + + + + + + + + `; + context = await testHelpers.context(source); + definition = new Definition(context, { + variables: { take1: true, take2: true }, + extensions: asyncCatch, + }); + }); + + let wait; + When('definition runs until the user task waits after the first catch run', async () => { + wait = definition.waitFor('wait'); + definition.run(); + await wait; + }); + + And('definition is stopped while a pending throw is still queued on the catch', () => { + definition.stop(); + }); + + And('state is captured', () => { + state = JSON.parse(JSON.stringify(definition.getState())); + }); + + let end; + When('definition is recovered into a fresh instance and resumed', () => { + definition = new Definition(context, { extensions: asyncCatch }).recover(state); + end = definition.waitFor('end'); + definition.resume(); + }); + + let wait2; + And('the first waiting user task is signaled (the second wait fires from the queued throw)', async () => { + wait2 = definition.waitFor('wait'); + const userTask = definition.getPostponed().find((api) => api.id === 'userTask'); + expect(userTask, 'first userTask api').to.exist; + userTask.signal(); + await wait2; + }); + + And('the second waiting user task is signaled', () => { + const userTask = definition.getPostponed().find((api) => api.id === 'userTask'); + expect(userTask, 'second userTask api').to.exist; + userTask.signal(); + }); + + Then('definition completes', () => { + return end; + }); + + And('both throws were taken', () => { + expect(definition.getActivityById('throw1').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw2').counters).to.have.property('taken', 1); + }); + + And('the shared catch ran twice across the lifecycle', () => { + expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('the downstream end was reached twice', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); + }); + Scenario('throw with no matching catch silently completes', () => { /** @type {Definition} */ let definition; diff --git a/test/feature/linking-feature.js b/test/feature/linking-feature.js index fdcc9047..78aff058 100644 --- a/test/feature/linking-feature.js +++ b/test/feature/linking-feature.js @@ -659,6 +659,84 @@ Feature('Linking', () => { expect(definition.getActivityById('end').counters).to.have.property('taken', 6); }); }); + + Scenario('a flow with multiple named link throw and catch events', () => { + /** @type {Definition} */ + let definition; + Given('a flow with an inclusive gateway routing to one or both link throw events', async () => { + const source = factory.resource('link-multiple.bpmn'); + const context = await testHelpers.context(source); + + definition = new Definition(context, { + variables: { + take1: true, + }, + settings: { + skipDiscard, + }, + }); + }); + + let end; + When('definition is ran with condition to take LINKA only', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('LINKA end was taken once', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 1); + }); + + And('LINKB end stayed dormant', () => { + expect(definition.getActivityById('end-b').counters).to.have.property('taken', 0); + }); + + When('definition is ran with condition to take LINKB only', () => { + end = definition.waitFor('end'); + + definition.environment.variables.take1 = false; + definition.environment.variables.take2 = true; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('LINKA end was not taken again', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 1); + }); + + And('LINKB end was taken once', () => { + expect(definition.getActivityById('end-b').counters).to.have.property('taken', 1); + }); + + When('definition is ran with condition to take both links', () => { + end = definition.waitFor('end'); + + definition.environment.variables.take1 = true; + definition.environment.variables.take2 = true; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('LINKA end was taken again', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 2); + }); + + And('LINKB end was taken again', () => { + expect(definition.getActivityById('end-b').counters).to.have.property('taken', 2); + }); + }); }); }); }); diff --git a/test/feature/multiple-startevent-feature.js b/test/feature/multiple-startevent-feature.js index 26597ea2..d0b0edba 100644 --- a/test/feature/multiple-startevent-feature.js +++ b/test/feature/multiple-startevent-feature.js @@ -205,6 +205,105 @@ Feature('Multiple start events', () => { }); }); }); + + Scenario('Two start events joined by a task followed by a parallel fork', () => { + const source = ` + + + + + + + + + + + + + + + + + + + + `; + + let context; + /** @type {Definition} */ + let definition; + Given('a process with multiple signal start events, a joining task and a subsequent fork', async () => { + context = await testHelpers.context(source); + definition = new Definition(context, { + settings: { skipDiscard }, + }); + }); + + And('the subsequent fork is a parallel gateway but not a parallel join', () => { + const fork = definition.getActivityById('fork'); + expect(fork.isParallelGateway, 'isParallelGateway').to.be.true; + expect(fork.isParallelJoin, 'isParallelJoin').to.be.false; + expect(fork.inbound).to.have.length(1); + expect(fork.outbound).to.have.length(2); + }); + + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + And('both start events are signaled', () => { + definition.signal(); + definition.signal({ id: 'Signal2' }); + }); + + Then('process is completed', async () => { + await leave; + expect(definition.counters).to.deep.equal({ + completed: 1, + discarded: 0, + }); + }); + + And('joining task was taken twice', () => { + const task = definition.getActivityById('task'); + expect(task.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('fork was aggregated to a single firing via peer monitoring', () => { + const fork = definition.getActivityById('fork'); + expect(fork.counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('both end events were taken once', () => { + expect(definition.getActivityById('end1').counters).to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('end2').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + When('process is ran again', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + And('both start events are signaled in the reverse order', () => { + definition.signal({ id: 'Signal2' }); + definition.signal(); + }); + + Then('process is completed', async () => { + await leave; + expect(definition.counters).to.deep.equal({ + completed: 2, + discarded: 0, + }); + }); + + And('fork was aggregated to a single firing per run', () => { + const fork = definition.getActivityById('fork'); + expect(fork.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + }); }); }); }); diff --git a/test/feature/parallel-gateway-fork-feature.js b/test/feature/parallel-gateway-fork-feature.js index d7dd1a3d..74d486ca 100644 --- a/test/feature/parallel-gateway-fork-feature.js +++ b/test/feature/parallel-gateway-fork-feature.js @@ -544,6 +544,80 @@ Feature('Parallel gateway fork', () => { return leave; }); }); + + Scenario('A process with a fork but no parallel join still triggers a shake', () => { + const source = ` + + + + + + + + + + + + + + + + + + + + + `; + + /** @type {Definition} */ + let definition; + const convergeMessages = []; + + Given('a definition with a fork (no join) and parallel upstream peers', async () => { + const context = await testHelpers.context(source); + definition = new Definition(context); + }); + + let leave; + When('definition is ran capturing activity.converge events', () => { + leave = definition.waitFor('leave'); + definition.broker.subscribeTmp( + 'event', + 'activity.converge', + (_, msg) => { + convergeMessages.push(msg.content.id); + }, + { noAck: true } + ); + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + And('the fork emitted activity.converge', () => { + expect(convergeMessages).to.include('fork'); + }); + + And('the fork discovered upstream parallel peers via shake', () => { + const fork = definition.getActivityById('fork'); + const peers = fork[Symbol.for('peers')]; + const peerIds = new Set([...peers.values()].flatMap((s) => [...s])); + expect(peerIds).to.include('task1'); + expect(peerIds).to.include('task2'); + expect(peerIds).to.include('split'); + }); + + And('the fork fires once, aggregating both upstream firings via peer monitoring', () => { + const fork = definition.getActivityById('fork'); + expect(fork.counters).to.deep.equal({ taken: 1, discarded: 0 }); + const merge = definition.getActivityById('merge'); + expect(merge.counters).to.deep.equal({ taken: 2, discarded: 0 }); + expect(definition.getActivityById('end1').counters).to.deep.equal({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('end2').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + }); }); function getTakeServices() { diff --git a/test/feature/skip-discard-feature.js b/test/feature/skip-discard-feature.js index a5d41078..eb634610 100644 --- a/test/feature/skip-discard-feature.js +++ b/test/feature/skip-discard-feature.js @@ -165,7 +165,7 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { }); }); - ['engine-issue-73.bpmn', 'engine-issue-73_2.bpmn', 'issue-42-same-target-sequence-flows-with-excl-gw.bpmn'].forEach((source) => { + ['engine-issue-73.bpmn', 'engine-issue-73_2.bpmn'].forEach((source) => { Scenario(`${source} should complete as expected`, () => { /** @type {Definition} */ let definition; @@ -239,6 +239,7 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { 'join-paradox-5.bpmn', 'join-inbound.bpmn', 'issue-42-same-target-sequence-flows.bpmn', + 'issue-42-same-target-sequence-flows-with-excl-gw.bpmn', 'parallel-join-edgecase.bpmn', ].forEach((source) => { Scenario(`${source} with parallel converging gateways should complete as expected`, () => { diff --git a/test/resources/link-multiple-catch.bpmn b/test/resources/link-multiple-catch.bpmn new file mode 100644 index 00000000..c801f21e --- /dev/null +++ b/test/resources/link-multiple-catch.bpmn @@ -0,0 +1,108 @@ + + + + + to-gw + + + + to-task1 + to-goto-a + + + ${environment.variables.take1} + + + to-task2 + to-goto-b + + + ${environment.variables.take2} + + + + + to-goto-a + + + + to-goto-b + + + + to-end-a + + + + to-end-a + + + + to-gw + to-task1 + to-task2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/link-multiple.bpmn b/test/resources/link-multiple.bpmn new file mode 100644 index 00000000..93df4325 --- /dev/null +++ b/test/resources/link-multiple.bpmn @@ -0,0 +1,129 @@ + + + + + to-gw + + + + to-task1 + to-goto-a + + + ${environment.variables.take1} + + + to-task2 + to-goto-b + + + ${environment.variables.take2} + + + + + to-goto-a + + + + to-goto-b + + + + to-end-a + + + + to-end-b + + + + to-end-a + + + + to-end-b + + + + to-gw + to-task1 + to-task2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/types/index.d.ts b/types/index.d.ts index a1f9d4b7..f164d989 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -864,6 +864,19 @@ declare module 'bpmn-elements' { * @param scopeId Process or sub-process id */ getStartActivities(filterOptions?: startActivityFilterOptions, scopeId?: string): Activity[]; + /** + * Inspect an activity def for link event definitions. + * */ + getLinkEventDefinitionInfo(activityDef: import("moddle-context-serializer").Activity): { + linkBehaviour?: Function; + linkNames?: string[]; + }; + /** + * Get activities whose event definitions include the given Behaviour with a matching name. + * @param Behaviour Behaviour constructor to match against `ed.Behaviour` + * @param scopeId Process or sub-process id + */ + getActivitiesByEventDefinitionBehaviour(Behaviour: Function, names: string[] | Iterable, scopeId?: string): Activity[]; /** * Resolve user-registered extensions and the built-in BpmnIO extension for an activity. * Returns undefined when the activity has no extensions to attach. From 5df370fb49735a64d85f5d7e3bc7dc11413e1e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 6 Jun 2026 11:04:20 +0200 Subject: [PATCH 22/31] allow activities to discard all outbound flows - i.e. execution ends here --- CHANGELOG.md | 2 + dist/activity/outbound-evaluator.js | 2 +- dist/condition.js | 7 + dist/gateways/ExclusiveGateway.js | 3 +- dist/gateways/InclusiveGateway.js | 4 +- docs/Expression.md | 6 +- docs/SequenceFlow.md | 34 ++ src/activity/outbound-evaluator.js | 2 +- src/condition.js | 7 + src/gateways/ExclusiveGateway.js | 2 +- src/gateways/InclusiveGateway.js | 2 +- test/feature/issues/issue-42-feature.js | 52 ++ test/flows/SequenceFlow-test.js | 132 +++++ test/resources/issue-42-original.bpmn | 623 ++++++++++++++++++++++++ 14 files changed, 869 insertions(+), 9 deletions(-) create mode 100644 test/resources/issue-42-original.bpmn diff --git a/CHANGELOG.md b/CHANGELOG.md index a6d7f5d1..03c5da41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Refactor parallel converging and forking gateways. - shake sequence has changed - IntermediateCatchEvent cannot be used as a starting element, or it can but will not be started by default - `Definition` must be called with `new` +- non-gateway activities discard their outbound when all conditional flows are falsy instead of throwing; only exclusive and inclusive gateways still require a taken or default flow ### Additions @@ -18,6 +19,7 @@ Refactor parallel converging and forking gateways. - new activity event `activity.converge` published when parallel gateway is executed - fix link event definition shaking - fix `Activity.recover()` to return the activity when called without state +- a condition expression resolving to a service function is now invoked with the flow execution scope, supporting sync (return) and async (callback) results ### Types diff --git a/dist/activity/outbound-evaluator.js b/dist/activity/outbound-evaluator.js index 88201d7b..1c8cd795 100644 --- a/dist/activity/outbound-evaluator.js +++ b/dist/activity/outbound-evaluator.js @@ -102,7 +102,7 @@ OutboundEvaluator.prototype.completed = function completed(err) { } = this.evaluateArgs; this.broker.cancel(`_flow-evaluation-${evaluationId}`); if (err) return callback(err); - if (!takenCount && this.outboundFlows.length) { + if (!takenCount && this.outboundFlows.length && fromMessage.content.requireOutbound) { const nonTakenError = new _Errors.ActivityError(`<${this.activity.id}> no conditional flow taken`, fromMessage); return callback(nonTakenError); } diff --git a/dist/condition.js b/dist/condition.js index fa60ce9c..f882685f 100644 --- a/dist/condition.js +++ b/dist/condition.js @@ -55,6 +55,13 @@ ExpressionCondition.prototype.execute = function execute(message, callback) { const owner = this._owner; try { const result = owner.environment.resolveExpression(this.expression, message); + if (typeof result === 'function') { + const scope = (0, _ExecutionScope.ExecutionScope)(owner, message); + if (callback && result.length > 1) return result.call(owner, scope, callback); + const conditionResult = result.call(owner, scope); + if (callback) return callback(null, conditionResult); + return conditionResult; + } if (callback) return callback(null, result); return result; } catch (err) { diff --git a/dist/gateways/ExclusiveGateway.js b/dist/gateways/ExclusiveGateway.js index 8a532ea4..3b8df40d 100644 --- a/dist/gateways/ExclusiveGateway.js +++ b/dist/gateways/ExclusiveGateway.js @@ -39,6 +39,7 @@ ExclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(content, { - outboundTakeOne: true + outboundTakeOne: true, + requireOutbound: true })); }; \ No newline at end of file diff --git a/dist/gateways/InclusiveGateway.js b/dist/gateways/InclusiveGateway.js index ef12f4c6..9be15093 100644 --- a/dist/gateways/InclusiveGateway.js +++ b/dist/gateways/InclusiveGateway.js @@ -38,5 +38,7 @@ function InclusiveGatewayBehaviour(activity) { InclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { - this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(content)); + this.broker.publish('execution', 'execute.completed', (0, _messageHelper.cloneContent)(content, { + requireOutbound: true + })); }; \ No newline at end of file diff --git a/docs/Expression.md b/docs/Expression.md index 6dbb73d0..a763c708 100644 --- a/docs/Expression.md +++ b/docs/Expression.md @@ -38,9 +38,9 @@ The following expressions are supported: - `${environment.variables.input[-1]}` - resolves to last item of the variable input array - `${environment.variables.input[spaced name]}` - resolves to the variable input object property `spaced name` -- `${environment.services.getInput}` - return the service function `getInput` -- `${environment.services.getInput()}` - executes the service function `getInput` with the argument `{services, variables}` -- `${environment.services.isBelow(content.input,2)}` - executes the service function `isBelow` with result of `variable.input` value and 2 +- `${environment.services.getInput}` - resolves to the service function `getInput` itself (it is **not** called). The caller decides how to invoke it — e.g. a [sequence flow condition](/docs/SequenceFlow.md#service-function-conditions) calls it with the flow execution scope +- `${environment.services.getInput()}` - calls the service function `getInput`. Empty parentheses are **not** a no-argument call: the resolution `context` is passed as the single argument, i.e. `{ environment, ...message }` (so the service can read `arg.content`, `arg.environment`, …) +- `${environment.services.isBelow(content.input,2)}` - calls the service function `isBelow` with the resolved `content.input` value and `2` - `I, ${content.id}, execute with id ${content.executionId}` - formats a string addressing content object values diff --git a/docs/SequenceFlow.md b/docs/SequenceFlow.md index 31b36d5c..dc07b47b 100644 --- a/docs/SequenceFlow.md +++ b/docs/SequenceFlow.md @@ -35,3 +35,37 @@ Sequence flows: - `to-task3`: unconditional. Flow is taken - `to-task4`: script condition. Callback (next) is called with environment variable as result. If result is truthy the flow is taken, otherwise discarded - `to-task5`: expression condition. Expression will be evaluated and passed as result. If result is truthy the flow is taken, otherwise discarded + +## Service function conditions + +An expression condition can resolve to a service function instead of a plain value. The function then produces the take/discard result, which makes per-flow state and asynchronous conditions possible. There are two forms, and they receive **different** arguments: + +- `${environment.services.takeOnce}` (no call) — the expression resolves to the function itself and the sequence flow invokes it with the flow [execution scope](/docs/ExecutionScope.md) as the first argument (and as `this`). The scope exposes the flow `id`, the source activity `content`, and the `environment`. Return a value synchronously, or declare a second `callback` parameter to resolve asynchronously: + + ```js + // synchronous — return the result + function takeOnce(scope) { + const taken = (scope.environment.variables.takenFlows ??= new Set()); + if (taken.has(scope.id)) return false; // scope.id is the sequence flow id + taken.add(scope.id); + return true; + } + + // asynchronous — resolve through the callback + function isAllowed(scope, callback) { + checkRemotely(scope.content, (err, ok) => callback(err, ok)); + } + ``` + +- `${environment.services.takeFlow(content.id)}` (called) — the expression calls the function and the flow uses the returned value. Arguments are resolved by the [expression handler](/docs/Expression.md); note that **empty** parentheses `takeFlow()` pass the resolution context `{ environment, ...message }` as the single argument (not zero arguments). + +> The flow id is only reachable through the no-call form, via `scope.id`. The called form receives the **source activity** in `content` (`content.id` is the activity, not the flow). + +## When no conditional flow is taken + +If every conditional outbound flow evaluates to falsy, the behaviour depends on the element: + +- a diverging **exclusive or inclusive gateway** takes its `default` flow when declared, otherwise it raises an ` no conditional flow taken` error — these gateways require exactly one (exclusive) or at least one (inclusive) outbound to be taken; +- any **other activity** (task, event, …) simply discards its outbound — the branch ends, no error is raised. + +> With the default `skipDiscard` setting the discards are not published, so the outbound flow `discard` counters stay at `0`. Set `skipDiscard` to `false` to observe the discards. diff --git a/src/activity/outbound-evaluator.js b/src/activity/outbound-evaluator.js index cbe2cd6f..499ca257 100644 --- a/src/activity/outbound-evaluator.js +++ b/src/activity/outbound-evaluator.js @@ -99,7 +99,7 @@ OutboundEvaluator.prototype.completed = function completed(err) { if (err) return callback(err); - if (!takenCount && this.outboundFlows.length) { + if (!takenCount && this.outboundFlows.length && fromMessage.content.requireOutbound) { const nonTakenError = new ActivityError(`<${this.activity.id}> no conditional flow taken`, fromMessage); return callback(nonTakenError); } diff --git a/src/condition.js b/src/condition.js index df028057..33ec2bc1 100644 --- a/src/condition.js +++ b/src/condition.js @@ -48,6 +48,13 @@ ExpressionCondition.prototype.execute = function execute(message, callback) { const owner = this._owner; try { const result = owner.environment.resolveExpression(this.expression, message); + if (typeof result === 'function') { + const scope = ExecutionScope(owner, message); + if (callback && result.length > 1) return result.call(owner, scope, callback); + const conditionResult = result.call(owner, scope); + if (callback) return callback(null, conditionResult); + return conditionResult; + } if (callback) return callback(null, result); return result; } catch (err) { diff --git a/src/gateways/ExclusiveGateway.js b/src/gateways/ExclusiveGateway.js index 70623ef5..0c211909 100644 --- a/src/gateways/ExclusiveGateway.js +++ b/src/gateways/ExclusiveGateway.js @@ -26,5 +26,5 @@ export function ExclusiveGatewayBehaviour(activity) { * @returns {void} */ ExclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { - this.broker.publish('execution', 'execute.completed', cloneContent(content, { outboundTakeOne: true })); + this.broker.publish('execution', 'execute.completed', cloneContent(content, { outboundTakeOne: true, requireOutbound: true })); }; diff --git a/src/gateways/InclusiveGateway.js b/src/gateways/InclusiveGateway.js index a42538e8..5ee5dba5 100644 --- a/src/gateways/InclusiveGateway.js +++ b/src/gateways/InclusiveGateway.js @@ -26,5 +26,5 @@ export function InclusiveGatewayBehaviour(activity) { * @returns {void} */ InclusiveGatewayBehaviour.prototype.execute = function execute({ content }) { - this.broker.publish('execution', 'execute.completed', cloneContent(content)); + this.broker.publish('execution', 'execute.completed', cloneContent(content, { requireOutbound: true })); }; diff --git a/test/feature/issues/issue-42-feature.js b/test/feature/issues/issue-42-feature.js index e982ffe7..9043794e 100644 --- a/test/feature/issues/issue-42-feature.js +++ b/test/feature/issues/issue-42-feature.js @@ -99,3 +99,55 @@ Feature('Issue 42 - discard loops due to multiple outbound flows to same target' }); }); }); + +const originalSource = factory.resource('issue-42-original.bpmn'); + +Feature('Issue 42 - reconstructed diagram with takeOnce conditional flows', () => { + /** + * Take each conditional sequence flow at most once per run. + * The condition expression resolves to this function, so it is called with the + * flow execution scope and keys on the flow id to break the diagram loops. + */ + function takeOnce(flowScope) { + const variables = flowScope.environment.variables; + const takenFlows = variables.takenFlows || (variables.takenFlows = new Set()); + if (takenFlows.has(flowScope.id)) return false; + takenFlows.add(flowScope.id); + return true; + } + + [ + ['synchronous', (scope, next) => next()], + ['asynchronous', (scope, next) => process.nextTick(next)], + ].forEach(([kind, serviceTask]) => { + Scenario(`every task completes with a ${kind} service task implementation`, () => { + let context, definition; + Given('a definition where conditional flows resolve to the takeOnce service function', async () => { + context = await testHelpers.context(originalSource); + definition = new Definition(context, { services: { takeOnce, serviceTask } }); + }); + + let left; + When('definition is ran', () => { + left = definition.waitFor('leave'); + definition.run(); + }); + + Then('it completes without error', () => { + return left; + }); + + And('all twenty service tasks completed at least once', () => { + for (let n = 1; n <= 20; n++) { + expect(definition.getActivityById(`task${n}`).counters, `task${n}`) + .to.have.property('taken') + .above(0); + } + }); + + And('the end event was reached', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + }); + }); +}); diff --git a/test/flows/SequenceFlow-test.js b/test/flows/SequenceFlow-test.js index b709e9f0..a9b5db6a 100644 --- a/test/flows/SequenceFlow-test.js +++ b/test/flows/SequenceFlow-test.js @@ -202,6 +202,138 @@ describe('SequenceFlow', () => { expect(activity.outbound[1].counters).to.have.property('take', 0); }); + it('calls a service expression that resolves to a function with the flow as scope', async () => { + const source = ` + + + + + + + + + + + + \${environment.services.cond} + + + \${environment.services.cond} + + + `; + + const ctx = await testHelpers.context(source); + const scopes = []; + ctx.environment.addService('cond', function cond(scope) { + scopes.push(scope.id); + return scope.id === 'flow3'; + }); + + const activity = ctx.getActivityById('decision'); + activity.run(); + + expect(scopes, 'function called once per conditional flow with the flow id').to.have.members(['flow3', 'flow4']); + + expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.deep.include({ take: 1, discard: 0 }); + expect(activity.outbound.find((f) => f.id === 'flow4').counters).to.deep.include({ take: 0 }); + }); + + it('resolves an asynchronous function-valued service expression via its callback', async () => { + const source = ` + + + + + + + + + + + \${environment.services.cond} + + + `; + + const ctx = await testHelpers.context(source); + ctx.environment.addService('cond', function cond(scope, next) { + process.nextTick(next, null, scope.id === 'flow3'); + }); + + const activity = ctx.getActivityById('decision'); + const left = activity.waitFor('leave'); + activity.run(); + await left; + + expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.deep.include({ take: 1, discard: 0 }); + }); + + it('does not error a non-gateway activity when every outbound condition is falsy', async () => { + const source = ` + + + + + + + + + + \${environment.variables.never} + + + \${environment.variables.never} + + + `; + + const ctx = await testHelpers.context(source); + + const activity = ctx.getActivityById('task'); + const errors = []; + activity.broker.subscribeTmp('event', 'activity.error', (_, msg) => errors.push(msg), { noAck: true }); + + const leave = activity.waitFor('leave'); + activity.run(); + await leave; + + expect(errors, 'unlike a gateway, no error is raised').to.have.length(0); + expect(activity.counters, 'activity is taken').to.include({ taken: 1 }); + expect(activity.outbound.find((f) => f.id === 'flow2').counters).to.include({ take: 0 }); + expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.include({ take: 0 }); + }); + + it('discards the outbound of a non-gateway activity with falsy conditions when skipDiscard is off', async () => { + const source = ` + + + + + + + + + + \${environment.variables.never} + + + \${environment.variables.never} + + + `; + + const ctx = await testHelpers.context(source, { settings: { skipDiscard: false } }); + + const activity = ctx.getActivityById('task'); + const leave = activity.waitFor('leave'); + activity.run(); + await leave; + + expect(activity.outbound.find((f) => f.id === 'flow2').counters).to.include({ take: 0, discard: 1 }); + expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.include({ take: 0, discard: 1 }); + }); + it('can handle external resource condition with custom script handler', async () => { const source = ` diff --git a/test/resources/issue-42-original.bpmn b/test/resources/issue-42-original.bpmn new file mode 100644 index 00000000..29ea6d53 --- /dev/null +++ b/test/resources/issue-42-original.bpmn @@ -0,0 +1,623 @@ + + + + + flow_start + + + flow_start + flow33 + flow32 + flow31 + flow30 + flow28 + flow29 + u_t10_t1 + flow1 + flow2 + flow3 + + + flow1 + flow2 + flow3 + flow4 + flow6 + flow5 + + + flow6 + flow5 + flow7 + flow8 + flow9 + + + flow7 + flow8 + flow9 + flow10 + flow11 + + + flow11 + flow12 + flow13 + flow14 + + + flow10 + u_t6_t8 + + + flow12 + u_t7_t9 + + + u_t6_t8 + flow16 + flow15 + flow17 + flow18 + + + flow16 + flow15 + u_t7_t9 + flow13 + flow22 + from-task10 + flow19 + flow20 + flow21 + + + flow24 + u_t14_t10 + from-task10 + + + flow23 + flow22 + + + flow21 + flow34 + flow14 + flow23 + flow35 + + + flow35 + flow24 + flow25 + flow26 + u_t10_t1 + + + flow25 + u_t14_t10 + + + flow26 + flow27 + flow28 + + + flow27 + flow29 + + + flow20 + flow34 + flow33 + + + flow19 + flow32 + + + flow17 + flow31 + + + flow18 + flow30 + + + flow4 + + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + ${environment.services.takeOnce} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From cb26c4249bc31f14a99b1b283032ab1f0439b9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 6 Jun 2026 11:50:15 +0200 Subject: [PATCH 23/31] cache parallel gateway peers - recover forces refresh --- CHANGELOG.md | 1 + dist/activity/Activity.js | 51 +++++++------------- dist/gateways/ParallelGateway.js | 8 ++-- dist/process/ProcessExecution.js | 64 +++++++++++++++---------- src/activity/Activity.js | 29 ++++------- src/gateways/ParallelGateway.js | 9 ++-- src/process/ProcessExecution.js | 64 ++++++++++++++++--------- test/feature/issues/issue-42-feature.js | 60 +++++++++++------------ test/feature/linking-feature.js | 54 +++++++++++++++++++++ test/feature/shake-feature.js | 62 ++++++++++++++++++++++++ test/flows/SequenceFlow-test.js | 25 ++++++++++ types/index.d.ts | 3 +- 12 files changed, 286 insertions(+), 144 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03c5da41..818e47c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Refactor parallel converging and forking gateways. - fix link event definition shaking - fix `Activity.recover()` to return the activity when called without state - a condition expression resolving to a service function is now invoked with the flow execution scope, supporting sync (return) and async (callback) results +- converging parallel gateways cache their discovered peers per runtime instance, skipping the start-up shake on repeated runs (loops, stop/resume); the cache is rebuilt on recover ### Types diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 8602e4da..a450875d 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -630,18 +630,26 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { persistent: false, type: 'shake' }); - if (this[K_FLAGS].isThrowing && this[K_FLAGS].linkNames?.length) { - for (const linkName of this[K_FLAGS].linkNames) { - this.broker.publish('event', 'activity.shake.link', (0, _messageHelper.cloneContent)(message.content, { + const flags = this[K_FLAGS]; + if (flags.isThrowing && flags.linkNames?.length) { + for (const target of this.context.getActivitiesByEventDefinitionBehaviour(flags.linkBehaviour, flags.linkNames)) { + if (target.id === this.id || !target.isCatching) continue; + const linkedContent = (0, _messageHelper.cloneContent)(message.content, { sourceId: this.id, - message: { - id: linkName, - linkName, - referenceType: 'link' - } - }), { + targetId: target.id, + isLinked: true + }); + linkedContent.sequence = linkedContent.sequence.concat({ + id: target.id, + type: target.type + }); + target.broker.publish('event', 'activity.shake.linked', linkedContent, { + persistent: false, type: 'shake' }); + for (const flow of target.outbound) flow.shake({ + content: (0, _messageHelper.cloneContent)(linkedContent) + }); } } if (this[K_FLAGS].isEnd) { @@ -752,31 +760,6 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message }), properties); return; } - case 'activity.shake.link': - { - const linkName = content.message?.linkName; - if (!this[K_FLAGS].linkNames?.includes(linkName)) break; - const linkedContent = (0, _messageHelper.cloneContent)(content, { - targetId: this.id, - isLinked: true - }); - linkedContent.sequence = linkedContent.sequence || []; - linkedContent.sequence.push({ - id: this.id, - type: this.type - }); - this.broker.publish('event', 'activity.shake.linked', linkedContent, { - persistent: false, - type: 'shake' - }); - const outbound = this.outbound; - if (outbound?.length) { - for (const flow of outbound) flow.shake({ - content: (0, _messageHelper.cloneContent)(linkedContent) - }); - } - break; - } case 'association.take': case 'flow.take': case 'flow.discard': diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 8f69ba9a..6667b38b 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -11,7 +11,7 @@ var _constants = require("../constants.js"); const STATE_MONTITORING = 'monitoring'; const STATE_SETUP = 'setup'; const K_PEERS = Symbol.for('peers'); -const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); +const K_PEERS_DISCOVERED = Symbol.for('peers discovered'); /** * Parallel gateway @@ -52,6 +52,7 @@ function ParallelGateway(activityDef, context) { } } activity.logger.debug(`<${activity.id}> collected parallel gateway peers`); + activity[K_PEERS_DISCOVERED] = true; activity.shake(message); } } @@ -102,7 +103,7 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) { ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { const peerIds = new Set([...this.activity[K_PEERS].values()].map(v => [...v]).flat()); this[_constants.K_TARGETS] = new Map([...peerIds].map(pid => [pid, this.activity.getActivityById(pid)])); - this.peerMonitor = new PeerMonitor(this.activity, this.activity[K_INBOUND_SOURCE_IDS], this[_constants.K_TARGETS]); + this.peerMonitor = new PeerMonitor(this.activity, this[_constants.K_TARGETS]); const message = this[_constants.K_EXECUTE_MESSAGE] = (0, _messageHelper.cloneMessage)(executeMessage); const executeContent = message.content; const { @@ -172,7 +173,7 @@ ParallelGatewayBehaviour.prototype._stop = function stop() { this.broker.cancel('_parallel-execution-peer-enter-tag'); this.peerMonitor.stop(); }; -function PeerMonitor(activity, peers, targets) { +function PeerMonitor(activity, targets) { this.activity = activity; this.id = activity.id; this.broker = activity.broker; @@ -181,7 +182,6 @@ function PeerMonitor(activity, peers, targets) { this.discarded = 0; this.running = new Map(); this.watching = new Map(); - this.peers = peers; this.targets = targets; this.touched = new Set(); this.inbound = []; diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 505f8863..a9b1c89f 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -13,6 +13,7 @@ const K_ACTIVITY_Q = Symbol.for('activityQ'); const K_ELEMENTS = Symbol.for('elements'); const K_PARENT = Symbol.for('parent'); const K_TRACKER = Symbol.for('activity tracker'); +const K_PEERS_DISCOVERED = Symbol.for('peers discovered'); /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -136,16 +137,10 @@ ProcessExecution.prototype.resume = function resume() { if (this[_constants.K_COMPLETED]) return this._complete('completed'); this._activate(); const { - startActivities, postponed, - detachedActivities, - convergingGateways + detachedActivities } = this[K_ELEMENTS]; - if (startActivities.size > 1 || convergingGateways.size) { - const result = this._shakeElements(); - const skipDiscard = this.environment.settings.skipDiscard = result.settings.skipDiscard; - this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); - } + this._shakeOnStart(); postponed.clear(); detachedActivities.clear(); this[K_ACTIVITY_Q].consume(this[_constants.K_MESSAGE_HANDLERS].onChildMessage, { @@ -387,14 +382,9 @@ ProcessExecution.prototype._start = function start() { const { startActivities, postponed, - detachedActivities, - convergingGateways + detachedActivities } = this[K_ELEMENTS]; - if (startActivities.size > 1 || convergingGateways.size) { - const result = this._shakeElements(); - const skipDiscard = this.environment.settings.skipDiscard = result.settings.skipDiscard; - this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); - } + this._shakeOnStart(); for (const a of startActivities) a.init(); this[_constants.K_STATUS] = 'executing'; for (const a of startActivities) a.run(); @@ -517,6 +507,40 @@ ProcessExecution.prototype._deactivate = function deactivate() { this[_constants.K_ACTIVATED] = false; }; +/** + * Shake on start/resume when there are converging gateways or multiple start activities. + * Reuses already discovered parallel gateway peers to skip the graph shake on repeated runs. + * @internal + */ +ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { + const { + startActivities, + convergingGateways + } = this[K_ELEMENTS]; + if (startActivities.size <= 1 && this._peersDiscovered()) { + this.environment.settings.skipDiscard = false; + this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size}), disabling skipDiscard`); + return; + } + if (startActivities.size <= 1 && !convergingGateways.size) return; + const skipDiscard = this.environment.settings.skipDiscard = this._shakeElements().settings.skipDiscard; + this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); +}; + +/** + * Whether every converging parallel gateway has discovered its peers in this runtime instance. + * Peers are a runtime cache and absent after recover, so a changed source is reshaken. + * @internal + */ +ProcessExecution.prototype._peersDiscovered = function peersDiscovered() { + const convergingGateways = this[K_ELEMENTS].convergingGateways; + if (!convergingGateways.size) return false; + for (const gateway of convergingGateways) { + if (!gateway[K_PEERS_DISCOVERED]) return false; + } + return true; +}; + /** @internal */ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { let executing = true; @@ -540,16 +564,6 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { }) => { if (content.parent.id !== this.id) return; switch (routingKey) { - case 'activity.shake.link': - { - for (const a of this[K_ELEMENTS].triggeredByEvent) { - if (!a.isCatching) continue; - a.broker.publish('api', routingKey, (0, _messageHelper.cloneContent)(content), { - type: 'shake' - }); - } - break; - } case 'activity.shake.join': { const join = convergingGateways.get(content.join); diff --git a/src/activity/Activity.js b/src/activity/Activity.js index 33add07f..dd1844df 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -608,14 +608,14 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { this.broker.publish('api', 'activity.shake.start', message.content, { persistent: false, type: 'shake' }); - if (this[K_FLAGS].isThrowing && this[K_FLAGS].linkNames?.length) { - for (const linkName of this[K_FLAGS].linkNames) { - this.broker.publish( - 'event', - 'activity.shake.link', - cloneContent(message.content, { sourceId: this.id, message: { id: linkName, linkName, referenceType: 'link' } }), - { type: 'shake' } - ); + const flags = this[K_FLAGS]; + if (flags.isThrowing && flags.linkNames?.length) { + for (const target of this.context.getActivitiesByEventDefinitionBehaviour(flags.linkBehaviour, flags.linkNames)) { + if (target.id === this.id || !target.isCatching) continue; + const linkedContent = cloneContent(message.content, { sourceId: this.id, targetId: target.id, isLinked: true }); + linkedContent.sequence = linkedContent.sequence.concat({ id: target.id, type: target.type }); + target.broker.publish('event', 'activity.shake.linked', linkedContent, { persistent: false, type: 'shake' }); + for (const flow of target.outbound) flow.shake({ content: cloneContent(linkedContent) }); } } @@ -713,19 +713,6 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message ); return; } - case 'activity.shake.link': { - const linkName = content.message?.linkName; - if (!this[K_FLAGS].linkNames?.includes(linkName)) break; - const linkedContent = cloneContent(content, { targetId: this.id, isLinked: true }); - linkedContent.sequence = linkedContent.sequence || []; - linkedContent.sequence.push({ id: this.id, type: this.type }); - this.broker.publish('event', 'activity.shake.linked', linkedContent, { persistent: false, type: 'shake' }); - const outbound = this.outbound; - if (outbound?.length) { - for (const flow of outbound) flow.shake({ content: cloneContent(linkedContent) }); - } - break; - } case 'association.take': case 'flow.take': case 'flow.discard': diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index 844a328f..bb14aed8 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -6,7 +6,7 @@ const STATE_MONTITORING = 'monitoring'; const STATE_SETUP = 'setup'; const K_PEERS = Symbol.for('peers'); -const K_INBOUND_SOURCE_IDS = Symbol.for('inbound peers'); +const K_PEERS_DISCOVERED = Symbol.for('peers discovered'); /** * Parallel gateway @@ -45,6 +45,8 @@ export function ParallelGateway(activityDef, context) { activity.logger.debug(`<${activity.id}> collected parallel gateway peers`); + activity[K_PEERS_DISCOVERED] = true; + activity.shake(message); } } @@ -100,7 +102,7 @@ ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { const peerIds = new Set([...this.activity[K_PEERS].values()].map((v) => [...v]).flat()); this[K_TARGETS] = new Map([...peerIds].map((pid) => [pid, this.activity.getActivityById(pid)])); - this.peerMonitor = new PeerMonitor(this.activity, this.activity[K_INBOUND_SOURCE_IDS], this[K_TARGETS]); + this.peerMonitor = new PeerMonitor(this.activity, this[K_TARGETS]); const message = (this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage)); const executeContent = message.content; @@ -185,7 +187,7 @@ ParallelGatewayBehaviour.prototype._stop = function stop() { this.peerMonitor.stop(); }; -function PeerMonitor(activity, peers, targets) { +function PeerMonitor(activity, targets) { this.activity = activity; this.id = activity.id; this.broker = activity.broker; @@ -194,7 +196,6 @@ function PeerMonitor(activity, peers, targets) { this.discarded = 0; this.running = new Map(); this.watching = new Map(); - this.peers = peers; this.targets = targets; this.touched = new Set(); this.inbound = []; diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 6ab8dc37..5eae1b21 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -8,6 +8,7 @@ const K_ACTIVITY_Q = Symbol.for('activityQ'); const K_ELEMENTS = Symbol.for('elements'); const K_PARENT = Symbol.for('parent'); const K_TRACKER = Symbol.for('activity tracker'); +const K_PEERS_DISCOVERED = Symbol.for('peers discovered'); /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -133,14 +134,8 @@ ProcessExecution.prototype.resume = function resume() { this._activate(); - const { startActivities, postponed, detachedActivities, convergingGateways } = this[K_ELEMENTS]; - if (startActivities.size > 1 || convergingGateways.size) { - const result = this._shakeElements(); - const skipDiscard = (this.environment.settings.skipDiscard = result.settings.skipDiscard); - this._debug( - !skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake' - ); - } + const { postponed, detachedActivities } = this[K_ELEMENTS]; + this._shakeOnStart(); postponed.clear(); detachedActivities.clear(); @@ -394,14 +389,8 @@ ProcessExecution.prototype._start = function start() { this.broker.publish(this._exchangeName, 'execute.start', cloneContent(executeContent)); - const { startActivities, postponed, detachedActivities, convergingGateways } = this[K_ELEMENTS]; - if (startActivities.size > 1 || convergingGateways.size) { - const result = this._shakeElements(); - const skipDiscard = (this.environment.settings.skipDiscard = result.settings.skipDiscard); - this._debug( - !skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake' - ); - } + const { startActivities, postponed, detachedActivities } = this[K_ELEMENTS]; + this._shakeOnStart(); for (const a of startActivities) a.init(); this[K_STATUS] = 'executing'; @@ -525,6 +514,42 @@ ProcessExecution.prototype._deactivate = function deactivate() { this[K_ACTIVATED] = false; }; +/** + * Shake on start/resume when there are converging gateways or multiple start activities. + * Reuses already discovered parallel gateway peers to skip the graph shake on repeated runs. + * @internal + */ +ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { + const { startActivities, convergingGateways } = this[K_ELEMENTS]; + + if (startActivities.size <= 1 && this._peersDiscovered()) { + this.environment.settings.skipDiscard = false; + this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size}), disabling skipDiscard`); + return; + } + + if (startActivities.size <= 1 && !convergingGateways.size) return; + + const skipDiscard = (this.environment.settings.skipDiscard = this._shakeElements().settings.skipDiscard); + this._debug( + !skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake' + ); +}; + +/** + * Whether every converging parallel gateway has discovered its peers in this runtime instance. + * Peers are a runtime cache and absent after recover, so a changed source is reshaken. + * @internal + */ +ProcessExecution.prototype._peersDiscovered = function peersDiscovered() { + const convergingGateways = this[K_ELEMENTS].convergingGateways; + if (!convergingGateways.size) return false; + for (const gateway of convergingGateways) { + if (!gateway[K_PEERS_DISCOVERED]) return false; + } + return true; +}; + /** @internal */ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { let executing = true; @@ -553,13 +578,6 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { if (content.parent.id !== this.id) return; switch (routingKey) { - case 'activity.shake.link': { - for (const a of this[K_ELEMENTS].triggeredByEvent) { - if (!a.isCatching) continue; - a.broker.publish('api', routingKey, cloneContent(content), { type: 'shake' }); - } - break; - } case 'activity.shake.join': { const join = convergingGateways.get(content.join); if (!join) { diff --git a/test/feature/issues/issue-42-feature.js b/test/feature/issues/issue-42-feature.js index 9043794e..1cee5192 100644 --- a/test/feature/issues/issue-42-feature.js +++ b/test/feature/issues/issue-42-feature.js @@ -3,6 +3,7 @@ import testHelpers from '../../helpers/testHelpers.js'; import factory from '../../helpers/factory.js'; const source = factory.resource('issue-42-same-target-sequence-flows.bpmn'); +const originalSource = factory.resource('issue-42-original.bpmn'); Feature('Issue 42 - discard loops due to multiple outbound flows to same target', () => { function takeFlow(index, vars) { @@ -98,11 +99,7 @@ Feature('Issue 42 - discard loops due to multiple outbound flows to same target' expect(definition.getActivityById('task2').counters).to.deep.equal({ taken: 1, discarded: 1 }); }); }); -}); - -const originalSource = factory.resource('issue-42-original.bpmn'); -Feature('Issue 42 - reconstructed diagram with takeOnce conditional flows', () => { /** * Take each conditional sequence flow at most once per run. * The condition expression resolves to this function, so it is called with the @@ -120,33 +117,34 @@ Feature('Issue 42 - reconstructed diagram with takeOnce conditional flows', () = ['synchronous', (scope, next) => next()], ['asynchronous', (scope, next) => process.nextTick(next)], ].forEach(([kind, serviceTask]) => { - Scenario(`every task completes with a ${kind} service task implementation`, () => { - let context, definition; - Given('a definition where conditional flows resolve to the takeOnce service function', async () => { - context = await testHelpers.context(originalSource); - definition = new Definition(context, { services: { takeOnce, serviceTask } }); - }); - - let left; - When('definition is ran', () => { - left = definition.waitFor('leave'); - definition.run(); - }); - - Then('it completes without error', () => { - return left; - }); - - And('all twenty service tasks completed at least once', () => { - for (let n = 1; n <= 20; n++) { - expect(definition.getActivityById(`task${n}`).counters, `task${n}`) - .to.have.property('taken') - .above(0); - } - }); - - And('the end event was reached', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + [true, false].forEach((skipDiscard) => { + Scenario(`every task completes with a ${kind} service task implementation and skipDiscard ${skipDiscard}`, () => { + Given('a definition where conditional flows resolve to the takeOnce service function', async () => { + context = await testHelpers.context(originalSource); + definition = new Definition(context, { settings: { skipDiscard }, services: { takeOnce, serviceTask } }); + }); + + let left; + When('definition is ran', () => { + left = definition.waitFor('leave'); + definition.run(); + }); + + Then('it completes without error', () => { + return left; + }); + + And('all twenty service tasks completed at least once', () => { + for (let n = 1; n <= 20; n++) { + expect(definition.getActivityById(`task${n}`).counters, `task${n}`) + .to.have.property('taken') + .above(0); + } + }); + + And('the end event was reached', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); }); }); }); diff --git a/test/feature/linking-feature.js b/test/feature/linking-feature.js index 78aff058..f00d4b3c 100644 --- a/test/feature/linking-feature.js +++ b/test/feature/linking-feature.js @@ -529,6 +529,60 @@ Feature('Linking', () => { }); }); + Scenario('a parallel join waits for a peer reached through a link', () => { + let definition; + Given('a fork where one branch reaches the join directly and the other via a waiting task and a link', async () => { + const source = ` + + + + + + + + + + + + + + + + + + + `; + definition = new Definition(await testHelpers.context(source), { settings: { skipDiscard } }); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('the join discovered the link-fed peer and is not taken until it arrives', () => { + expect(definition.getActivityById('join').counters).to.have.property('taken', 0); + expect(definition.getPostponed().some((a) => a.id === 'waiting')).to.be.true; + }); + + When('the waiting task on the link branch is signalled', () => { + definition.signal({ id: 'waiting' }); + }); + + Then('run completes', () => { + return end; + }); + + And('the join was taken exactly once', () => { + expect(definition.getActivityById('join').counters).to.have.property('taken', 1); + }); + + And('end was taken once', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + }); + Scenario('a flow with link event to bypass logic', () => { let context, definition; Given('a flow with link event definition to bypass major part of logic', async () => { diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index eb4a93ed..96e51a11 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -696,6 +696,68 @@ Feature('Shaking', () => { }); }); + Scenario('a converging parallel gateway discovers its peers once and reuses them', () => { + let definition; + Given('a process with a parallel fork and join', async () => { + const source = ` + + + + + + + + + + + + + + + + `; + definition = new Definition(await testHelpers.context(source)); + }); + + let shakes; + function countShakes() { + shakes = 0; + definition.broker.subscribeTmp('event', 'activity.shake.end', () => (shakes += 1), { noAck: true, consumerTag: '_test-shakes' }); + } + + When('definition is ran the first time', async () => { + countShakes(); + const left = definition.waitFor('leave'); + definition.run(); + await left; + definition.broker.cancel('_test-shakes'); + }); + + Then('the converging gateway discovered its peers by shaking', () => { + expect(shakes, 'shake on first run').to.be.above(0); + }); + + And('the parallel join completed', () => { + expect(definition.getActivityById('join').counters).to.have.property('taken', 1); + }); + + When('the same definition is ran again', async () => { + countShakes(); + const left = definition.waitFor('leave'); + definition.run(); + await left; + definition.broker.cancel('_test-shakes'); + }); + + Then('the cached peers are reused without shaking again', () => { + expect(shakes, 'no shake on second run').to.equal(0); + }); + + And('the parallel join completed again', () => { + expect(definition.getActivityById('join').counters).to.have.property('taken', 2); + }); + }); + // [ // 'join-paradox-1.bpmn', // 'join-paradox-2.bpmn', diff --git a/test/flows/SequenceFlow-test.js b/test/flows/SequenceFlow-test.js index a9b5db6a..c0f4709b 100644 --- a/test/flows/SequenceFlow-test.js +++ b/test/flows/SequenceFlow-test.js @@ -269,6 +269,31 @@ describe('SequenceFlow', () => { expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.deep.include({ take: 1, discard: 0 }); }); + it('returns the function result synchronously when the condition is executed without a callback', async () => { + const source = ` + + + + + + + + + \${environment.services.cond} + + + `; + + const ctx = await testHelpers.context(source); + ctx.environment.addService('cond', (scope) => scope.id === 'flow2'); + + const flow = ctx.getActivityById('task').outbound.find((f) => f.id === 'flow2'); + const condition = flow.getCondition(); + const result = condition.execute({ fields: {}, content: { id: 'task' }, properties: {} }); + + expect(result).to.be.true; + }); + it('does not error a non-gateway activity when every outbound condition is falsy', async () => { const source = ` diff --git a/types/index.d.ts b/types/index.d.ts index f164d989..86336b36 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2101,7 +2101,7 @@ declare module 'bpmn-elements' { peerMonitor: PeerMonitor | undefined; } class PeerMonitor { - constructor(activity: any, peers: any, targets: any); + constructor(activity: any, targets: any); activity: any; id: any; broker: any; @@ -2109,7 +2109,6 @@ declare module 'bpmn-elements' { index: number; discarded: number; watching: Map; - peers: any; targets: any; touched: Set; inbound: any[]; From b86fc215cde7b46118479c4365197987269f8fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 6 Jun 2026 12:19:04 +0200 Subject: [PATCH 24/31] stop discarding sequence flows all together --- dist/Context.js | 25 +++++++++++- dist/gateways/ParallelGateway.js | 10 +++++ dist/process/ProcessExecution.js | 20 +++------- docs/ParallelGateway.md | 22 ++++++++++ package.json | 2 +- src/Context.js | 25 +++++++++++- src/gateways/ParallelGateway.js | 14 +++++++ src/process/ProcessExecution.js | 23 +++-------- test/feature/BoundaryEvent-feature.js | 2 +- test/feature/Process-feature.js | 40 ++++--------------- test/feature/gateway-feature.js | 10 ++--- test/feature/issues/issue-42-feature.js | 12 +++--- test/feature/multiple-startevent-feature.js | 8 ++-- test/feature/parallel-gateway-feature.js | 10 ++--- test/feature/parallel-gateway-fork-feature.js | 10 ++--- test/gateways/ParallelGateway-test.js | 12 +++--- types/index.d.ts | 14 ++++++- 17 files changed, 156 insertions(+), 103 deletions(-) diff --git a/dist/Context.js b/dist/Context.js index af45ef9c..04ccc5e1 100644 --- a/dist/Context.js +++ b/dist/Context.js @@ -26,8 +26,9 @@ function Context(definitionContext, environment) { * @param {import('moddle-context-serializer').SerializableContext} definitionContext * @param {import('#types').Environment} environment * @param {import('#types').Process | import('#types').Activity} [owner] Process or sub-process activity that owns this context + * @param {Map} [peersCache] Shared converging parallel gateway peer cache; created at the root and propagated to every clone */ -function ContextInstance(definitionContext, environment, owner) { +function ContextInstance(definitionContext, environment, owner, peersCache) { const { id = 'Def', name, @@ -40,6 +41,8 @@ function ContextInstance(definitionContext, environment, owner) { this.sid = (0, _shared.getUniqueId)(id); this.definitionContext = definitionContext; this.environment = environment; + /** Discovered parallel gateway peers, keyed by gateway id, shared with all clones. Runtime-only, not serialized. */ + this.peersCache = peersCache || new Map(); /** @type {import('#types').IExtensionsMapper} */ this.extensionsMapper = new ExtensionsMapper(this); /** @private */ @@ -177,7 +180,25 @@ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associa * @param {import('#types').Process | import('#types').Activity} [newOwner] */ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { - return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner); + return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner, this.peersCache); +}; + +/** + * Cached converging parallel gateway peers discovered by an earlier shake. + * @param {string} gatewayId + * @returns {Array<[string, string[]]> | undefined} + */ +ContextInstance.prototype.getShakenPeers = function getShakenPeers(gatewayId) { + return this.peersCache.get(gatewayId); +}; + +/** + * Store converging parallel gateway peers so subsequent runs can skip the graph shake. + * @param {string} gatewayId + * @param {Array<[string, string[]]>} peers + */ +ContextInstance.prototype.setShakenPeers = function setShakenPeers(gatewayId, peers) { + this.peersCache.set(gatewayId, peers); }; /** diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 6667b38b..8c7188e2 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -34,6 +34,15 @@ function ParallelGateway(activityDef, context) { id: flowId, sourceId }) => [flowId, new Set([sourceId])])); + const cachedPeers = context.getShakenPeers(id); + if (cachedPeers) { + for (const [flowId, sourceIds] of cachedPeers) { + let peer = peers.get(flowId); + if (!peer) peers.set(flowId, peer = new Set()); + for (const sourceId of sourceIds) peer.add(sourceId); + } + activity[K_PEERS_DISCOVERED] = true; + } return activity; function onApiShake(_, message) { const collect = new Set(); @@ -53,6 +62,7 @@ function ParallelGateway(activityDef, context) { } activity.logger.debug(`<${activity.id}> collected parallel gateway peers`); activity[K_PEERS_DISCOVERED] = true; + context.setShakenPeers(id, [...peers].map(([flowId, sourceIds]) => [flowId, [...sourceIds]])); activity.shake(message); } } diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index a9b1c89f..20559d0e 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -510,6 +510,8 @@ ProcessExecution.prototype._deactivate = function deactivate() { /** * Shake on start/resume when there are converging gateways or multiple start activities. * Reuses already discovered parallel gateway peers to skip the graph shake on repeated runs. + * The shake only discovers parallel gateway peers for the peer monitor; converging joins no + * longer rely on discarded flows, so skipDiscard is left untouched. * @internal */ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { @@ -518,13 +520,12 @@ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { convergingGateways } = this[K_ELEMENTS]; if (startActivities.size <= 1 && this._peersDiscovered()) { - this.environment.settings.skipDiscard = false; - this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size}), disabling skipDiscard`); + this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size})`); return; } if (startActivities.size <= 1 && !convergingGateways.size) return; - const skipDiscard = this.environment.settings.skipDiscard = this._shakeElements().settings.skipDiscard; - this._debug(!skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake'); + this._shakeElements(); + this._debug(`forced shake to discover converging gateway peers (${convergingGateways.size})`); }; /** @@ -552,9 +553,6 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { } const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[K_ELEMENTS].startActivities; const result = { - settings: { - skipDiscard: this.environment.settings.skipDiscard - }, sequences: new Map() }; const convergingGateways = new Map(); @@ -606,14 +604,6 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { type: 'shake' }); } - if (result.settings.skipDiscard) { - for (const aid of convergingGateways.keys()) { - if (this.getActivityById(aid).isParallelGateway) { - result.settings.skipDiscard = false; - break; - } - } - } if (!executing) this._deactivate(); this.broker.cancel(consumerTag); return result; diff --git a/docs/ParallelGateway.md b/docs/ParallelGateway.md index 4314b27c..4aa2095a 100644 --- a/docs/ParallelGateway.md +++ b/docs/ParallelGateway.md @@ -8,6 +8,28 @@ A parallel gateway — fork or join — monitors its upstream peer activities an This avoids stalls in the edge case where the same inbound flow may be touched more than once before all peers have reported, and lets a single-inbound fork correctly wait for parallel upstream branches before taking its outbound flows. The outcome is `taken` if any inbound flow was taken, otherwise `discarded`. +## When to use a parallel gateway + +A parallel gateway is the only element that gives true **barrier** semantics: a converging parallel gateway waits for _every_ concurrent upstream branch to settle before it continues. Reach for it when you must converge all flows before proceeding — e.g. two parallel branches that both have to finish before the next step may start. + +If you do **not** need that guarantee, prefer a cheaper construct: + +- An exclusive gateway or an uncontrolled merge (an activity with multiple incoming flows) continues as soon as _any_ inbound flow is taken — it does not wait, and does not trigger the costs below. +- For "first one wins" semantics use an event-based gateway. + +Picking a parallel join only when you genuinely need the barrier keeps the common path on the cheaper machinery. + +## Performance and trade-offs + +A converging parallel gateway is more expensive than the other gateways, by design: + +- **Process shake on start.** To learn which upstream activities are its peers, the presence of a converging parallel gateway forces a graph shake when the process starts. Exclusive, inclusive and event-based joins do not. The shake walks the reachable graph, so its cost grows with graph size, and on graphs with many branching gateways in series it can grow super-linearly (it enumerates paths). The shake result is cached on the context and reused, so it runs **once per context** rather than once per run — reuse the same `Context`/`Definition` source across executions so the shake amortizes instead of repeating. +- **Peer monitoring at runtime.** While converging, the gateway watches all of its discovered peer activities until they settle (see _Converging behaviour_ above), which is more work than counting inbound flows. + +The upside is correctness on hard topologies and a large win elsewhere: because joins no longer rely on discarded flows arriving, dead branches are not propagated as discards. On branchy or looping diagrams that is dramatically cheaper than discarding every dead-path flow on every run. + +Rule of thumb: a parallel join is the right tool when you must synchronise all branches; avoid it on hot paths where an exclusive merge would do, and reuse the context so the one-time shake is paid once. + ## Events - `activity.converge`: The parallel gateway is collecting inbound and monitoring peers diff --git a/package.json b/package.json index 71ad40d8..734f7095 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "globals": "^17.0.0", "mocha": "^11.0.1", "mocha-cakes-2": "^3.3.0", - "moddle-context-serializer": "^5.0.0", + "moddle-context-serializer": "^6.0.0", "nock": "^14.0.0", "prettier": "^3.2.5", "texample": "^1.0.1" diff --git a/src/Context.js b/src/Context.js index ad5662a3..a6c25d02 100644 --- a/src/Context.js +++ b/src/Context.js @@ -20,8 +20,9 @@ export function Context(definitionContext, environment) { * @param {import('moddle-context-serializer').SerializableContext} definitionContext * @param {import('#types').Environment} environment * @param {import('#types').Process | import('#types').Activity} [owner] Process or sub-process activity that owns this context + * @param {Map} [peersCache] Shared converging parallel gateway peer cache; created at the root and propagated to every clone */ -export function ContextInstance(definitionContext, environment, owner) { +export function ContextInstance(definitionContext, environment, owner, peersCache) { const { id = 'Def', name, type = 'context' } = definitionContext; this.id = id; this.name = name; @@ -30,6 +31,8 @@ export function ContextInstance(definitionContext, environment, owner) { this.sid = getUniqueId(id); this.definitionContext = definitionContext; this.environment = environment; + /** Discovered parallel gateway peers, keyed by gateway id, shared with all clones. Runtime-only, not serialized. */ + this.peersCache = peersCache || new Map(); /** @type {import('#types').IExtensionsMapper} */ this.extensionsMapper = new ExtensionsMapper(this); /** @private */ @@ -184,7 +187,25 @@ ContextInstance.prototype.upsertAssociation = function upsertAssociation(associa * @param {import('#types').Process | import('#types').Activity} [newOwner] */ ContextInstance.prototype.clone = function clone(newEnvironment, newOwner) { - return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner); + return new ContextInstance(this.definitionContext, newEnvironment || this.environment, newOwner, this.peersCache); +}; + +/** + * Cached converging parallel gateway peers discovered by an earlier shake. + * @param {string} gatewayId + * @returns {Array<[string, string[]]> | undefined} + */ +ContextInstance.prototype.getShakenPeers = function getShakenPeers(gatewayId) { + return this.peersCache.get(gatewayId); +}; + +/** + * Store converging parallel gateway peers so subsequent runs can skip the graph shake. + * @param {string} gatewayId + * @param {Array<[string, string[]]>} peers + */ +ContextInstance.prototype.setShakenPeers = function setShakenPeers(gatewayId, peers) { + this.peersCache.set(gatewayId, peers); }; /** diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index bb14aed8..363e9a41 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -23,6 +23,16 @@ export function ParallelGateway(activityDef, context) { const peers = (activity[K_PEERS] = new Map(activity.inbound.map(({ id: flowId, sourceId }) => [flowId, new Set([sourceId])]))); + const cachedPeers = context.getShakenPeers(id); + if (cachedPeers) { + for (const [flowId, sourceIds] of cachedPeers) { + let peer = peers.get(flowId); + if (!peer) peers.set(flowId, (peer = new Set())); + for (const sourceId of sourceIds) peer.add(sourceId); + } + activity[K_PEERS_DISCOVERED] = true; + } + return activity; function onApiShake(_, message) { @@ -46,6 +56,10 @@ export function ParallelGateway(activityDef, context) { activity.logger.debug(`<${activity.id}> collected parallel gateway peers`); activity[K_PEERS_DISCOVERED] = true; + context.setShakenPeers( + id, + [...peers].map(([flowId, sourceIds]) => [flowId, [...sourceIds]]) + ); activity.shake(message); } diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 5eae1b21..6067ac3a 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -517,23 +517,22 @@ ProcessExecution.prototype._deactivate = function deactivate() { /** * Shake on start/resume when there are converging gateways or multiple start activities. * Reuses already discovered parallel gateway peers to skip the graph shake on repeated runs. + * The shake only discovers parallel gateway peers for the peer monitor; converging joins no + * longer rely on discarded flows, so skipDiscard is left untouched. * @internal */ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { const { startActivities, convergingGateways } = this[K_ELEMENTS]; if (startActivities.size <= 1 && this._peersDiscovered()) { - this.environment.settings.skipDiscard = false; - this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size}), disabling skipDiscard`); + this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size})`); return; } if (startActivities.size <= 1 && !convergingGateways.size) return; - const skipDiscard = (this.environment.settings.skipDiscard = this._shakeElements().settings.skipDiscard); - this._debug( - !skipDiscard ? `forced shake, disabling skipDiscard due to converging gateways (${convergingGateways.size})` : 'forced shake' - ); + this._shakeElements(); + this._debug(`forced shake to discover converging gateway peers (${convergingGateways.size})`); }; /** @@ -562,9 +561,6 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[K_ELEMENTS].startActivities; const result = { - settings: { - skipDiscard: this.environment.settings.skipDiscard, - }, sequences: new Map(), }; @@ -614,15 +610,6 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { this.getActivityById(aid).broker.publish('api', 'activity.shake.continue', c, { type: 'shake' }); } - if (result.settings.skipDiscard) { - for (const aid of convergingGateways.keys()) { - if (this.getActivityById(aid).isParallelGateway) { - result.settings.skipDiscard = false; - break; - } - } - } - if (!executing) this._deactivate(); this.broker.cancel(consumerTag); diff --git a/test/feature/BoundaryEvent-feature.js b/test/feature/BoundaryEvent-feature.js index b9e55c92..dee59b51 100644 --- a/test/feature/BoundaryEvent-feature.js +++ b/test/feature/BoundaryEvent-feature.js @@ -110,7 +110,7 @@ Feature('BoundaryEvent', () => { }); And('user task was taken', () => { - expect(bp.getActivityById('task').counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); + expect(bp.getActivityById('task').counters).to.have.property('discarded', 1); expect(bp.getActivityById('task').counters).to.have.property('taken', 1); }); diff --git a/test/feature/Process-feature.js b/test/feature/Process-feature.js index aa9839e3..358ee8f6 100644 --- a/test/feature/Process-feature.js +++ b/test/feature/Process-feature.js @@ -2273,14 +2273,11 @@ Feature('Process', () => { return timeout; }); - Then('process execution is looped back to user task', () => { + Then('the loop branch is taken and execution loops back to user task', () => { + assertMessage('flow.take', 'toLoop'); assertMessage('activity.wait', 'userTask1'); }); - And('end event is discarded', () => { - assertMessage('activity.discard', 'theEnd'); - }); - When('user task is signaled again', () => { timeout = processInstance.waitFor('activity.timeout'); @@ -2296,22 +2293,11 @@ Feature('Process', () => { return timeout; }); - Then('looped flow is discarded', () => { - assertMessage('flow.discard', 'toLoop'); - }); - - And('user task is discarded', () => { - assertMessage('activity.discard', 'userTask1'); - }); - - And('end event completes', () => { + Then('the final branch is taken and end event completes', () => { + assertMessage('flow.take', 'toFinal'); assertMessage('activity.end', 'theEnd'); }); - And('flow loop is detected', () => { - assertMessage('flow.looped', 'toDecision'); - }); - And('process execution is completed', () => { assertMessage('process.end', 'motherOfAll'); assertMessage('process.leave', 'motherOfAll'); @@ -2435,7 +2421,8 @@ Feature('Process', () => { return timeout; }); - Then('process execution is looped back to user task', () => { + Then('the loop branch is taken and execution loops back to user task', () => { + assertMessage('flow.take', 'toLoop'); assertMessage('activity.wait', 'userTask1'); }); @@ -2452,22 +2439,11 @@ Feature('Process', () => { return timeout; }); - Then('looped flow is discarded', () => { - assertMessage('flow.discard', 'toLoop'); - }); - - And('user task is discarded', () => { - assertMessage('activity.discard', 'userTask1'); - }); - - And('end event completes', () => { + Then('the final branch is taken and end event completes', () => { + assertMessage('flow.take', 'toFinal'); assertMessage('activity.end', 'theEnd'); }); - And('flow loop is detected', () => { - assertMessage('flow.looped', 'toDecision'); - }); - And('process execution is completed', () => { assertMessage('process.end', 'motherOfAll'); assertMessage('process.leave', 'motherOfAll'); diff --git a/test/feature/gateway-feature.js b/test/feature/gateway-feature.js index 99f14615..90588f9a 100644 --- a/test/feature/gateway-feature.js +++ b/test/feature/gateway-feature.js @@ -313,10 +313,10 @@ Feature('Gateway', () => { expect(denied.counters).to.have.property('discarded', 0); }); - And('script flow was discarded', () => { + And('script flow was not taken', () => { const accepted = definition.getActivityById('accepted'); expect(accepted.counters).to.have.property('taken', 0); - expect(accepted.counters).to.have.property('discarded', 1); + expect(accepted.counters).to.have.property('discarded', 0); }); When('definition is ran again', () => { @@ -332,16 +332,16 @@ Feature('Gateway', () => { return end; }); - And('default flow was discarded', () => { + And('default flow was not taken again', () => { const denied = definition.getActivityById('denied'); expect(denied.counters).to.have.property('taken', 1); - expect(denied.counters).to.have.property('discarded', 1); + expect(denied.counters).to.have.property('discarded', 0); }); And('script flow was taken', () => { const accepted = definition.getActivityById('accepted'); expect(accepted.counters).to.have.property('taken', 1); - expect(accepted.counters).to.have.property('discarded', 1); + expect(accepted.counters).to.have.property('discarded', 0); }); }); diff --git a/test/feature/issues/issue-42-feature.js b/test/feature/issues/issue-42-feature.js index 1cee5192..fbb5e47e 100644 --- a/test/feature/issues/issue-42-feature.js +++ b/test/feature/issues/issue-42-feature.js @@ -33,8 +33,8 @@ Feature('Issue 42 - discard loops due to multiple outbound flows to same target' return end; }); - And('target activity is discarded twice due to loop back flow', () => { - expect(definition.getActivityById('task2').counters).to.deep.equal({ taken: 0, discarded: 2 }); + And('target activity is neither taken nor discarded', () => { + expect(definition.getActivityById('task2').counters).to.deep.equal({ taken: 0, discarded: 0 }); }); }); @@ -54,7 +54,7 @@ Feature('Issue 42 - discard loops due to multiple outbound flows to same target' let task; And('target activity is taken once', () => { task = definition.getActivityById('task2'); - expect(task.counters).to.deep.equal({ taken: 1, discarded: 1 }); + expect(task.counters).to.deep.equal({ taken: 1, discarded: 0 }); }); And('sequence flow 1 is taken', () => { @@ -74,11 +74,11 @@ Feature('Issue 42 - discard loops due to multiple outbound flows to same target' }); And('target activity is taken once', () => { - expect(task.counters).to.deep.equal({ taken: 2, discarded: 2 }); + expect(task.counters).to.deep.equal({ taken: 2, discarded: 0 }); }); And('sequence flow 2 is taken', () => { - expect(task.inbound.find((f) => f.id === 'to-task2-2').counters).to.deep.equal({ take: 1, discard: 2, looped: 0 }); + expect(task.inbound.find((f) => f.id === 'to-task2-2').counters).to.deep.equal({ take: 1, discard: 0, looped: 0 }); }); }); @@ -96,7 +96,7 @@ Feature('Issue 42 - discard loops due to multiple outbound flows to same target' }); And('target activity is taken once', () => { - expect(definition.getActivityById('task2').counters).to.deep.equal({ taken: 1, discarded: 1 }); + expect(definition.getActivityById('task2').counters).to.deep.equal({ taken: 1, discarded: 0 }); }); }); diff --git a/test/feature/multiple-startevent-feature.js b/test/feature/multiple-startevent-feature.js index d0b0edba..e6a5b8e2 100644 --- a/test/feature/multiple-startevent-feature.js +++ b/test/feature/multiple-startevent-feature.js @@ -169,9 +169,9 @@ Feature('Multiple start events', () => { }); }); - Then('first end event is discarded', () => { + Then('first end event is not taken', () => { const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 1 }); + expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 0 }); }); And('second end event is taken', () => { @@ -188,9 +188,9 @@ Feature('Multiple start events', () => { definition.signal({ id: 'Message_1' }); }); - Then('first end event is discarded', () => { + Then('first end event is not taken', () => { const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 2 }); + expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 0 }); }); And('second end event is taken', () => { diff --git a/test/feature/parallel-gateway-feature.js b/test/feature/parallel-gateway-feature.js index 712cc404..5e7e40c8 100644 --- a/test/feature/parallel-gateway-feature.js +++ b/test/feature/parallel-gateway-feature.js @@ -48,8 +48,8 @@ Feature('Parallel gateway', () => { expect(joinGw.inbound).to.have.length(4); }); - And('join end message inbound flows is greater then inbound sequence flows', () => { - expect(endMsg.content.inbound).to.have.length(6); + And('join end message inbound flows are only the taken inbound sequence flows', () => { + expect(endMsg.content.inbound).to.have.length(2); }); And('no pending inbound exists', () => { @@ -74,8 +74,8 @@ Feature('Parallel gateway', () => { expect(joinGw.inbound).to.have.length(4); }); - And('join start message inbound flows is greater then inbound sequence flows', () => { - expect(endMsg.content.inbound).to.have.length(6); + And('join start message inbound flows are only the taken inbound sequence flows', () => { + expect(endMsg.content.inbound).to.have.length(2); }); let stopped; @@ -223,7 +223,7 @@ Feature('Parallel gateway', () => { }); But('with expected number of inbound', () => { - expect(joinLeaveMsg.content.inbound).to.have.length(6); + expect(joinLeaveMsg.content.inbound).to.have.length(2); }); And('and no postponed elements', () => { diff --git a/test/feature/parallel-gateway-fork-feature.js b/test/feature/parallel-gateway-fork-feature.js index 74d486ca..a13d8773 100644 --- a/test/feature/parallel-gateway-fork-feature.js +++ b/test/feature/parallel-gateway-fork-feature.js @@ -293,13 +293,13 @@ Feature('Parallel gateway fork', () => { let forkGw; And('parallel fork was taken twice', () => { forkGw = definition.getActivityById('join'); - expect(forkGw.counters).to.deep.equal({ taken: 2, discarded: 1 }); + expect(forkGw.counters).to.deep.equal({ taken: 2, discarded: 0 }); }); let joinGw; And('parallel join was taken twice', () => { joinGw = definition.getActivityById('join'); - expect(joinGw.counters).to.deep.equal({ taken: 2, discarded: 1 }); + expect(joinGw.counters).to.deep.equal({ taken: 2, discarded: 0 }); }); And('no pending inbound exists', () => { @@ -322,7 +322,7 @@ Feature('Parallel gateway fork', () => { And('parallel join was taken twice again', () => { joinGw = definition.getActivityById('join'); - expect(joinGw.counters).to.deep.equal({ taken: 4, discarded: 2 }); + expect(joinGw.counters).to.deep.equal({ taken: 4, discarded: 0 }); }); let stopped; @@ -455,7 +455,7 @@ Feature('Parallel gateway fork', () => { And('join was taken the expected number of times', () => { const joinGw = definition.getActivityById('join'); - expect(joinGw.counters).to.deep.equal({ taken: 2, discarded: 1 }); + expect(joinGw.counters).to.deep.equal({ taken: 2, discarded: 0 }); }); And('fork was taken the expected number of times', () => { @@ -499,7 +499,7 @@ Feature('Parallel gateway fork', () => { And('join was taken the expected number of times', () => { const joinGw = definition.getActivityById('join'); - expect(joinGw.counters).to.deep.equal({ taken: 3, discarded: 2 }); + expect(joinGw.counters).to.deep.equal({ taken: 3, discarded: 0 }); }); And('fork was taken the expected number of times', () => { diff --git a/test/gateways/ParallelGateway-test.js b/test/gateways/ParallelGateway-test.js index 4791427f..eb6e3913 100644 --- a/test/gateways/ParallelGateway-test.js +++ b/test/gateways/ParallelGateway-test.js @@ -106,11 +106,11 @@ describe('ParallelGateway', () => { expect(join.outbound[0].counters).to.have.property('discard', 0); }); - it('discards outbound when all three branches skip their task (all inbound discarded)', async () => { + it('leaves the join untouched when all three branches skip their task (all inbound discarded)', async () => { const join = await runWith([false, false, false]); - expect(join.counters).to.deep.equal({ taken: 0, discarded: 1 }); + expect(join.counters).to.deep.equal({ taken: 0, discarded: 0 }); expect(join.outbound[0].counters).to.have.property('take', 0); - expect(join.outbound[0].counters).to.have.property('discard', 1); + expect(join.outbound[0].counters).to.have.property('discard', 0); }); it('takes outbound when at least one branch takes (one discarded, two taken)', async () => { @@ -221,14 +221,14 @@ describe('ParallelGateway', () => { expect(join1.inbound[0].counters).to.have.property('take', 1); expect(join1.inbound[0].counters).to.have.property('discard', 0); expect(join1.inbound[1].counters).to.have.property('take', 0); - expect(join1.inbound[1].counters).to.have.property('discard', 1); + expect(join1.inbound[1].counters).to.have.property('discard', 0); expect(join1.outbound[0].counters).to.have.property('take', 1); expect(join1.outbound[0].counters).to.have.property('discard', 0); const join2 = bp.getActivityById('join2'); expect(join2.inbound[0].counters).to.have.property('take', 0); - expect(join2.inbound[0].counters).to.have.property('discard', 1); + expect(join2.inbound[0].counters).to.have.property('discard', 0); expect(join2.inbound[1].counters).to.have.property('take', 1); expect(join2.inbound[1].counters).to.have.property('discard', 0); expect(join2.outbound[0].counters).to.have.property('take', 1); @@ -278,7 +278,7 @@ describe('ParallelGateway', () => { expect(join.inbound[0].counters).to.have.property('take', 1); expect(join.inbound[0].counters).to.have.property('discard', 0); expect(join.inbound[1].counters).to.have.property('take', 0); - expect(join.inbound[1].counters).to.have.property('discard', 1); + expect(join.inbound[1].counters).to.have.property('discard', 0); expect(join.outbound[0].counters).to.have.property('take', 1); expect(join.outbound[0].counters).to.have.property('discard', 0); }); diff --git a/types/index.d.ts b/types/index.d.ts index 86336b36..6286cc28 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -767,13 +767,15 @@ declare module 'bpmn-elements' { /** * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. * @param owner Process or sub-process activity that owns this context + * @param peersCache Shared converging parallel gateway peer cache; created at the root and propagated to every clone */ export class ContextInstance { /** * Per-execution registry that lazily upserts activities, flows, and processes from the parsed BPMN definition. * @param owner Process or sub-process activity that owns this context + * @param peersCache Shared converging parallel gateway peer cache; created at the root and propagated to every clone */ - constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity); + constructor(definitionContext: import("moddle-context-serializer").SerializableContext, environment: Environment, owner?: Process | Activity, peersCache?: Map); id: string; name: string; type: string; @@ -781,6 +783,8 @@ declare module 'bpmn-elements' { sid: string; definitionContext: import("moddle-context-serializer").SerializableContext; environment: Environment; + /** Discovered parallel gateway peers, keyed by gateway id, shared with all clones. Runtime-only, not serialized. */ + peersCache: Map; extensionsMapper: IExtensionsMapper; get owner(): Activity | Process | undefined; @@ -830,6 +834,14 @@ declare module 'bpmn-elements' { * */ clone(newEnvironment?: Environment, newOwner?: Process | Activity): ContextInstance; + /** + * Cached converging parallel gateway peers discovered by an earlier shake. + * */ + getShakenPeers(gatewayId: string): Array<[string, string[]]> | undefined; + /** + * Store converging parallel gateway peers so subsequent runs can skip the graph shake. + * */ + setShakenPeers(gatewayId: string, peers: Array<[string, string[]]>): void; /** * Get or create the process instance for the given id. Each process gets its own cloned environment. * */ From 9be635a4fccb2f2e73fe46d254a8fa4da04aa3d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Tue, 9 Jun 2026 08:19:01 +0200 Subject: [PATCH 25/31] multiple start events are mutually exclusive entry points --- CHANGELOG.md | 7 +- dist/activity/Activity.js | 6 + dist/events/StartEvent.js | 5 +- dist/process/ProcessExecution.js | 73 ++-- src/activity/Activity.js | 6 + src/events/StartEvent.js | 2 +- src/process/ProcessExecution.js | 75 ++-- test/feature/Process-feature.js | 27 +- test/feature/multiple-startevent-feature.js | 381 ++++++++++++++++---- test/feature/shake-feature.js | 83 ++--- test/feature/signal-feature.js | 45 +-- types/index.d.ts | 5 +- types/interfaces.d.ts | 2 + 13 files changed, 468 insertions(+), 249 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 818e47c7..cd00ce3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## v18.0.0 - 2026-05-31 -Refactor parallel converging and forking gateways. +Refactor parallel converging and forking gateways, and treat multiple start events as mutually exclusive entry points. ### Breaking @@ -11,11 +11,15 @@ Refactor parallel converging and forking gateways. - IntermediateCatchEvent cannot be used as a starting element, or it can but will not be started by default - `Definition` must be called with `new` - non-gateway activities discard their outbound when all conditional flows are falsy instead of throwing; only exclusive and inclusive gateways still require a taken or default flow +- multiple start events are mutually exclusive entry points — the first start event to fire discards the others still waiting to be triggered, so two start events can no longer both run (e.g. into a parallel join, or a joining task taken twice) +- start activities that are not start events (e.g. a starting receive task, or an activity without an inbound flow) are no longer auto-discarded; they are genuine tokens that must be signalled or completed +- multiple start events no longer trigger a graph shake on run/resume; only converging parallel gateways do, and the shake remains available on demand via `shake()` ### Additions - expose throwable error classes via new `bpmn-elements/errors` subpath: `import { ActivityError, BpmnError, RunError } from 'bpmn-elements/errors'` - activity readonly property `isParallelJoin` indicating a parallel converging gateway +- activity readonly property `isStartEvent` indicating a start event - new activity event `activity.converge` published when parallel gateway is executed - fix link event definition shaking - fix `Activity.recover()` to return the activity when called without state @@ -25,6 +29,7 @@ Refactor parallel converging and forking gateways. ### Types - runtime types are now generated from JSDoc and bundled with [dts-buddy](https://github.com/Rich-Harris/dts-buddy); status enums (`ActivityStatus`, `DefinitionStatus`, `ProcessStatus`) and `TimerType` accept both enum members and their string literals. +- expose `isStartEvent` and `isParallelGateway` on the `Activity` interface ## v17.3.0 - 2025-12-03 diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index a450875d..1d782eef 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -107,6 +107,7 @@ function Activity(Behaviour, activityDef, context) { isTransaction: activityDef.isTransaction, isParallelJoin, isParallelGateway: activityDef.isParallelGateway, + isStartEvent: !!activityDef.isStartEvent, isThrowing: activityDef.isThrowing, linkNames: activityDef.linkNames, linkBehaviour: activityDef.linkBehaviour, @@ -230,6 +231,11 @@ Object.defineProperties(Activity.prototype, { return this[K_FLAGS].isParallelGateway; } }, + isStartEvent: { + get() { + return this[K_FLAGS].isStartEvent; + } + }, triggeredByEvent: { get() { return this[K_ACTIVITY_DEF].triggeredByEvent; diff --git a/dist/events/StartEvent.js b/dist/events/StartEvent.js index 14dc9793..07e513f6 100644 --- a/dist/events/StartEvent.js +++ b/dist/events/StartEvent.js @@ -15,7 +15,10 @@ var _constants = require("../constants.js"); * @param {import('#types').ContextInstance} context */ function StartEvent(activityDef, context) { - return new _Activity.Activity(StartEventBehaviour, activityDef, context); + return new _Activity.Activity(StartEventBehaviour, { + ...activityDef, + isStartEvent: true + }, context); } /** diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 20559d0e..4af063e6 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -44,10 +44,10 @@ function ProcessExecution(parentActivity, context) { flows: context.getSequenceFlows(id), outboundMessageFlows: context.getMessageFlows(id), startActivities: new Set(), + startEventCount: 0, triggeredByEvent: new Set(), detachedActivities: new Set(), - convergingGateways: new Set(), - startSequences: new Map() + convergingGateways: new Set() }; const exchangeName = this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution'; broker.assertExchange(exchangeName, 'topic', { @@ -129,8 +129,7 @@ ProcessExecution.prototype.execute = function execute(executeMessage) { }; /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. + * Resume after recover, resuming any postponed children. */ ProcessExecution.prototype.resume = function resume() { this._debug(`resume process execution at ${this.status}`); @@ -426,7 +425,6 @@ ProcessExecution.prototype._activate = function activate() { flows, associations, startActivities, - startSequences, triggeredByEvent, convergingGateways, children @@ -455,6 +453,7 @@ ProcessExecution.prototype._activate = function activate() { } startActivities.clear(); triggeredByEvent.clear(); + let startEventCount = 0; for (const activity of children) { if (activity.placeholder) continue; activity.activate(this); @@ -465,15 +464,12 @@ ProcessExecution.prototype._activate = function activate() { }); if (activity.isStart) { startActivities.add(activity); + if (activity.isStartEvent) startEventCount++; } if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); if (activity.isParallelGateway) convergingGateways.add(activity); } - if (startActivities.size > 1) { - for (const activity of startActivities) { - startSequences.set(activity.id, new Set()); - } - } + this[K_ELEMENTS].startEventCount = startEventCount; this[_constants.K_ACTIVATED] = true; }; @@ -508,22 +504,16 @@ ProcessExecution.prototype._deactivate = function deactivate() { }; /** - * Shake on start/resume when there are converging gateways or multiple start activities. - * Reuses already discovered parallel gateway peers to skip the graph shake on repeated runs. - * The shake only discovers parallel gateway peers for the peer monitor; converging joins no - * longer rely on discarded flows, so skipDiscard is left untouched. + * Discover converging parallel gateway peers for the peer monitor, reusing already discovered ones. * @internal */ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { - const { - startActivities, - convergingGateways - } = this[K_ELEMENTS]; - if (startActivities.size <= 1 && this._peersDiscovered()) { + const convergingGateways = this[K_ELEMENTS].convergingGateways; + if (!convergingGateways.size) return; + if (this._peersDiscovered()) { this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size})`); return; } - if (startActivities.size <= 1 && !convergingGateways.size) return; this._shakeElements(); this._debug(`forced shake to discover converging gateway peers (${convergingGateways.size})`); }; @@ -535,7 +525,6 @@ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { */ ProcessExecution.prototype._peersDiscovered = function peersDiscovered() { const convergingGateways = this[K_ELEMENTS].convergingGateways; - if (!convergingGateways.size) return false; for (const gateway of convergingGateways) { if (!gateway[K_PEERS_DISCOVERED]) return false; } @@ -667,7 +656,7 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe delegate, mandatory: false }); - if (shaking) return this._onShakeMessage(message); + if (shaking) return; if (!isDirectChild) return; switch (routingKey) { case 'process.terminate': @@ -750,6 +739,20 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, } break; } + case 'activity.end': + { + if (!content.isStartEvent) break; + const elements = this[K_ELEMENTS]; + if (elements.startEventCount <= 1) break; + const startPeers = new Set(); + for (const msg of elements.postponed) { + const peerId = msg.content.id; + if (peerId !== content.id && msg.content.isStartEvent) startPeers.add(msg); + } + elements.startEventCount = 0; + for (const msg of startPeers) this._getChildApi(msg).discard(); + break; + } case 'activity.error': { let eventCaughtBy; @@ -822,7 +825,6 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message const { id, type, - isEnd, isParallelGateway } = message.content; if (isParallelGateway) { @@ -832,8 +834,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message } const { postponed, - detachedActivities, - startActivities + detachedActivities } = this[K_ELEMENTS]; const postponedCount = postponed.size; if (!postponedCount) { @@ -854,17 +855,6 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message type: 'cancel' }); } - if (isEnd && startActivities.size) { - const startSequences = this[K_ELEMENTS].startSequences; - for (const msg of postponed) { - const postponedId = msg.content.id; - const startSequence = startSequences.get(postponedId); - if (!startSequence) continue; - if (startSequence.has(id)) { - this._getChildApi(msg).discard(); - } - } - } }; /** @internal */ @@ -1067,17 +1057,6 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { } }; -/** @internal */ -ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { - if (message.fields.routingKey !== 'activity.shake.end') return; - let seq; - if (!(seq = this[K_ELEMENTS].startSequences.get(message.content.id))) return; - for (const s of message.content.sequence) { - if (s.isSequenceFlow) continue; - seq.add(s.id); - } -}; - /** @internal */ ProcessExecution.prototype._debug = function debugMessage(logMessage) { this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); diff --git a/src/activity/Activity.js b/src/activity/Activity.js index dd1844df..f2f702cb 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -101,6 +101,7 @@ export function Activity(Behaviour, activityDef, context) { isTransaction: activityDef.isTransaction, isParallelJoin, isParallelGateway: activityDef.isParallelGateway, + isStartEvent: !!activityDef.isStartEvent, isThrowing: activityDef.isThrowing, linkNames: activityDef.linkNames, linkBehaviour: activityDef.linkBehaviour, @@ -224,6 +225,11 @@ Object.defineProperties(Activity.prototype, { return this[K_FLAGS].isParallelGateway; }, }, + isStartEvent: { + get() { + return this[K_FLAGS].isStartEvent; + }, + }, triggeredByEvent: { get() { return this[K_ACTIVITY_DEF].triggeredByEvent; diff --git a/src/events/StartEvent.js b/src/events/StartEvent.js index bd3da4f9..7d8e0bc2 100644 --- a/src/events/StartEvent.js +++ b/src/events/StartEvent.js @@ -9,7 +9,7 @@ import { K_EXECUTE_MESSAGE, K_EXECUTION } from '../constants.js'; * @param {import('#types').ContextInstance} context */ export function StartEvent(activityDef, context) { - return new Activity(StartEventBehaviour, activityDef, context); + return new Activity(StartEventBehaviour, { ...activityDef, isStartEvent: true }, context); } /** diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 6067ac3a..42ca5e09 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -35,10 +35,10 @@ export function ProcessExecution(parentActivity, context) { flows: context.getSequenceFlows(id), outboundMessageFlows: context.getMessageFlows(id), startActivities: new Set(), + startEventCount: 0, triggeredByEvent: new Set(), detachedActivities: new Set(), convergingGateways: new Set(), - startSequences: new Map(), }; const exchangeName = (this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution'); @@ -124,8 +124,7 @@ ProcessExecution.prototype.execute = function execute(executeMessage) { }; /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. + * Resume after recover, resuming any postponed children. */ ProcessExecution.prototype.resume = function resume() { this._debug(`resume process execution at ${this.status}`); @@ -428,8 +427,7 @@ ProcessExecution.prototype._activate = function activate() { }); } - const { outboundMessageFlows, flows, associations, startActivities, startSequences, triggeredByEvent, convergingGateways, children } = - this[K_ELEMENTS]; + const { outboundMessageFlows, flows, associations, startActivities, triggeredByEvent, convergingGateways, children } = this[K_ELEMENTS]; for (const flow of outboundMessageFlows) { flow.activate(); @@ -459,6 +457,7 @@ ProcessExecution.prototype._activate = function activate() { startActivities.clear(); triggeredByEvent.clear(); + let startEventCount = 0; for (const activity of children) { if (activity.placeholder) continue; activity.activate(this); @@ -469,17 +468,13 @@ ProcessExecution.prototype._activate = function activate() { }); if (activity.isStart) { startActivities.add(activity); + if (activity.isStartEvent) startEventCount++; } if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity); if (activity.isParallelGateway) convergingGateways.add(activity); } - if (startActivities.size > 1) { - for (const activity of startActivities) { - startSequences.set(activity.id, new Set()); - } - } - + this[K_ELEMENTS].startEventCount = startEventCount; this[K_ACTIVATED] = true; }; @@ -515,22 +510,18 @@ ProcessExecution.prototype._deactivate = function deactivate() { }; /** - * Shake on start/resume when there are converging gateways or multiple start activities. - * Reuses already discovered parallel gateway peers to skip the graph shake on repeated runs. - * The shake only discovers parallel gateway peers for the peer monitor; converging joins no - * longer rely on discarded flows, so skipDiscard is left untouched. + * Discover converging parallel gateway peers for the peer monitor, reusing already discovered ones. * @internal */ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { - const { startActivities, convergingGateways } = this[K_ELEMENTS]; + const convergingGateways = this[K_ELEMENTS].convergingGateways; + if (!convergingGateways.size) return; - if (startActivities.size <= 1 && this._peersDiscovered()) { + if (this._peersDiscovered()) { this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size})`); return; } - if (startActivities.size <= 1 && !convergingGateways.size) return; - this._shakeElements(); this._debug(`forced shake to discover converging gateway peers (${convergingGateways.size})`); }; @@ -542,7 +533,6 @@ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() { */ ProcessExecution.prototype._peersDiscovered = function peersDiscovered() { const convergingGateways = this[K_ELEMENTS].convergingGateways; - if (!convergingGateways.size) return false; for (const gateway of convergingGateways) { if (!gateway[K_PEERS_DISCOVERED]) return false; } @@ -667,7 +657,7 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe this[K_TRACKER].track(routingKey, message); this.broker.publish('event', routingKey, content, { ...properties, delegate, mandatory: false }); - if (shaking) return this._onShakeMessage(message); + if (shaking) return; if (!isDirectChild) return; switch (routingKey) { @@ -748,6 +738,20 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, break; } + case 'activity.end': { + if (!content.isStartEvent) break; + const elements = this[K_ELEMENTS]; + if (elements.startEventCount <= 1) break; + + const startPeers = new Set(); + for (const msg of elements.postponed) { + const peerId = msg.content.id; + if (peerId !== content.id && msg.content.isStartEvent) startPeers.add(msg); + } + elements.startEventCount = 0; + for (const msg of startPeers) this._getChildApi(msg).discard(); + break; + } case 'activity.error': { let eventCaughtBy; for (const msg of this[K_ELEMENTS].postponed) { @@ -814,7 +818,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message this._stateChangeMessage(message, false); if (message.fields.redelivered) return message.ack(); - const { id, type, isEnd, isParallelGateway } = message.content; + const { id, type, isParallelGateway } = message.content; if (isParallelGateway) { for (const inb of message.content.inbound) { @@ -822,7 +826,7 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message } } - const { postponed, detachedActivities, startActivities } = this[K_ELEMENTS]; + const { postponed, detachedActivities } = this[K_ELEMENTS]; const postponedCount = postponed.size; if (!postponedCount) { @@ -845,19 +849,6 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message { type: 'cancel' } ); } - - if (isEnd && startActivities.size) { - const startSequences = this[K_ELEMENTS].startSequences; - for (const msg of postponed) { - const postponedId = msg.content.id; - const startSequence = startSequences.get(postponedId); - if (!startSequence) continue; - - if (startSequence.has(id)) { - this._getChildApi(msg).discard(); - } - } - } }; /** @internal */ @@ -1085,18 +1076,6 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) { } }; -/** @internal */ -ProcessExecution.prototype._onShakeMessage = function onShakeMessage(message) { - if (message.fields.routingKey !== 'activity.shake.end') return; - let seq; - if (!(seq = this[K_ELEMENTS].startSequences.get(message.content.id))) return; - - for (const s of message.content.sequence) { - if (s.isSequenceFlow) continue; - seq.add(s.id); - } -}; - /** @internal */ ProcessExecution.prototype._debug = function debugMessage(logMessage) { this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`); diff --git a/test/feature/Process-feature.js b/test/feature/Process-feature.js index 358ee8f6..cfdbb913 100644 --- a/test/feature/Process-feature.js +++ b/test/feature/Process-feature.js @@ -328,9 +328,10 @@ Feature('Process', () => { start2.signal(); }); - Then('the process completes', () => { - expect(bp.isRunning).to.be.false; - return completed; + // Both user tasks have no incoming flow, so per BPMN 2.0 they are independent tokens that must + // both complete - neither is an alternative entry point to be discarded (that is start events). + Then('the process is still running', () => { + expect(bp.isRunning).to.be.true; }); And('second user task was taken', () => { @@ -338,9 +339,23 @@ Feature('Process', () => { expect(start2.owner.counters).to.have.property('discarded', 0); }); - And('first user task was discarded', () => { - expect(start1.owner.counters).to.have.property('discarded', 1); - expect(start1.owner.counters).to.have.property('taken', 0); + When('first user task is signaled', () => { + start1.signal(); + }); + + Then('the process completes', () => { + expect(bp.isRunning).to.be.false; + return completed; + }); + + And('first user task was taken', () => { + expect(start1.owner.counters).to.have.property('taken', 1); + expect(start1.owner.counters).to.have.property('discarded', 0); + }); + + And('end event was taken twice', () => { + expect(bp.getActivityById('end').counters).to.have.property('taken', 2); + expect(bp.getActivityById('end').counters).to.have.property('discarded', 0); }); Given('a process with two user tasks both arriving at a join', async () => { diff --git a/test/feature/multiple-startevent-feature.js b/test/feature/multiple-startevent-feature.js index e6a5b8e2..82c80cd4 100644 --- a/test/feature/multiple-startevent-feature.js +++ b/test/feature/multiple-startevent-feature.js @@ -145,7 +145,9 @@ Feature('Multiple start events', () => { }); }); + let leave; When('process is ran', () => { + leave = definition.waitFor('leave'); definition.run(); }); @@ -153,56 +155,35 @@ Feature('Multiple start events', () => { definition.signal(); }); - Then('parallel join is pending', () => { - const join = definition.getActivityById('join'); - expect(join.counters).to.deep.equal({ taken: 0, discarded: 0 }); - }); - - When('second start event is signaled', () => { - definition.signal({ id: 'Message_1' }); - }); - - Then('process is completed', () => { - expect(definition.counters).to.deep.equal({ - completed: 1, - discarded: 0, - }); + Then('the second start event is discarded as an alternative entry point', () => { + expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); }); - Then('first end event is not taken', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 0 }); + And('the parallel join fires once with the single token', () => { + expect(definition.getActivityById('join').counters).to.include({ taken: 1 }); }); - And('second end event is taken', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 0 }); + And('the default end event is taken and the process is completed', async () => { + await leave; + expect(definition.getActivityById('end').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('named-end').counters).to.include({ taken: 0 }); + expect(definition.counters).to.include({ completed: 1 }); }); - When('process is ran again', () => { + When('process is ran again and the second start event is signaled first', () => { + leave = definition.waitFor('leave'); definition.run(); - }); - - And('start events are signaled', () => { - definition.signal(); definition.signal({ id: 'Message_1' }); }); - Then('first end event is not taken', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 0 }); - }); - - And('second end event is taken', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 2, discarded: 0 }); + Then('the first start event is now discarded as the alternative', () => { + expect(definition.getActivityById('start1').counters).to.include({ discarded: 1 }); }); - And('process is completed', () => { - expect(definition.counters).to.deep.equal({ - completed: 2, - discarded: 0, - }); + And('the named end event is taken and the process is completed', async () => { + await leave; + expect(definition.getActivityById('named-end').counters).to.include({ taken: 1 }); + expect(definition.counters).to.include({ completed: 2 }); }); }); @@ -253,57 +234,315 @@ Feature('Multiple start events', () => { definition.run(); }); - And('both start events are signaled', () => { + And('the first start event is signaled', () => { definition.signal(); - definition.signal({ id: 'Signal2' }); - }); - - Then('process is completed', async () => { - await leave; - expect(definition.counters).to.deep.equal({ - completed: 1, - discarded: 0, - }); }); - And('joining task was taken twice', () => { - const task = definition.getActivityById('task'); - expect(task.counters).to.deep.equal({ taken: 2, discarded: 0 }); + Then('the second start event is discarded as an alternative entry point', () => { + expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); }); - And('fork was aggregated to a single firing via peer monitoring', () => { - const fork = definition.getActivityById('fork'); - expect(fork.counters).to.deep.equal({ taken: 1, discarded: 0 }); + And('the joining task was taken once', () => { + expect(definition.getActivityById('task').counters).to.include({ taken: 1 }); }); - And('both end events were taken once', () => { - expect(definition.getActivityById('end1').counters).to.deep.equal({ taken: 1, discarded: 0 }); - expect(definition.getActivityById('end2').counters).to.deep.equal({ taken: 1, discarded: 0 }); + And('the fork fired once and both end events were taken once, completing the process', async () => { + await leave; + expect(definition.getActivityById('fork').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('end1').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('end2').counters).to.include({ taken: 1 }); + expect(definition.counters).to.include({ completed: 1 }); }); - When('process is ran again', () => { + When('process is ran again and the second start event is signaled', () => { leave = definition.waitFor('leave'); definition.run(); - }); - - And('both start events are signaled in the reverse order', () => { definition.signal({ id: 'Signal2' }); - definition.signal(); }); - Then('process is completed', async () => { - await leave; - expect(definition.counters).to.deep.equal({ - completed: 2, - discarded: 0, - }); + Then('the first start event is now discarded as the alternative', () => { + expect(definition.getActivityById('start1').counters).to.include({ discarded: 1 }); }); - And('fork was aggregated to a single firing per run', () => { - const fork = definition.getActivityById('fork'); - expect(fork.counters).to.deep.equal({ taken: 2, discarded: 0 }); + And('the process is completed and the task was taken once more', async () => { + await leave; + expect(definition.getActivityById('task').counters).to.include({ taken: 2 }); + expect(definition.getActivityById('fork').counters).to.include({ taken: 2 }); + expect(definition.counters).to.include({ completed: 2 }); }); }); }); }); + + const startAndReceiveSource = ` + + + + + + + + + + + + + + + + + + + + `; + + Scenario('Two signal start events combined with a starting receive task', () => { + const source = startAndReceiveSource; + + let definition; + Given('a process with two signal start events and a starting receive task', async () => { + const context = await testHelpers.context(source); + definition = new Definition(context); + }); + + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('both start events and the receive task are armed', () => { + expect(definition.getPostponed().map(({ id }) => id)).to.have.members(['start1', 'start2', 'receive']); + }); + + When('the first start event is signaled', () => { + definition.signal({ id: 'Signal1' }); + }); + + Then('the first start event ran to its end event', () => { + expect(definition.getActivityById('start1').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('end1').counters).to.include({ taken: 1 }); + }); + + And('the second start event was discarded as an alternative entry point', () => { + expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); + }); + + But('the receive task is left armed, since it is a real token that must be signaled', () => { + expect(definition.getActivityById('receive').counters).to.include({ taken: 0, discarded: 0 }); + expect(definition.getPostponed().map(({ id }) => id)).to.deep.equal(['receive']); + }); + + And('the process is still running', () => { + expect(definition.isRunning).to.be.true; + }); + + When('the receive task is signaled with its message', () => { + definition.sendMessage({ id: 'Message1' }); + }); + + Then('the receive task ran to its end event', () => { + expect(definition.getActivityById('receive').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('end3').counters).to.include({ taken: 1 }); + }); + + And('the process completed', async () => { + await leave; + expect(definition.counters).to.include({ completed: 1 }); + }); + }); + + Scenario('Stop and resume while all start events are armed', () => { + let definition; + Given('a process with two signal start events and a starting receive task', async () => { + const context = await testHelpers.context(startAndReceiveSource); + definition = new Definition(context); + }); + + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('both start events and the receive task are armed', () => { + expect(definition.getPostponed().map(({ id }) => id)).to.have.members(['start1', 'start2', 'receive']); + }); + + When('process is stopped', () => { + definition.stop(); + }); + + Then('it is stopped with all entry points still armed', () => { + expect(definition.stopped).to.be.true; + expect(definition.getPostponed().map(({ id }) => id)).to.have.members(['start1', 'start2', 'receive']); + }); + + When('process is resumed', () => { + leave = definition.waitFor('leave'); + definition.resume(); + }); + + Then('all entry points are armed again', () => { + expect(definition.isRunning).to.be.true; + expect(definition.getPostponed().map(({ id }) => id)).to.have.members(['start1', 'start2', 'receive']); + }); + + When('the first start event is signaled after resume', () => { + definition.signal({ id: 'Signal1' }); + }); + + Then('the second start event is still discarded as an alternative entry point', () => { + expect(definition.getActivityById('start1').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); + }); + + And('the receive task is left armed', () => { + expect(definition.getPostponed().map(({ id }) => id)).to.deep.equal(['receive']); + }); + + When('the receive task is signaled with its message', () => { + definition.sendMessage({ id: 'Message1' }); + }); + + Then('the process completed', async () => { + await leave; + expect(definition.counters).to.include({ completed: 1 }); + }); + }); + + Scenario('Get state, recover, and resume while all start events are armed', () => { + let definition; + Given('a process with two signal start events and a starting receive task', async () => { + const context = await testHelpers.context(startAndReceiveSource); + definition = new Definition(context); + }); + + When('process is ran', () => { + definition.run(); + }); + + Then('both start events and the receive task are armed', () => { + expect(definition.getPostponed().map(({ id }) => id)).to.have.members(['start1', 'start2', 'receive']); + }); + + let state; + When('process is stopped and state is saved', () => { + definition.stop(); + state = definition.getState(); + }); + + let recovered, leave; + Given('the state is recovered into a new definition and resumed', async () => { + const context = await testHelpers.context(startAndReceiveSource); + recovered = new Definition(context).recover(JSON.parse(JSON.stringify(state))); + leave = recovered.waitFor('leave'); + recovered.resume(); + }); + + Then('all entry points are armed in the recovered definition', () => { + expect(recovered.isRunning).to.be.true; + expect(recovered.getPostponed().map(({ id }) => id)).to.have.members(['start1', 'start2', 'receive']); + }); + + When('the second start event is signaled in the recovered definition', () => { + recovered.signal({ id: 'Signal2' }); + }); + + Then('the first start event is discarded as an alternative entry point', () => { + expect(recovered.getActivityById('start2').counters).to.include({ taken: 1 }); + expect(recovered.getActivityById('start1').counters).to.include({ taken: 0, discarded: 1 }); + }); + + And('the receive task is left armed', () => { + expect(recovered.getPostponed().map(({ id }) => id)).to.deep.equal(['receive']); + }); + + When('the receive task is signaled with its message', () => { + recovered.sendMessage({ id: 'Message1' }); + }); + + Then('the recovered process completed', async () => { + await leave; + expect(recovered.counters).to.include({ completed: 1 }); + }); + }); + + Scenario('A timer start event combined with a signal start event', () => { + const source = ` + + + + + PT1H + + + + + + + + + + + + `; + + let definition; + Given('a process with a timer start event and a signal start event', async () => { + const context = await testHelpers.context(source); + definition = new Definition(context); + }); + + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('both start events are armed', () => { + expect(definition.getPostponed().map(({ id }) => id)).to.have.members(['timerStart', 'signalStart']); + expect(definition.environment.timers.executing).to.have.length(1); + }); + + When('the timer start event is cancelled', () => { + definition.cancelActivity({ id: 'timerStart' }); + }); + + Then('the timer start event completes', () => { + expect(definition.getActivityById('timerStart').counters).to.include({ taken: 1, discarded: 0 }); + expect(definition.getActivityById('timerEnd').counters).to.include({ taken: 1 }); + }); + + And('the signal start event is discarded as an alternative entry point', () => { + expect(definition.getActivityById('signalStart').counters).to.include({ taken: 0, discarded: 1 }); + }); + + And('the process completed with no timer left executing', async () => { + await leave; + expect(definition.counters).to.include({ completed: 1 }); + expect(definition.environment.timers.executing).to.have.length(0); + }); + + When('process is ran again and the signal start event is signaled', () => { + leave = definition.waitFor('leave'); + definition.run(); + definition.signal({ id: 'Signal1' }); + }); + + Then('the signal start event completes', () => { + expect(definition.getActivityById('signalStart').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('signalEnd').counters).to.include({ taken: 1 }); + }); + + And('the timer start event is discarded and its timer torn down', () => { + expect(definition.getActivityById('timerStart').counters).to.include({ discarded: 1 }); + expect(definition.environment.timers.executing).to.have.length(0); + }); + + And('the process completed again', async () => { + await leave; + expect(definition.counters).to.include({ completed: 2 }); + }); + }); }); diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index 96e51a11..e92fc197 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -30,9 +30,9 @@ Feature('Shaking', () => { When('definition is ran', () => { definition.broker.subscribeTmp( 'event', - 'activity.shake.end', - (_, msg) => { - messages.push(msg); + '*.shake.*', + (routingKey) => { + messages.push(routingKey); }, { noAck: true } ); @@ -40,32 +40,37 @@ Feature('Shaking', () => { definition.run(); }); - Then('the start events are shaken', () => { - expect(messages).to.have.length(2); + // Multiple start events no longer trigger a graph shake on run; they are torn down on + // completion directly. The shake remains available on demand. + Then('the start events are not shaken on run', () => { + expect(messages, messages.join()).to.have.length(0); + }); + + let start1, start2; + And('both start events are waiting for message', () => { + [start1, start2] = definition.getPostponed(); + expect(start1).to.have.property('id', 'start1'); + expect(start2).to.have.property('id', 'start2'); }); - And('execution sequence is presented in messages', () => { - expect(messages[0].content).to.have.property('sequence').that.is.an('array'); - const sequence1 = messages[0].content.sequence; + let result; + When('definition is shaken on demand', () => { + result = definition.shake(); + }); + + Then('execution sequence is presented for each start event', () => { + const sequence1 = result.start1[0].sequence; expect(sequence1[0]).to.have.property('id', 'start1'); expect(sequence1[1]).to.have.property('id', 'from12end'); expect(sequence1[2]).to.have.property('id', 'end'); expect(sequence1).to.have.length(3); - expect(messages[1].content).to.have.property('sequence').that.is.an('array'); - const sequence2 = messages[1].content.sequence; + const sequence2 = result.start2[0].sequence; expect(sequence2[0]).to.have.property('id', 'start2'); expect(sequence2[1]).to.have.property('id', 'from22end'); expect(sequence2[2]).to.have.property('id', 'end'); expect(sequence2).to.have.length(3); }); - - let start1, start2; - And('both start events are waiting for message', () => { - [start1, start2] = definition.getPostponed(); - expect(start1).to.have.property('id', 'start1'); - expect(start2).to.have.property('id', 'start2'); - }); }); Scenario('a process with a loopback flow', () => { @@ -103,18 +108,9 @@ Feature('Shaking', () => { When('definition is ran', () => { definition.broker.subscribeTmp( 'event', - 'activity.shake.end', - (_, msg) => { - messages.push(msg); - }, - { noAck: true } - ); - - definition.broker.subscribeTmp( - 'event', - 'flow.shake.loop', - (_, msg) => { - messages.push(msg); + '*.shake.*', + (routingKey) => { + messages.push(routingKey); }, { noAck: true } ); @@ -122,21 +118,26 @@ Feature('Shaking', () => { definition.run(); }); - Then('execution sequence is presented in first start event shake end message', () => { - expect(messages).to.have.length(3); - expect(messages[0].content).to.have.property('sequence').that.is.an('array'); - const sequence = messages[0].content.sequence; + Then('the start events are not shaken on run', () => { + expect(messages, messages.join()).to.have.length(0); + }); + + let result; + When('definition is shaken on demand', () => { + result = definition.shake(); + }); + + Then('execution sequence is presented for the first start event', () => { + const sequence = result.start1[0].sequence; expect(sequence[0]).to.have.property('id', 'start1'); expect(sequence[1]).to.have.property('id', 'from12end'); expect(sequence[2]).to.have.property('id', 'end'); expect(sequence).to.have.length(3); }); - And('execution sequence is presented in second start event shake end message', () => { - expect(messages).to.have.length(3); - - expect(messages[1].content).to.have.property('sequence').that.is.an('array'); - const sequence = messages[1].content.sequence; + And('execution sequence is presented for the second start event', () => { + expect(result.start2[0]).to.have.property('isLooped', false); + const sequence = result.start2[0].sequence; expect(sequence[0]).to.have.property('id', 'start2'); expect(sequence[1]).to.have.property('id', 'from22Task'); expect(sequence[2]).to.have.property('id', 'task'); @@ -147,9 +148,9 @@ Feature('Shaking', () => { expect(sequence).to.have.length(7); }); - And('second start event loop sequence is presented in shake loop message', () => { - expect(messages[2].content).to.have.property('sequence').that.is.an('array'); - const sequence = messages[2].content.sequence; + And('second start event loop sequence is presented', () => { + expect(result.start2[1]).to.have.property('isLooped', true); + const sequence = result.start2[1].sequence; expect(sequence).to.have.length(7); expect(sequence[0]).to.have.property('id', 'start2'); diff --git a/test/feature/signal-feature.js b/test/feature/signal-feature.js index dfb3de38..10f5d8b4 100644 --- a/test/feature/signal-feature.js +++ b/test/feature/signal-feature.js @@ -409,12 +409,10 @@ Feature('Signals', () => { }); }); - Scenario('Process with end throwing signal and a start event waiting for signal', () => { + Scenario('A none start event discards a waiting signal start event at instantiation', () => { let definition; - Given( - 'a process with two flows with user input, the first flow ends with signal, the second expects signal and then user input', - async () => { - const source = ` + Given('a process with two flows, the first started by a none start event, the second by a signal start event', async () => { + const source = ` @@ -433,23 +431,21 @@ Feature('Signals', () => { `; - const context = await testHelpers.context(source); - definition = new Definition(context); - } - ); + const context = await testHelpers.context(source); + definition = new Definition(context); + }); When('definition is ran', () => { definition.run(); }); - let task1, start2; - Then('first user task is waiting for input and second start event waits for signal', () => { + let task1; + Then('the none start event fired and discarded the waiting signal start event', () => { const postponed = definition.getPostponed(); - expect(postponed).to.have.length(2); - [task1, start2] = postponed; - expect(task1).to.be.ok; + expect(postponed).to.have.length(1); + [task1] = postponed; expect(task1).to.have.property('id', 'task1'); - expect(start2).to.have.property('id', 'start2'); + expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); }); When('first user task receives input', () => { @@ -460,24 +456,11 @@ Feature('Signals', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); }); - And('second flow is continued', () => { - expect(start2.owner.counters).to.have.property('taken', 1); + But('the second flow never ran, since its start event was discarded at instantiation', () => { + expect(definition.getActivityById('task2').counters).to.include({ taken: 0 }); }); - let task2; - And('second user task is awaiting input', () => { - const postponed = definition.getPostponed(); - expect(postponed).to.have.length(1); - [task2] = postponed; - expect(task2).to.be.ok; - expect(task2).to.have.property('id', 'task2'); - }); - - When('second user task receives input', () => { - task2.signal(); - }); - - Then('run completes', () => { + And('run completes', () => { expect(definition.counters).to.have.property('completed', 1); }); }); diff --git a/types/index.d.ts b/types/index.d.ts index 6286cc28..f5fbf75e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -676,6 +676,8 @@ declare module 'bpmn-elements' { get isCatching(): boolean; get isForCompensation(): boolean; get isParallelJoin(): boolean; + get isParallelGateway(): boolean; + get isStartEvent(): boolean; get triggeredByEvent(): boolean; get attachedTo(): Activity | null; get lane(): Lane | undefined; @@ -1654,8 +1656,7 @@ declare module 'bpmn-elements' { */ execute(executeMessage: ElementBrokerMessage): true | void; /** - * Resume after recover. Reshakes elements when there are converging gateways or multiple - * start activities, then resumes any postponed children. + * Resume after recover, resuming any postponed children. */ resume(): void; /** diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index a44fb537..79679e89 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -39,6 +39,8 @@ declare module '../src/activity/Activity.js' { get isCatching(): boolean; get isForCompensation(): boolean; get isParallelJoin(): boolean; + get isParallelGateway(): boolean; + get isStartEvent(): boolean; get triggeredByEvent(): boolean; get attachedTo(): Activity | null; get lane(): Lane | undefined; From 0ab64cb50fe3cf7833c45eb8ba15e793a8657b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Thu, 11 Jun 2026 07:18:14 +0200 Subject: [PATCH 26/31] remove intermediate skipDiscard flag --- CHANGELOG.md | 14 +- dist/Environment.js | 1 - dist/activity/Activity.js | 30 +- docs/Environment.md | 1 - docs/SequenceFlow.md | 4 +- src/Environment.js | 2 +- src/activity/Activity.js | 26 +- test/Environment-test.js | 16 +- test/feature/BoundaryEvent-feature.js | 10 +- test/feature/Process-feature.js | 91 +- test/feature/environment-feature.js | 8 +- test/feature/gateway-feature.js | 82 +- .../issues/exclusive-gateway-join-feature.js | 70 +- test/feature/issues/issue-39-feature.js | 6 +- test/feature/issues/issue-42-feature.js | 54 +- test/feature/issues/issues-feature.js | 88 +- test/feature/linking-feature.js | 1187 ++++++++--------- test/feature/messaging-feature.js | 12 +- test/feature/multiple-startevent-feature.js | 510 ++++--- test/feature/outbound-flows-feature.js | 24 +- test/feature/performance-feature.js | 181 ++- test/feature/shake-feature.js | 39 - test/feature/skip-discard-feature.js | 10 +- test/feature/sub-process-feature.js | 9 +- test/flows/SequenceFlow-test.js | 8 +- test/gateways/EventBasedGateway-test.js | 6 +- test/gateways/ParallelGateway-test.js | 16 +- test/tasks/ServiceTask-test.js | 8 +- test/tasks/SubProcess-test.js | 4 +- types/index.d.ts | 5 - types/interfaces.d.ts | 5 - 31 files changed, 1166 insertions(+), 1361 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd00ce3c..4aa67043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,19 @@ # Changelog -## v18.0.0 - 2026-05-31 +## v18.0.0 - 2026-06-11 -Refactor parallel converging and forking gateways, and treat multiple start events as mutually exclusive entry points. +Refactor parallel converging and forking gateways, and treat multiple start events as mutually exclusive entry points. As a result of the parallel gateway keeping track of peers there is no need for discarding a sequence flows. ### Breaking +- `Definition` must be called with `new` - parallel gateways now enter execution as soon as the first inbound sequence flow is touched -- shake sequence has changed +- removed discarding of outbound sequence flows altogether — activities no longer publish flow discards, so sequence flow and downstream activity `discarded` counters stay at `0` - IntermediateCatchEvent cannot be used as a starting element, or it can but will not be started by default -- `Definition` must be called with `new` -- non-gateway activities discard their outbound when all conditional flows are falsy instead of throwing; only exclusive and inclusive gateways still require a taken or default flow +- non-gateway activities end the branch when all conditional outbound flows are falsy instead of throwing; only exclusive and inclusive gateways still require a taken or default flow - multiple start events are mutually exclusive entry points — the first start event to fire discards the others still waiting to be triggered, so two start events can no longer both run (e.g. into a parallel join, or a joining task taken twice) - start activities that are not start events (e.g. a starting receive task, or an activity without an inbound flow) are no longer auto-discarded; they are genuine tokens that must be signalled or completed -- multiple start events no longer trigger a graph shake on run/resume; only converging parallel gateways do, and the shake remains available on demand via `shake()` +- shake sequence has changed ### Additions @@ -28,7 +28,7 @@ Refactor parallel converging and forking gateways, and treat multiple start even ### Types -- runtime types are now generated from JSDoc and bundled with [dts-buddy](https://github.com/Rich-Harris/dts-buddy); status enums (`ActivityStatus`, `DefinitionStatus`, `ProcessStatus`) and `TimerType` accept both enum members and their string literals. +- runtime types are now generated from JSDoc and bundled with [dts-buddy](https://github.com/Rich-Harris/dts-buddy) - expose `isStartEvent` and `isParallelGateway` on the `Activity` interface ## v17.3.0 - 2025-12-03 diff --git a/dist/Environment.js b/dist/Environment.js index a681a299..6e42a4a7 100644 --- a/dist/Environment.js +++ b/dist/Environment.js @@ -29,7 +29,6 @@ function Environment(options = {}) { this.timers = options.timers || new _Timers.Timers(); /** @type {import('#types').EnvironmentSettings} */ this.settings = { - skipDiscard: true, ...options.settings }; /** @type {import('#types').LoggerFactory} */ diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 1d782eef..f9069d54 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -793,7 +793,6 @@ Activity.prototype._pauseRunQ = function pauseRunQ() { Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, messageProperties) { switch (routingKey) { case 'run.execute.passthrough': - case 'run.outbound.discard': case 'run.outbound.take': case 'run.next': return this._continueRunMessage(routingKey, message, messageProperties); @@ -932,12 +931,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, message.ack(); return flow.take(content.flow); } - case 'run.outbound.discard': - { - const flow = this._getOutboundSequenceFlowById(content.flow.id); - message.ack(); - return flow.discard(content.flow); - } case 'run.leave': { this.status = undefined; @@ -1065,10 +1058,6 @@ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, c const outboundSequenceFlows = this[K_FLOWS].outboundSequenceFlows; if (!outboundSequenceFlows.length) return callback(null, []); const fromContent = fromMessage.content; - let discardSequence = fromContent.discardSequence; - if (isDiscarded && !discardSequence && this[K_FLAGS].attachedTo && fromContent.inbound?.[0]) { - discardSequence = [fromContent.inbound[0].id]; - } let outboundFlows; if (isDiscarded) { outboundFlows = outboundSequenceFlows.map(flow => (0, _outboundEvaluator.formatFlowAction)(flow, { @@ -1078,20 +1067,20 @@ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, c outboundFlows = outboundSequenceFlows.map(flow => (0, _outboundEvaluator.formatFlowAction)(flow, fromContent.outbound.filter(f => f.id === flow.id).pop())); } if (outboundFlows) { - this._doRunOutbound(outboundFlows, fromContent, discardSequence); + this._doRunOutbound(outboundFlows, fromContent); return callback(null, outboundFlows); } return this.evaluateOutbound(fromMessage, fromContent.outboundTakeOne, (err, evaluatedOutbound) => { if (err) return callback(new _Errors.ActivityError(err.message, fromMessage, err)); - const outbound = this._doRunOutbound(evaluatedOutbound, fromContent, discardSequence); + const outbound = this._doRunOutbound(evaluatedOutbound, fromContent); return callback(null, outbound); }); }; /** @internal */ -Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) { +Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content) { if (outboundList.length === 1) { - this._publishRunOutbound(outboundList[0], content, discardSequence); + this._publishRunOutbound(outboundList[0], content); } else { const targets = new Map(); for (const outboundFlow of outboundList) { @@ -1103,30 +1092,27 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content } } for (const outboundFlow of targets.values()) { - this._publishRunOutbound(outboundFlow, content, discardSequence); + this._publishRunOutbound(outboundFlow, content); } } return outboundList; }; /** @internal */ -Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content, discardSequence) { +Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content) { const { id: flowId, action, result } = outboundFlow; - if (action === 'discard' && this.environment.settings.skipDiscard) { + if (action === 'discard') { return; } this.broker.publish('run', 'run.outbound.' + action, (0, _messageHelper.cloneContent)(content, { flow: { ...(result && typeof result === 'object' && result), ...outboundFlow, - sequenceId: (0, _shared.getUniqueId)(`${flowId}_${action}`), - ...(discardSequence && { - discardSequence: discardSequence.slice() - }) + sequenceId: (0, _shared.getUniqueId)(`${flowId}_${action}`) } })); }; diff --git a/docs/Environment.md b/docs/Environment.md index fe708403..2630bd40 100644 --- a/docs/Environment.md +++ b/docs/Environment.md @@ -16,7 +16,6 @@ Arguments: - `strict`: boolean, [strict mode](#strict-mode) defaults to false - `batchSize`: optional positive integer to control parallel loop batch size, defaults to 50 - `disableTrackState`: optional boolean to disable tracking of element counters between recover and resume. State of idle elements are not returned when getting state. Recommended if running and recovering really large flows - - `skipDiscard`: boolean, when true the runtime omits unnecessary discard messages for flows that no converging join is waiting on, defaults to true. Set to false for behaviour parity with older versions that always published discards - `scripts`: [Scripts instance](/docs/Scripts.md) - `timers`: [Timers instance](/docs/Timers.md) - `expressions`: expressions handler, defaults to [Expressions instance](/docs/Expression.md) diff --git a/docs/SequenceFlow.md b/docs/SequenceFlow.md index dc07b47b..6984ee30 100644 --- a/docs/SequenceFlow.md +++ b/docs/SequenceFlow.md @@ -66,6 +66,6 @@ An expression condition can resolve to a service function instead of a plain val If every conditional outbound flow evaluates to falsy, the behaviour depends on the element: - a diverging **exclusive or inclusive gateway** takes its `default` flow when declared, otherwise it raises an ` no conditional flow taken` error — these gateways require exactly one (exclusive) or at least one (inclusive) outbound to be taken; -- any **other activity** (task, event, …) simply discards its outbound — the branch ends, no error is raised. +- any **other activity** (task, event, …) simply ends the branch, no error is raised. -> With the default `skipDiscard` setting the discards are not published, so the outbound flow `discard` counters stay at `0`. Set `skipDiscard` to `false` to observe the discards. +> The runtime no longer publishes outbound flow discards, so outbound flow `discard` counters stay at `0`. diff --git a/src/Environment.js b/src/Environment.js index cdb4553a..7f6a322a 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -24,7 +24,7 @@ export function Environment(options = {}) { /** @type {import('#types').ITimers} */ this.timers = options.timers || new Timers(); /** @type {import('#types').EnvironmentSettings} */ - this.settings = { skipDiscard: true, ...options.settings }; + this.settings = { ...options.settings }; /** @type {import('#types').LoggerFactory} */ this.Logger = options.Logger || DummyLogger; this[K_SERVICES] = options.services || {}; diff --git a/src/activity/Activity.js b/src/activity/Activity.js index f2f702cb..5f0f9ac8 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -744,7 +744,6 @@ Activity.prototype._pauseRunQ = function pauseRunQ() { Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, messageProperties) { switch (routingKey) { case 'run.execute.passthrough': - case 'run.outbound.discard': case 'run.outbound.take': case 'run.next': return this._continueRunMessage(routingKey, message, messageProperties); @@ -881,11 +880,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, message.ack(); return flow.take(content.flow); } - case 'run.outbound.discard': { - const flow = this._getOutboundSequenceFlowById(content.flow.id); - message.ack(); - return flow.discard(content.flow); - } case 'run.leave': { this.status = undefined; @@ -994,11 +988,6 @@ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, c const fromContent = fromMessage.content; - let discardSequence = fromContent.discardSequence; - if (isDiscarded && !discardSequence && this[K_FLAGS].attachedTo && fromContent.inbound?.[0]) { - discardSequence = [fromContent.inbound[0].id]; - } - let outboundFlows; if (isDiscarded) { outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, { action: 'discard' })); @@ -1007,21 +996,21 @@ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, c } if (outboundFlows) { - this._doRunOutbound(outboundFlows, fromContent, discardSequence); + this._doRunOutbound(outboundFlows, fromContent); return callback(null, outboundFlows); } return this.evaluateOutbound(fromMessage, fromContent.outboundTakeOne, (err, evaluatedOutbound) => { if (err) return callback(new ActivityError(err.message, fromMessage, err)); - const outbound = this._doRunOutbound(evaluatedOutbound, fromContent, discardSequence); + const outbound = this._doRunOutbound(evaluatedOutbound, fromContent); return callback(null, outbound); }); }; /** @internal */ -Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) { +Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content) { if (outboundList.length === 1) { - this._publishRunOutbound(outboundList[0], content, discardSequence); + this._publishRunOutbound(outboundList[0], content); } else { const targets = new Map(); @@ -1035,7 +1024,7 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content } for (const outboundFlow of targets.values()) { - this._publishRunOutbound(outboundFlow, content, discardSequence); + this._publishRunOutbound(outboundFlow, content); } } @@ -1043,10 +1032,10 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content }; /** @internal */ -Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content, discardSequence) { +Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content) { const { id: flowId, action, result } = outboundFlow; - if (action === 'discard' && this.environment.settings.skipDiscard) { + if (action === 'discard') { return; } @@ -1058,7 +1047,6 @@ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlo ...(result && typeof result === 'object' && result), ...outboundFlow, sequenceId: getUniqueId(`${flowId}_${action}`), - ...(discardSequence && { discardSequence: discardSequence.slice() }), }, }) ); diff --git a/test/Environment-test.js b/test/Environment-test.js index 37b1bcae..b1b9fcd0 100644 --- a/test/Environment-test.js +++ b/test/Environment-test.js @@ -2,8 +2,8 @@ import { Environment, Timers } from 'bpmn-elements'; describe('Environment', () => { describe('ctor', () => { - it('sets settings with skipDiscard default', () => { - expect(new Environment()).to.have.property('settings').that.deep.equal({ skipDiscard: true }); + it('defaults settings to an empty object', () => { + expect(new Environment()).to.have.property('settings').that.deep.equal({}); expect( new Environment({ settings: { @@ -13,12 +13,11 @@ describe('Environment', () => { ) .to.have.property('settings') .that.eql({ - skipDiscard: true, test: 1, }); }); - it('shallow clones settings while preserving skipDiscard default', () => { + it('shallow clones settings', () => { const settings = { test: 1, }; @@ -28,7 +27,6 @@ describe('Environment', () => { settings.test = 2; expect(environment).to.have.property('settings').that.eql({ - skipDiscard: true, test: 1, }); }); @@ -268,13 +266,13 @@ describe('Environment', () => { it('ignored if non-object is passed', () => { const environment = new Environment({ settings: { before: true } }); environment.assignSettings(); - expect(environment.settings).to.eql({ skipDiscard: true, before: true }); + expect(environment.settings).to.eql({ before: true }); environment.assignSettings(null); - expect(environment.settings).to.eql({ skipDiscard: true, before: true }); + expect(environment.settings).to.eql({ before: true }); environment.assignSettings('null'); - expect(environment.settings).to.eql({ skipDiscard: true, before: true }); + expect(environment.settings).to.eql({ before: true }); environment.assignSettings(1); - expect(environment.settings).to.eql({ skipDiscard: true, before: true }); + expect(environment.settings).to.eql({ before: true }); }); }); diff --git a/test/feature/BoundaryEvent-feature.js b/test/feature/BoundaryEvent-feature.js index dee59b51..0efa296d 100644 --- a/test/feature/BoundaryEvent-feature.js +++ b/test/feature/BoundaryEvent-feature.js @@ -280,8 +280,8 @@ Feature('BoundaryEvent', () => { expect(initTask.counters).to.have.property('taken', 2); }); - And('end was discarded', () => { - expect(bp.getActivityById('end').counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); + And('end was not discarded', () => { + expect(bp.getActivityById('end').counters).to.have.property('discarded', 0); expect(bp.getActivityById('end').counters).to.have.property('taken', 0); }); @@ -302,8 +302,8 @@ Feature('BoundaryEvent', () => { expect(bound.owner.counters).to.have.property('discarded', 1); }); - And('init task is discarded', () => { - expect(initTask.counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); + And('init task is not discarded', () => { + expect(initTask.counters).to.have.property('discarded', 0); expect(initTask.counters).to.have.property('taken', 2); }); @@ -314,7 +314,7 @@ Feature('BoundaryEvent', () => { And('end was taken', () => { expect(bp.getActivityById('end').counters).to.have.property('taken', 1); - expect(bp.getActivityById('end').counters).to.have.property('discarded', bp.environment.settings.skipDiscard ? 0 : 1); + expect(bp.getActivityById('end').counters).to.have.property('discarded', 0); }); And('process completes', () => { diff --git a/test/feature/Process-feature.js b/test/feature/Process-feature.js index cfdbb913..715311c7 100644 --- a/test/feature/Process-feature.js +++ b/test/feature/Process-feature.js @@ -240,7 +240,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -285,8 +285,6 @@ Feature('Process', () => { assertMessage('activity.enter', 'decision'); assertMessage('activity.start', 'decision'); assertMessage('activity.end', 'decision'); - assertMessage('activity.discard', 'end1'); - assertMessage('activity.leave', 'end1'); assertMessage('activity.enter', 'end2'); assertMessage('activity.start', 'end2'); assertMessage('activity.end', 'end2'); @@ -511,7 +509,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -682,7 +680,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -756,23 +754,10 @@ Feature('Process', () => { assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); - assertMessage('flow.discard', 'back-to-activity1'); - assertMessage('activity.leave', 'decision'); assertMessage('activity.leave', 'activity2'); assertMessage('activity.leave', 'activity1'); - assertMessage('activity.discard', 'activity1'); - - assertMessage('flow.discard', 'to-activity2'); - - assertMessage('activity.discard', 'activity2'); - - assertMessage('flow.looped', 'to-decision'); - - assertMessage('activity.leave', 'activity2'); - assertMessage('activity.leave', 'activity1'); - assertMessage('process.end'); assertMessage('process.leave'); @@ -987,7 +972,7 @@ Feature('Process', () => { const messages = []; let bp, assertMessage; Given('a process', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); bp = context.getProcessById('theProcess'); bp.environment.variables.condition1 = true; assertMessage = AssertMessage(context, messages, true); @@ -1277,7 +1262,7 @@ Feature('Process', () => { const messages = []; let bp, assertMessage, serviceComplete; Given('a process', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); bp = context.getProcessById('theProcess'); bp.environment.addService('get', get); assertMessage = AssertMessage(context, messages, false); @@ -1334,8 +1319,8 @@ Feature('Process', () => { assertMessage('activity.end', 'end1'); }); - And('boundary event flow is discarded', () => { - assertMessage('activity.discard', 'end2'); + And('boundary event is discarded without taking its flow', () => { + assertMessage('activity.leave', 'attached'); }); And('service task has left', () => { @@ -1379,8 +1364,8 @@ Feature('Process', () => { assertMessage('activity.catch', 'attached'); }); - And('the service flows is discarded', () => { - assertMessage('activity.discard', 'end1'); + And('the service task errors without taking its flow', () => { + assertMessage('activity.error', 'service'); }); And('the boundary event flow is taken', () => { @@ -1411,7 +1396,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage, serviceComplete; Given('a process', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); processInstance.environment.variables.timeout = 'PT1S'; processInstance.environment.addService('get', get); @@ -1472,9 +1457,7 @@ Feature('Process', () => { assertMessage('activity.leave', 'end1'); }); - And('boundary event flow is discarded', () => { - assertMessage('activity.discard', 'end2'); - assertMessage('activity.leave', 'end2'); + And('boundary event is discarded without taking its flow', () => { assertMessage('activity.leave', 'attached'); }); @@ -1519,12 +1502,7 @@ Feature('Process', () => { assertMessage('activity.timeout', 'attached'); }); - And('the service task flow was discarded', () => { - assertMessage('activity.discard', 'end1'); - assertMessage('activity.leave', 'end1'); - }); - - And('the service task was discarded', () => { + And('the service task is discarded without taking its flow', () => { assertMessage('activity.leave', 'service'); }); @@ -1562,7 +1540,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage, serviceComplete; Given('a process', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); processInstance.environment.variables.timeout = 'PT1S'; processInstance.environment.addService('get', get); @@ -1620,9 +1598,7 @@ Feature('Process', () => { assertMessage('activity.leave', 'end1'); }); - And('boundary event flow was discarded', () => { - assertMessage('activity.discard', 'end2'); - assertMessage('activity.leave', 'end2'); + And('boundary event is discarded without taking its flow', () => { assertMessage('activity.leave', 'attached'); }); @@ -1691,7 +1667,7 @@ Feature('Process', () => { const messages = []; let context, processInstance, assertMessage; Given('a process with a user task', async () => { - context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, false); }); @@ -1775,7 +1751,7 @@ Feature('Process', () => { const messages = []; let context, processInstance, assertMessage; Given('a process', async () => { - context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); processInstance.environment.variables.timeout = 'PT1S'; assertMessage = AssertMessage(context, messages, false); @@ -1855,9 +1831,8 @@ Feature('Process', () => { assertMessage('activity.leave', 'end1'); }); - And('boundary event flow were discarded', () => { - assertMessage('activity.discard', 'end2'); - assertMessage('activity.leave', 'end2'); + And('boundary event is discarded without taking its flow', () => { + assertMessage('activity.leave', 'attached'); assertMessage('activity.leave', 'userInput'); expect(messages.length, 'no more messages').to.equal(0); }); @@ -1892,7 +1867,7 @@ Feature('Process', () => { const messages = []; let processInstance, assertMessage; Given('a process with user task and timer', async () => { - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -2007,28 +1982,10 @@ Feature('Process', () => { assertMessage('activity.end', 'end'); assertMessage('activity.leave', 'end'); - assertMessage('flow.discard', 'back-to-activity0'); - - assertMessage('activity.discard', 'activity0'); - - assertMessage('flow.discard', 'to-activity1'); - - assertMessage('activity.leave', 'activity0'); - assertMessage('activity.leave', 'decision'); assertMessage('activity.leave', 'activity2'); assertMessage('activity.leave', 'activity1'); - assertMessage('activity.discard', 'activity1'); - - assertMessage('flow.discard', 'to-activity2'); - - assertMessage('activity.discard', 'activity2'); - assertMessage('flow.looped', 'to-decision'); - - assertMessage('activity.leave', 'activity2'); - assertMessage('activity.leave', 'activity1'); - assertMessage('process.end'); assertMessage('process.leave'); @@ -2148,7 +2105,7 @@ Feature('Process', () => { const messages = []; let context, processInstance, assertMessage; Given('a process with a task and bound timer event both leading to end event', async () => { - context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + context = await testHelpers.context(source); processInstance = context.getProcessById('theProcess'); assertMessage = AssertMessage(context, messages, true); }); @@ -2209,13 +2166,7 @@ Feature('Process', () => { assertMessage('activity.execution.discard', 'bound'); }); - And('bound flow is discarded', () => { - assertMessage('flow.discard', 'fromBoundaryEvent'); - }); - - And('end event is discarded', () => { - assertMessage('activity.discard', 'end'); - assertMessage('activity.leave', 'end'); + And('bound event leaves without taking its flow', () => { assertMessage('activity.leave', 'bound'); }); diff --git a/test/feature/environment-feature.js b/test/feature/environment-feature.js index 5c6fd614..1bb8eb54 100644 --- a/test/feature/environment-feature.js +++ b/test/feature/environment-feature.js @@ -53,7 +53,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(task.environment.settings).to.deep.equal({ strict: true, skipDiscard: true }); + expect(task.environment.settings).to.deep.equal({ strict: true }); }); And('differs from definition', () => { @@ -70,7 +70,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(runningBp.environment.settings).to.deep.equal({ strict: true, skipDiscard: true }); + expect(runningBp.environment.settings).to.deep.equal({ strict: true }); }); When('definition completes', () => { @@ -102,7 +102,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(runningBp.environment.settings).to.deep.equal({ strict: false, skipDiscard: true }); + expect(runningBp.environment.settings).to.deep.equal({ strict: false }); }); But('differs from definition', () => { @@ -120,7 +120,7 @@ Feature('Environment', () => { }); And('settings', () => { - expect(runningBp.environment.settings).to.deep.equal({ strict: false, skipDiscard: true }); + expect(runningBp.environment.settings).to.deep.equal({ strict: false }); }); When('definition completes', () => { diff --git a/test/feature/gateway-feature.js b/test/feature/gateway-feature.js index 90588f9a..dabf358e 100644 --- a/test/feature/gateway-feature.js +++ b/test/feature/gateway-feature.js @@ -36,7 +36,7 @@ Feature('Gateway', () => { `; - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); definition = new Definition(context); }); @@ -49,9 +49,9 @@ Feature('Gateway', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); }); - And('the other two discarded', () => { - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 1); + And('the other two are not discarded', () => { + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); When('definition is ran with truthy second condition script', () => { @@ -59,18 +59,18 @@ Feature('Gateway', () => { definition.run(); }); - Then('default flow is discarded', () => { + Then('default flow is not taken again and not discarded', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end1').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end1').counters).to.have.property('discarded', 0); }); And('the second flow is taken', () => { expect(definition.getActivityById('end2').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); }); - And('the third flow is discarded', () => { - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 2); + And('the third flow is not discarded', () => { + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); When('definition is ran with truthy second and third condition script', () => { @@ -79,19 +79,19 @@ Feature('Gateway', () => { definition.run(); }); - Then('default flow is discarded', () => { + Then('default flow is not taken and not discarded', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end1').counters).to.have.property('discarded', 2); + expect(definition.getActivityById('end1').counters).to.have.property('discarded', 0); }); And('the second flow is taken', () => { expect(definition.getActivityById('end2').counters).to.have.property('taken', 2); - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); }); And('the third flow is taken', () => { expect(definition.getActivityById('end3').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 2); + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); let error; @@ -132,7 +132,7 @@ Feature('Gateway', () => { `; - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); definition = new Definition(context); }); @@ -145,9 +145,9 @@ Feature('Gateway', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); }); - And('the other two discarded', () => { - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 1); + And('the other two are not discarded', () => { + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); When('definition is ran with truthy second condition script', () => { @@ -155,18 +155,18 @@ Feature('Gateway', () => { definition.run(); }); - Then('default flow is discarded', () => { + Then('default flow is not taken again and not discarded', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end1').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end1').counters).to.have.property('discarded', 0); }); And('the second flow is taken', () => { expect(definition.getActivityById('end2').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); }); - And('the third flow is discarded', () => { - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 2); + And('the third flow is not discarded', () => { + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); When('definition is ran with truthy second and third condition script', () => { @@ -175,19 +175,19 @@ Feature('Gateway', () => { definition.run(); }); - Then('default flow is discarded', () => { + Then('default flow is not taken and not discarded', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end1').counters).to.have.property('discarded', 2); + expect(definition.getActivityById('end1').counters).to.have.property('discarded', 0); }); And('the second flow is taken', () => { expect(definition.getActivityById('end2').counters).to.have.property('taken', 2); - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); }); - And('the third flow is still discarded', () => { + And('the third flow is still not taken and not discarded', () => { expect(definition.getActivityById('end3').counters).to.have.property('taken', 0); - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 3); + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); let error; @@ -386,7 +386,7 @@ Feature('Gateway', () => { `; - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); definition = new Definition(context); }); @@ -410,9 +410,9 @@ Feature('Gateway', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); }); - And('the other two discarded', () => { - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 1); + And('the other two are not discarded', () => { + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); When('definition is ran with truthy second condition script', () => { @@ -420,18 +420,18 @@ Feature('Gateway', () => { definition.run(); }); - Then('default flow is discarded', () => { + Then('default flow is not taken again and not discarded', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end1').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end1').counters).to.have.property('discarded', 0); }); And('the second flow is taken', () => { expect(definition.getActivityById('end2').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); }); - And('the third flow is discarded', () => { - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 2); + And('the third flow is not discarded', () => { + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); When('definition is ran with truthy second and third condition script', () => { @@ -440,19 +440,19 @@ Feature('Gateway', () => { definition.run(); }); - Then('default flow is discarded', () => { + Then('default flow is not taken and not discarded', () => { expect(definition.getActivityById('end1').counters).to.have.property('taken', 1); - expect(definition.getActivityById('end1').counters).to.have.property('discarded', 2); + expect(definition.getActivityById('end1').counters).to.have.property('discarded', 0); }); And('the second flow is taken', () => { expect(definition.getActivityById('end2').counters).to.have.property('taken', 2); - expect(definition.getActivityById('end2').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end2').counters).to.have.property('discarded', 0); }); - And('the third flow is still discarded', () => { + And('the third flow is still not taken and not discarded', () => { expect(definition.getActivityById('end3').counters).to.have.property('taken', 0); - expect(definition.getActivityById('end3').counters).to.have.property('discarded', 3); + expect(definition.getActivityById('end3').counters).to.have.property('discarded', 0); }); let error; diff --git a/test/feature/issues/exclusive-gateway-join-feature.js b/test/feature/issues/exclusive-gateway-join-feature.js index 00f6cd4c..2d68f3e5 100644 --- a/test/feature/issues/exclusive-gateway-join-feature.js +++ b/test/feature/issues/exclusive-gateway-join-feature.js @@ -6,43 +6,39 @@ import factory from '../../helpers/factory.js'; const source = factory.resource('exclusive-gateway-as-join.bpmn'); Feature('Exclusive gateway used for joining', () => { - [false, true].forEach((skipDiscard) => { - describe(`run ${skipDiscard ? 'with' : 'without'} skipDiscard setting`, () => { - Scenario('a number of exclusive gateway join and split', () => { - let context; - /** @type {Definition} */ - let definition; - let end; - When('running a definition matching the scenario', async () => { - context = await testHelpers.context(source); - - definition = new Definition(context, { settings: { skipDiscard } }); - end = definition.waitFor('leave'); - definition.run(); - }); - - Then('run completes', () => { - return end; - }); - - When('same instance is ran again', () => { - end = definition.waitFor('leave'); - definition.run(); - }); - - Then('second run completes', () => { - return end; - }); - - When('same instance is ran yet again', () => { - end = definition.waitFor('leave'); - definition.run(); - }); - - Then('third run completes', () => { - return end; - }); - }); + Scenario('a number of exclusive gateway join and split', () => { + let context; + /** @type {Definition} */ + let definition; + let end; + When('running a definition matching the scenario', async () => { + context = await testHelpers.context(source); + + definition = new Definition(context); + end = definition.waitFor('leave'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + When('same instance is ran again', () => { + end = definition.waitFor('leave'); + definition.run(); + }); + + Then('second run completes', () => { + return end; + }); + + When('same instance is ran yet again', () => { + end = definition.waitFor('leave'); + definition.run(); + }); + + Then('third run completes', () => { + return end; }); }); }); diff --git a/test/feature/issues/issue-39-feature.js b/test/feature/issues/issue-39-feature.js index 17b8670e..688551c3 100644 --- a/test/feature/issues/issue-39-feature.js +++ b/test/feature/issues/issue-39-feature.js @@ -73,14 +73,14 @@ Feature('Issue 39 - resolve SequenceFlow expression promise', () => { expect(definition.getActivityById('takenend').counters).to.deep.equal({ taken: 1, discarded: 0 }); }); - And('discarded default and the other one', () => { + And('neither took nor discarded default and the other one', () => { expect(definition.getActivityById('defaultend').counters, 'default').to.deep.equal({ taken: 0, - discarded: definition.environment.settings.skipDiscard ? 0 : 1, + discarded: 0, }); expect(definition.getActivityById('theotherone').counters, 'the other one').to.deep.equal({ taken: 0, - discarded: definition.environment.settings.skipDiscard ? 0 : 1, + discarded: 0, }); }); }); diff --git a/test/feature/issues/issue-42-feature.js b/test/feature/issues/issue-42-feature.js index fbb5e47e..fd58f340 100644 --- a/test/feature/issues/issue-42-feature.js +++ b/test/feature/issues/issue-42-feature.js @@ -117,34 +117,32 @@ Feature('Issue 42 - discard loops due to multiple outbound flows to same target' ['synchronous', (scope, next) => next()], ['asynchronous', (scope, next) => process.nextTick(next)], ].forEach(([kind, serviceTask]) => { - [true, false].forEach((skipDiscard) => { - Scenario(`every task completes with a ${kind} service task implementation and skipDiscard ${skipDiscard}`, () => { - Given('a definition where conditional flows resolve to the takeOnce service function', async () => { - context = await testHelpers.context(originalSource); - definition = new Definition(context, { settings: { skipDiscard }, services: { takeOnce, serviceTask } }); - }); - - let left; - When('definition is ran', () => { - left = definition.waitFor('leave'); - definition.run(); - }); - - Then('it completes without error', () => { - return left; - }); - - And('all twenty service tasks completed at least once', () => { - for (let n = 1; n <= 20; n++) { - expect(definition.getActivityById(`task${n}`).counters, `task${n}`) - .to.have.property('taken') - .above(0); - } - }); - - And('the end event was reached', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); - }); + Scenario(`every task completes with a ${kind} service task implementation`, () => { + Given('a definition where conditional flows resolve to the takeOnce service function', async () => { + context = await testHelpers.context(originalSource); + definition = new Definition(context, { services: { takeOnce, serviceTask } }); + }); + + let left; + When('definition is ran', () => { + left = definition.waitFor('leave'); + definition.run(); + }); + + Then('it completes without error', () => { + return left; + }); + + And('all twenty service tasks completed at least once', () => { + for (let n = 1; n <= 20; n++) { + expect(definition.getActivityById(`task${n}`).counters, `task${n}`) + .to.have.property('taken') + .above(0); + } + }); + + And('the end event was reached', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); }); }); }); diff --git a/test/feature/issues/issues-feature.js b/test/feature/issues/issues-feature.js index 7557f6f7..125ef40c 100644 --- a/test/feature/issues/issues-feature.js +++ b/test/feature/issues/issues-feature.js @@ -55,32 +55,32 @@ Feature('Issues', () => { return leave; }); - And('first user task is taken once and discarded twice', () => { + And('first user task is taken once and discarded once', () => { expect(task1.counters).to.have.property('taken', 1); - expect(task1.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 1 : 2); + expect(task1.counters).to.have.property('discarded', 1); }); - And('second user task is taken once and discarded twice', () => { + And('second user task is taken once and not discarded', () => { expect(task2.counters).to.have.property('taken', 1); - expect(task2.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); + expect(task2.counters).to.have.property('discarded', 0); }); - And('first decision is taken once and discarded once since discard loop prevents more', () => { + And('first decision is taken once and not discarded', () => { const decision = definition.getActivityById('decision1'); expect(decision.counters).to.have.property('taken', 1); - expect(decision.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); + expect(decision.counters).to.have.property('discarded', 0); }); - And('second decision is discarded twice', () => { + And('second decision is not discarded', () => { const decision = definition.getActivityById('decision2'); expect(decision.counters).to.have.property('taken', 0); - expect(decision.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); + expect(decision.counters).to.have.property('discarded', 0); }); - And('end event is discarded four times', () => { + And('end event is not discarded', () => { const decision = definition.getActivityById('end'); expect(decision.counters).to.have.property('taken', 0); - expect(decision.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 4); + expect(decision.counters).to.have.property('discarded', 0); }); }); @@ -149,14 +149,14 @@ Feature('Issues', () => { expect(usertask.counters).to.have.property('taken', 3); }); - And('discarded 4 times', () => { - expect(usertask.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 4); + And('not discarded', () => { + expect(usertask.counters).to.have.property('discarded', 0); }); - And('end event is taken once and discarded twice', () => { + And('end event is taken once and not discarded', () => { const endEvent = recovered.getActivityById('end'); expect(endEvent.counters).to.have.property('taken', 1); - expect(endEvent.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); + expect(endEvent.counters).to.have.property('discarded', 0); }); }); @@ -277,16 +277,16 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded once', () => { + And('user task was taken once and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); + expect(task.counters).to.have.property('discarded', 0); }); - And('end was discarded thrice', () => { + And('end was not discarded', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); + expect(task.counters).to.have.property('discarded', 0); }); Given('variables are reset', () => { @@ -325,16 +325,16 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded twice', () => { + And('user task was taken twice and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); + expect(task.counters).to.have.property('discarded', 0); }); - And('end was discarded six times', () => { + And('end was not discarded', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 6); + expect(task.counters).to.have.property('discarded', 0); }); When('definition is recovered with state from first run user task wait', () => { @@ -375,16 +375,16 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded once', () => { + And('user task was taken once and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); + expect(task.counters).to.have.property('discarded', 0); }); - And('end was discarded thrice', () => { + And('end was not discarded', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); + expect(task.counters).to.have.property('discarded', 0); }); }); @@ -450,10 +450,10 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded twice', () => { + And('user task was taken twice and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); + expect(task.counters).to.have.property('discarded', 0); }); When('definition is recovered with state from wait', () => { @@ -494,10 +494,10 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded twice', () => { + And('user task was taken twice and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); + expect(task.counters).to.have.property('discarded', 0); }); }); @@ -565,16 +565,16 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded once', () => { + And('user task was taken once and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); + expect(task.counters).to.have.property('discarded', 0); }); - And('end was discarded thrice', () => { + And('end was not discarded', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); + expect(task.counters).to.have.property('discarded', 0); }); Given('variables are reset', () => { @@ -613,16 +613,16 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded twice', () => { + And('user task was taken twice and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 2); + expect(task.counters).to.have.property('discarded', 0); }); - And('end was discarded six times', () => { + And('end was not discarded', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 2); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 6); + expect(task.counters).to.have.property('discarded', 0); }); When('definition is recovered with state from first run user task wait', () => { @@ -663,16 +663,16 @@ Feature('Issues', () => { return leave; }); - And('user task was discarded once', () => { + And('user task was taken once and not discarded', () => { const task = definition.getActivityById('UserTask'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); + expect(task.counters).to.have.property('discarded', 0); }); - And('end was discarded thrice', () => { + And('end was not discarded', () => { const task = definition.getActivityById('End'); expect(task.counters).to.have.property('taken', 1); - expect(task.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 3); + expect(task.counters).to.have.property('discarded', 0); }); Given('definition is ran again', () => { @@ -712,10 +712,10 @@ Feature('Issues', () => { definition.resume(); }); - Then('end event is discarded once', () => { + Then('end event is still not discarded', () => { expect(definition.getActivityById('End').counters).to.deep.equal({ taken: 0, - discarded: definition.environment.settings.skipDiscard ? 0 : 1, + discarded: 0, }); }); }); diff --git a/test/feature/linking-feature.js b/test/feature/linking-feature.js index f00d4b3c..4d25c966 100644 --- a/test/feature/linking-feature.js +++ b/test/feature/linking-feature.js @@ -40,163 +40,155 @@ Feature('Linking', () => { }); }); - [false, true].forEach((skipDiscard) => { - describe(`run with skipDiscard=${skipDiscard}`, () => { - Scenario('basic link event definition', () => { - /** @type {Definition} */ - let definition; - Given('a flow matching scenario', async () => { - const source = factory.resource('link-basic.bpmn'); - const context = await testHelpers.context(source); - - definition = new Definition(context, { - settings: { - skipDiscard, - }, - services: getTakeServices(), - }); - }); - - let end; - When('definition is ran', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was not reached (default flow taken)', () => { - expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 0, discarded: skipDiscard ? 0 : 1 }); - }); - - And('catch event stayed dormant', () => { - expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 0, discarded: 0 }); - }); - - Given('decision changes to take', () => { - definition.environment.variables.condition = true; - }); - - When('definition is ran again', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was taken', () => { - expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); - expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); - }); - - And('catch event was taken', () => { - expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); - }); + Scenario('basic link event definition', () => { + /** @type {Definition} */ + let definition; + Given('a flow matching scenario', async () => { + const source = factory.resource('link-basic.bpmn'); + const context = await testHelpers.context(source); + + definition = new Definition(context, { + services: getTakeServices(), }); + }); - Scenario('Link within discard flow', () => { - /** @type {Definition} */ - let definition; - const logBook = []; - Given('a decision decides if an intermediate catch event is discarded', async () => { - const source = ` - - - - - - - - - \${environment.variables.condition} - - - - - - - - - - - - - - - - - - - - `; - const context = await testHelpers.context(source); - - definition = new Definition(context, { - settings: { - skipDiscard, - }, - services: { - log(...args) { - logBook.push(...args); - }, - }, - }); - }); - - let end; - When('definition is ran with the decision to discard', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was discarded', () => { - expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); - expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); - }); - - And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); - expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); - }); - - Given('decision changes to take', () => { - definition.environment.variables.condition = true; - }); - - When('definition is ran again', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was taken', () => { - expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); - expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); - }); - - And('catch event was taken', () => { - expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); - }); + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was not reached (default flow taken)', () => { + expect(definition.getActivityById('throw').counters).to.deep.equal({ taken: 0, discarded: 0 }); + }); + + And('catch event stayed dormant', () => { + expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 0, discarded: 0 }); + }); + + Given('decision changes to take', () => { + definition.environment.variables.condition = true; + }); + + When('definition is ran again', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', 0); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); + }); + }); + + Scenario('Link within discard flow', () => { + /** @type {Definition} */ + let definition; + const logBook = []; + Given('a decision decides if an intermediate catch event is discarded', async () => { + const source = ` + + + + + + + + + \${environment.variables.condition} + + + + + + + + + + + + + + + + + + + + `; + const context = await testHelpers.context(source); + + definition = new Definition(context, { + services: { + log(...args) { + logBook.push(...args); + }, + }, }); + }); + + let end; + When('definition is ran with the decision to discard', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event stayed dormant', () => { + expect(definition.getActivityById('throw').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); + }); + + And('catch event stayed dormant', () => { + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); + }); - Scenario('Link within discard flow reversed order', () => { - let definition; - const logBook = []; - Given('a decision decides if an intermediate catch event is discarded', async () => { - const source = ` + Given('decision changes to take', () => { + definition.environment.variables.condition = true; + }); + + When('definition is ran again', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', 0); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); + }); + }); + + Scenario('Link within discard flow reversed order', () => { + let definition; + const logBook = []; + Given('a decision decides if an intermediate catch event is discarded', async () => { + const source = ` @@ -226,68 +218,65 @@ Feature('Linking', () => { `; - const context = await testHelpers.context(source); - - definition = new Definition(context, { - settings: { - skipDiscard, - }, - services: { - log(...args) { - logBook.push(...args); - }, - }, - }); - }); - - let end; - When('definition is ran with the decision to discard', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was discarded', () => { - expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); - expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); - }); - - And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); - expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); - }); - - Given('decision changes to take', () => { - definition.environment.variables.condition = true; - }); - - When('definition is ran again', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition completes immediately', () => { - return end; - }); - - And('throw event was taken', () => { - expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); - expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); - }); - - And('catch event was taken', () => { - expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); - }); + const context = await testHelpers.context(source); + + definition = new Definition(context, { + services: { + log(...args) { + logBook.push(...args); + }, + }, }); + }); + + let end; + When('definition is ran with the decision to discard', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event stayed dormant', () => { + expect(definition.getActivityById('throw').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); + }); + + And('catch event stayed dormant', () => { + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); + }); + + Given('decision changes to take', () => { + definition.environment.variables.condition = true; + }); + + When('definition is ran again', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('definition completes immediately', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', 0); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); + }); + }); - Scenario('Stop and resume', () => { - let context, definition; - Given('a user is asked to take decision if an intermediate catch event is discarded or not', async () => { - const source = ` + Scenario('Stop and resume', () => { + let context, definition; + Given('a user is asked to take decision if an intermediate catch event is discarded or not', async () => { + const source = ` @@ -315,224 +304,215 @@ Feature('Linking', () => { `; - context = await testHelpers.context(source, { - extensions: { js: JsExtension }, - }); - - definition = new Definition(context, { - settings: { - skipDiscard, - }, - extensions: { - js: JsExtension.extension, - }, - }); - }); - - let wait, end; - When('definition is ran', () => { - wait = definition.waitFor('wait'); - end = definition.waitFor('end'); - definition.run(); - }); - - let user; - Then('definition waits for user to decide', async () => { - user = await wait; - expect(user).to.have.property('id', 'start'); - }); - - And('catch is dormant — not running while waiting for the throw', () => { - expect(definition.getActivityById('catch')).to.have.property('isRunning', false); - }); - - Given('execution is stopped', () => { - definition.stop(); - }); - - When('resumed', () => { - definition.resume(); - }); - - And('user takes decision to discard', () => { - user.signal(false); - }); - - Then('definition completes', () => { - return end; - }); - - And('throw event was discarded', () => { - expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); - expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); - }); - - And('catch event was discarded', () => { - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); - expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); - }); - - When('definition is ran again', () => { - wait = definition.waitFor('wait'); - end = definition.waitFor('end'); - definition.run(); - }); - - Then('definition waits for user to decide', async () => { - user = await wait; - expect(user).to.have.property('id', 'start'); - }); - - And('catch is dormant — not running while waiting for the throw', () => { - expect(definition.getActivityById('catch')).to.have.property('isRunning', false); - }); - - Given('execution is stopped', () => { - definition.stop(); - }); - - let state; - And('state is saved', () => { - state = definition.getState(); - }); - - When('definition is recovered and resumed', () => { - definition = new Definition(context, { - extensions: { - js: JsExtension.extension, - }, - }).recover(JSON.parse(JSON.stringify(state))); - - wait = definition.waitFor('wait'); - end = definition.waitFor('end'); - - definition.resume(); - }); - - Then('definition waits for user to decide', async () => { - user = await wait; - expect(user).to.have.property('id', 'start'); - }); - - When('user takes decision to proceed', () => { - user.signal(true); - }); - - Then('definition completes', () => { - return end; - }); - - And('throw event was taken', () => { - expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); - expect(definition.getActivityById('throw').counters).to.have.property('discarded', skipDiscard ? 0 : 1); - }); - - And('catch event was taken', () => { - expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); - expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); - }); + context = await testHelpers.context(source, { + extensions: { js: JsExtension }, }); - Scenario('a flow with link event to bypass parallel join', () => { - let context, definition; - Given('a flow with link event definitions and a bypassed parallel gateway', async () => { - const source = factory.resource('link-to-bypass-parallel-join.bpmn'); + definition = new Definition(context, { + extensions: { + js: JsExtension.extension, + }, + }); + }); - context = await testHelpers.context(source); + let wait, end; + When('definition is ran', () => { + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + definition.run(); + }); - definition = new Definition(context, { - variables: { - condition: true, - }, - settings: { - skipDiscard, - }, - }); - }); + let user; + Then('definition waits for user to decide', async () => { + user = await wait; + expect(user).to.have.property('id', 'start'); + }); - let end; - When('definition is ran with condition to take link', () => { - end = definition.waitFor('end'); - definition.run(); - }); + And('catch is dormant — not running while waiting for the throw', () => { + expect(definition.getActivityById('catch')).to.have.property('isRunning', false); + }); - Then('run completes', () => { - return end; - }); + Given('execution is stopped', () => { + definition.stop(); + }); - And('end was taken', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); - }); + When('resumed', () => { + definition.resume(); + }); + + And('user takes decision to discard', () => { + user.signal(false); + }); - When('definition is ran with condition to discard link', () => { - end = definition.waitFor('end'); + Then('definition completes', () => { + return end; + }); - definition.environment.variables.condition = false; + And('throw event stayed dormant', () => { + expect(definition.getActivityById('throw').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('throw').counters).to.have.property('taken', 0); + }); - definition.run(); - }); + And('catch event stayed dormant', () => { + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); + expect(definition.getActivityById('catch').counters).to.have.property('taken', 0); + }); + + When('definition is ran again', () => { + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return end; - }); + Then('definition waits for user to decide', async () => { + user = await wait; + expect(user).to.have.property('id', 'start'); + }); + + And('catch is dormant — not running while waiting for the throw', () => { + expect(definition.getActivityById('catch')).to.have.property('isRunning', false); + }); + + Given('execution is stopped', () => { + definition.stop(); + }); + + let state; + And('state is saved', () => { + state = definition.getState(); + }); + + When('definition is recovered and resumed', () => { + definition = new Definition(context, { + extensions: { + js: JsExtension.extension, + }, + }).recover(JSON.parse(JSON.stringify(state))); - And('end was taken', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 2); - }); + wait = definition.waitFor('wait'); + end = definition.waitFor('end'); + + definition.resume(); + }); + + Then('definition waits for user to decide', async () => { + user = await wait; + expect(user).to.have.property('id', 'start'); + }); + + When('user takes decision to proceed', () => { + user.signal(true); + }); + + Then('definition completes', () => { + return end; + }); + + And('throw event was taken', () => { + expect(definition.getActivityById('throw').counters).to.have.property('taken', 1); + expect(definition.getActivityById('throw').counters).to.have.property('discarded', 0); + }); + + And('catch event was taken', () => { + expect(definition.getActivityById('catch').counters).to.have.property('taken', 1); + expect(definition.getActivityById('catch').counters).to.have.property('discarded', 0); + }); + }); + + Scenario('a flow with link event to bypass parallel join', () => { + let context, definition; + Given('a flow with link event definitions and a bypassed parallel gateway', async () => { + const source = factory.resource('link-to-bypass-parallel-join.bpmn'); + + context = await testHelpers.context(source); + + definition = new Definition(context, { + variables: { + condition: true, + }, }); + }); - Scenario('a flow with link event to complete parallel join', () => { - let context, definition; - Given('a flow matching scenario', async () => { - const source = factory.resource('link-to-parallel-join.bpmn'); + let end; + When('definition is ran with condition to take link', () => { + end = definition.waitFor('end'); + definition.run(); + }); - context = await testHelpers.context(source); + Then('run completes', () => { + return end; + }); - definition = new Definition(context, { - variables: { - condition: true, - }, - settings: { - skipDiscard, - }, - }); - }); + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); - let end; - When('definition is ran with condition to take link', () => { - end = definition.waitFor('end'); - definition.run(); - }); + When('definition is ran with condition to discard link', () => { + end = definition.waitFor('end'); - Then('run completes', () => { - return end; - }); + definition.environment.variables.condition = false; - And('end was taken', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); - }); + definition.run(); + }); - When('definition is ran with condition to discard link', () => { - end = definition.waitFor('end'); + Then('run completes', () => { + return end; + }); - definition.environment.variables.condition = false; + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); + }); - definition.run(); - }); + Scenario('a flow with link event to complete parallel join', () => { + let context, definition; + Given('a flow matching scenario', async () => { + const source = factory.resource('link-to-parallel-join.bpmn'); - Then('run completes', () => { - return end; - }); + context = await testHelpers.context(source); - And('end was taken', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 2); - }); + definition = new Definition(context, { + variables: { + condition: true, + }, }); + }); + + let end; + When('definition is ran with condition to take link', () => { + end = definition.waitFor('end'); + definition.run(); + }); - Scenario('a parallel join waits for a peer reached through a link', () => { - let definition; - Given('a fork where one branch reaches the join directly and the other via a waiting task and a link', async () => { - const source = ` + Then('run completes', () => { + return end; + }); + + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + + When('definition is ran with condition to discard link', () => { + end = definition.waitFor('end'); + + definition.environment.variables.condition = false; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('end was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); + }); + + Scenario('a parallel join waits for a peer reached through a link', () => { + let definition; + Given('a fork where one branch reaches the join directly and the other via a waiting task and a link', async () => { + const source = ` @@ -552,245 +532,234 @@ Feature('Linking', () => { `; - definition = new Definition(await testHelpers.context(source), { settings: { skipDiscard } }); - }); - - let end; - When('definition is ran', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('the join discovered the link-fed peer and is not taken until it arrives', () => { - expect(definition.getActivityById('join').counters).to.have.property('taken', 0); - expect(definition.getPostponed().some((a) => a.id === 'waiting')).to.be.true; - }); - - When('the waiting task on the link branch is signalled', () => { - definition.signal({ id: 'waiting' }); - }); - - Then('run completes', () => { - return end; - }); - - And('the join was taken exactly once', () => { - expect(definition.getActivityById('join').counters).to.have.property('taken', 1); - }); - - And('end was taken once', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); - }); + definition = new Definition(await testHelpers.context(source)); + }); + + let end; + When('definition is ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('the join discovered the link-fed peer and is not taken until it arrives', () => { + expect(definition.getActivityById('join').counters).to.have.property('taken', 0); + expect(definition.getPostponed().some((a) => a.id === 'waiting')).to.be.true; + }); + + When('the waiting task on the link branch is signalled', () => { + definition.signal({ id: 'waiting' }); + }); + + Then('run completes', () => { + return end; + }); + + And('the join was taken exactly once', () => { + expect(definition.getActivityById('join').counters).to.have.property('taken', 1); + }); + + And('end was taken once', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); + }); + + Scenario('a flow with link event to bypass logic', () => { + let context, definition; + Given('a flow with link event definition to bypass major part of logic', async () => { + const source = factory.resource('link-to-bypass-logic.bpmn'); + + context = await testHelpers.context(source); + + definition = new Definition(context, { + variables: { + condition: true, + }, }); + }); - Scenario('a flow with link event to bypass logic', () => { - let context, definition; - Given('a flow with link event definition to bypass major part of logic', async () => { - const source = factory.resource('link-to-bypass-logic.bpmn'); + let end; + When('definition is ran with condition to take link', () => { + end = definition.waitFor('end'); + definition.run(); + }); - context = await testHelpers.context(source); + Then('run completes', () => { + return end; + }); - definition = new Definition(context, { - variables: { - condition: true, - }, - settings: { - skipDiscard, - }, - }); - }); + And('end was taken once', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); - let end; - When('definition is ran with condition to take link', () => { - end = definition.waitFor('end'); - definition.run(); - }); + When('definition is ran with condition to discard link', () => { + end = definition.waitFor('end'); - Then('run completes', () => { - return end; - }); + definition.environment.variables.condition = false; - And('end was taken once', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); - }); + definition.run(); + }); - When('definition is ran with condition to discard link', () => { - end = definition.waitFor('end'); + Then('run completes', () => { + return end; + }); - definition.environment.variables.condition = false; + And('end was taken again', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 3); + }); + }); - definition.run(); - }); + Scenario('a flow with multiple link events to bypass logic', () => { + let context, definition; + Given('a flow matching scenario', async () => { + const source = factory.resource('multiple-links-to-bypass-logic.bpmn'); - Then('run completes', () => { - return end; - }); + context = await testHelpers.context(source); - And('end was taken again', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 3); - }); + definition = new Definition(context, { + variables: { + condition1: true, + }, }); + }); - Scenario('a flow with multiple link events to bypass logic', () => { - let context, definition; - Given('a flow matching scenario', async () => { - const source = factory.resource('multiple-links-to-bypass-logic.bpmn'); - - context = await testHelpers.context(source); + let end; + When('definition is ran with condition to take link 1', () => { + end = definition.waitFor('end'); + definition.run(); + }); - definition = new Definition(context, { - variables: { - condition1: true, - }, - settings: { - skipDiscard, - }, - }); - }); + Then('run completes', () => { + return end; + }); - let end; - When('definition is ran with condition to take link 1', () => { - end = definition.waitFor('end'); - definition.run(); - }); + And('end was taken once', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); + }); - Then('run completes', () => { - return end; - }); + When('definition is ran with condition to take link 2', () => { + end = definition.waitFor('end'); - And('end was taken once', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); - }); + definition.environment.variables.condition1 = false; + definition.environment.variables.condition2 = true; - When('definition is ran with condition to take link 2', () => { - end = definition.waitFor('end'); + definition.run(); + }); - definition.environment.variables.condition1 = false; - definition.environment.variables.condition2 = true; + Then('run completes', () => { + return end; + }); - definition.run(); - }); + And('end was taken again', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 2); + }); - Then('run completes', () => { - return end; - }); + When('definition is ran with condition to take both links', () => { + end = definition.waitFor('end'); - And('end was taken again', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 2); - }); + definition.environment.variables.condition1 = true; + definition.environment.variables.condition2 = true; - When('definition is ran with condition to take both links', () => { - end = definition.waitFor('end'); + definition.run(); + }); - definition.environment.variables.condition1 = true; - definition.environment.variables.condition2 = true; + Then('run completes', () => { + return end; + }); - definition.run(); - }); + And('end was taken twice', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 4); + }); - Then('run completes', () => { - return end; - }); + When('definition is ran with condition to discard both links', () => { + end = definition.waitFor('end'); - And('end was taken twice', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 4); - }); + definition.environment.variables.condition1 = false; + definition.environment.variables.condition2 = false; - When('definition is ran with condition to discard both links', () => { - end = definition.waitFor('end'); + definition.run(); + }); - definition.environment.variables.condition1 = false; - definition.environment.variables.condition2 = false; + Then('run completes', () => { + return end; + }); - definition.run(); - }); + And('end was taken twice', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 6); + }); + }); - Then('run completes', () => { - return end; - }); + Scenario('a flow with multiple named link throw and catch events', () => { + /** @type {Definition} */ + let definition; + Given('a flow with an inclusive gateway routing to one or both link throw events', async () => { + const source = factory.resource('link-multiple.bpmn'); + const context = await testHelpers.context(source); - And('end was taken twice', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 6); - }); + definition = new Definition(context, { + variables: { + take1: true, + }, }); + }); - Scenario('a flow with multiple named link throw and catch events', () => { - /** @type {Definition} */ - let definition; - Given('a flow with an inclusive gateway routing to one or both link throw events', async () => { - const source = factory.resource('link-multiple.bpmn'); - const context = await testHelpers.context(source); - - definition = new Definition(context, { - variables: { - take1: true, - }, - settings: { - skipDiscard, - }, - }); - }); - - let end; - When('definition is ran with condition to take LINKA only', () => { - end = definition.waitFor('end'); - definition.run(); - }); - - Then('run completes', () => { - return end; - }); - - And('LINKA end was taken once', () => { - expect(definition.getActivityById('end-a').counters).to.have.property('taken', 1); - }); - - And('LINKB end stayed dormant', () => { - expect(definition.getActivityById('end-b').counters).to.have.property('taken', 0); - }); - - When('definition is ran with condition to take LINKB only', () => { - end = definition.waitFor('end'); - - definition.environment.variables.take1 = false; - definition.environment.variables.take2 = true; - - definition.run(); - }); - - Then('run completes', () => { - return end; - }); - - And('LINKA end was not taken again', () => { - expect(definition.getActivityById('end-a').counters).to.have.property('taken', 1); - }); - - And('LINKB end was taken once', () => { - expect(definition.getActivityById('end-b').counters).to.have.property('taken', 1); - }); - - When('definition is ran with condition to take both links', () => { - end = definition.waitFor('end'); - - definition.environment.variables.take1 = true; - definition.environment.variables.take2 = true; - - definition.run(); - }); - - Then('run completes', () => { - return end; - }); - - And('LINKA end was taken again', () => { - expect(definition.getActivityById('end-a').counters).to.have.property('taken', 2); - }); - - And('LINKB end was taken again', () => { - expect(definition.getActivityById('end-b').counters).to.have.property('taken', 2); - }); - }); + let end; + When('definition is ran with condition to take LINKA only', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('LINKA end was taken once', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 1); + }); + + And('LINKB end stayed dormant', () => { + expect(definition.getActivityById('end-b').counters).to.have.property('taken', 0); + }); + + When('definition is ran with condition to take LINKB only', () => { + end = definition.waitFor('end'); + + definition.environment.variables.take1 = false; + definition.environment.variables.take2 = true; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('LINKA end was not taken again', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 1); + }); + + And('LINKB end was taken once', () => { + expect(definition.getActivityById('end-b').counters).to.have.property('taken', 1); + }); + + When('definition is ran with condition to take both links', () => { + end = definition.waitFor('end'); + + definition.environment.variables.take1 = true; + definition.environment.variables.take2 = true; + + definition.run(); + }); + + Then('run completes', () => { + return end; + }); + + And('LINKA end was taken again', () => { + expect(definition.getActivityById('end-a').counters).to.have.property('taken', 2); + }); + + And('LINKB end was taken again', () => { + expect(definition.getActivityById('end-b').counters).to.have.property('taken', 2); }); }); }); diff --git a/test/feature/messaging-feature.js b/test/feature/messaging-feature.js index 8cc86ef5..3cc85fd6 100644 --- a/test/feature/messaging-feature.js +++ b/test/feature/messaging-feature.js @@ -23,7 +23,7 @@ Feature('Messaging', () => { `; - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); definition = new Definition(context); }); @@ -58,9 +58,9 @@ Feature('Messaging', () => { expect(start2.owner.counters).to.have.property('discarded', 1); }); - And('gateway is taken and discarded', () => { + And('gateway is taken', () => { expect(definition.getActivityById('gateway').counters).to.have.property('taken', 1); - expect(definition.getActivityById('gateway').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('gateway').counters).to.have.property('discarded', 0); }); }); @@ -549,7 +549,7 @@ Feature('Messaging', () => { `; - context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + context = await testHelpers.context(source); definition = new Definition(context); }); @@ -633,7 +633,7 @@ Feature('Messaging', () => { And('receive task is discarded', () => { expect(receive.owner.counters).to.have.property('discarded', 1); expect(receive.owner.counters).to.have.property('taken', 2); - expect(definition.getActivityById('end').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end').counters).to.have.property('discarded', 0); expect(definition.getActivityById('end').counters).to.have.property('taken', 2); }); @@ -684,7 +684,7 @@ Feature('Messaging', () => { expect(definition.getActivityById('receive').counters).to.have.property('taken', 3); expect(definition.getActivityById('receive').counters).to.have.property('discarded', 1); expect(definition.getActivityById('end').counters).to.have.property('taken', 3); - expect(definition.getActivityById('end').counters).to.have.property('discarded', 1); + expect(definition.getActivityById('end').counters).to.have.property('discarded', 0); }); When('definition is ran again', () => { diff --git a/test/feature/multiple-startevent-feature.js b/test/feature/multiple-startevent-feature.js index 82c80cd4..e7a09f63 100644 --- a/test/feature/multiple-startevent-feature.js +++ b/test/feature/multiple-startevent-feature.js @@ -3,275 +3,261 @@ import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; Feature('Multiple start events', () => { - [false, true].forEach((skipDiscard) => { - describe(`run ${skipDiscard ? 'with' : 'without'} skipDiscard setting`, () => { - Scenario('Two start events waiting to be signaled ending up in a task', () => { - const source = factory.resource('multiple-signal-startevents.bpmn'); - - let definition; - Given('a process with multiple start events, a joining task and an end event', async () => { - const context = await testHelpers.context(source); - definition = new Definition(context, { - settings: { - skipDiscard, - }, - extensions: { - output(element) { - if (element.type !== 'bpmn:Process') return; - - const { broker, environment } = element; - broker.subscribeTmp( - 'event', - 'activity.end', - (_, { content }) => { - environment.output[content.id] = 1; - }, - { noAck: true } - ); + Scenario('Two start events waiting to be signaled ending up in a task', () => { + const source = factory.resource('multiple-signal-startevents.bpmn'); + + let definition; + Given('a process with multiple start events, a joining task and an end event', async () => { + const context = await testHelpers.context(source); + definition = new Definition(context, { + extensions: { + output(element) { + if (element.type !== 'bpmn:Process') return; + + const { broker, environment } = element; + broker.subscribeTmp( + 'event', + 'activity.end', + (_, { content }) => { + environment.output[content.id] = 1; }, - }, - }); - }); - - let leave; - When('process is ran', () => { - leave = definition.waitFor('leave'); - definition.run(); - }); - - And('first start event is signaled', () => { - definition.signal(); - }); - - Then('first end event is taken', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: skipDiscard ? 0 : 1 }); - }); - - And('second end event is not taken', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: skipDiscard ? 0 : 2 }); - }); - - And('process is completed', async () => { - await leave; - expect(definition.counters).to.deep.equal({ - completed: 1, - discarded: 0, - }); - }); - - When('process is ran again', () => { - leave = definition.waitFor('leave'); - definition.run(); - }); - - And('second start event is signaled', () => { - const start2 = definition.getPostponed().find(({ id }) => id === 'start2'); - definition.signal(start2.content.signal); - }); - - Then('second end event is taken', () => { - const endEvent = definition.getActivityById('named-end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: skipDiscard ? 0 : 3 }); - }); - - And('first end event is discarded', () => { - const endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: skipDiscard ? 0 : 3 }); - }); - - And('process is completed', async () => { - await leave; - - const pending = definition.getPostponed().map(({ id }) => id); - - expect(definition.counters, `pending <${pending}>`).to.deep.equal({ - completed: 2, - discarded: 0, - }); - }); + { noAck: true } + ); + }, + }, }); + }); - Scenario('Two start events waiting to be signaled ending up in a parallel join', () => { - const source = ` - - - - - - - - - - - - - - - next(null, environment.output.start2) - - - - - - - `; - - let definition; - Given('a process with multiple start events, a joining task and an end event', async () => { - const context = await testHelpers.context(source); - definition = new Definition(context, { - environment: { - settings: { - skipDiscard, - }, - }, - extensions: { - output(element) { - if (element.type !== 'bpmn:Process') return; - - const { broker, environment } = element; - broker.subscribeTmp( - 'event', - 'activity.end', - (_, { content }) => { - environment.output[content.id] = 1; - }, - { noAck: true } - ); - }, - }, - }); - }); - - let leave; - When('process is ran', () => { - leave = definition.waitFor('leave'); - definition.run(); - }); - - And('first start event is signaled', () => { - definition.signal(); - }); - - Then('the second start event is discarded as an alternative entry point', () => { - expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); - }); - - And('the parallel join fires once with the single token', () => { - expect(definition.getActivityById('join').counters).to.include({ taken: 1 }); - }); - - And('the default end event is taken and the process is completed', async () => { - await leave; - expect(definition.getActivityById('end').counters).to.include({ taken: 1 }); - expect(definition.getActivityById('named-end').counters).to.include({ taken: 0 }); - expect(definition.counters).to.include({ completed: 1 }); - }); - - When('process is ran again and the second start event is signaled first', () => { - leave = definition.waitFor('leave'); - definition.run(); - definition.signal({ id: 'Message_1' }); - }); - - Then('the first start event is now discarded as the alternative', () => { - expect(definition.getActivityById('start1').counters).to.include({ discarded: 1 }); - }); - - And('the named end event is taken and the process is completed', async () => { - await leave; - expect(definition.getActivityById('named-end').counters).to.include({ taken: 1 }); - expect(definition.counters).to.include({ completed: 2 }); - }); + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + And('first start event is signaled', () => { + definition.signal(); + }); + + Then('first end event is taken', () => { + const endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('second end event is not taken', () => { + const endEvent = definition.getActivityById('named-end'); + expect(endEvent.counters).to.deep.equal({ taken: 0, discarded: 0 }); + }); + + And('process is completed', async () => { + await leave; + expect(definition.counters).to.deep.equal({ + completed: 1, + discarded: 0, }); + }); + + When('process is ran again', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); - Scenario('Two start events joined by a task followed by a parallel fork', () => { - const source = ` - - - - - - - - - - - - - - - - - - - - `; - - let context; - /** @type {Definition} */ - let definition; - Given('a process with multiple signal start events, a joining task and a subsequent fork', async () => { - context = await testHelpers.context(source); - definition = new Definition(context, { - settings: { skipDiscard }, - }); - }); - - And('the subsequent fork is a parallel gateway but not a parallel join', () => { - const fork = definition.getActivityById('fork'); - expect(fork.isParallelGateway, 'isParallelGateway').to.be.true; - expect(fork.isParallelJoin, 'isParallelJoin').to.be.false; - expect(fork.inbound).to.have.length(1); - expect(fork.outbound).to.have.length(2); - }); - - let leave; - When('process is ran', () => { - leave = definition.waitFor('leave'); - definition.run(); - }); - - And('the first start event is signaled', () => { - definition.signal(); - }); - - Then('the second start event is discarded as an alternative entry point', () => { - expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); - }); - - And('the joining task was taken once', () => { - expect(definition.getActivityById('task').counters).to.include({ taken: 1 }); - }); - - And('the fork fired once and both end events were taken once, completing the process', async () => { - await leave; - expect(definition.getActivityById('fork').counters).to.include({ taken: 1 }); - expect(definition.getActivityById('end1').counters).to.include({ taken: 1 }); - expect(definition.getActivityById('end2').counters).to.include({ taken: 1 }); - expect(definition.counters).to.include({ completed: 1 }); - }); - - When('process is ran again and the second start event is signaled', () => { - leave = definition.waitFor('leave'); - definition.run(); - definition.signal({ id: 'Signal2' }); - }); - - Then('the first start event is now discarded as the alternative', () => { - expect(definition.getActivityById('start1').counters).to.include({ discarded: 1 }); - }); - - And('the process is completed and the task was taken once more', async () => { - await leave; - expect(definition.getActivityById('task').counters).to.include({ taken: 2 }); - expect(definition.getActivityById('fork').counters).to.include({ taken: 2 }); - expect(definition.counters).to.include({ completed: 2 }); - }); + And('second start event is signaled', () => { + const start2 = definition.getPostponed().find(({ id }) => id === 'start2'); + definition.signal(start2.content.signal); + }); + + Then('second end event is taken', () => { + const endEvent = definition.getActivityById('named-end'); + expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('first end event is discarded', () => { + const endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + And('process is completed', async () => { + await leave; + + const pending = definition.getPostponed().map(({ id }) => id); + + expect(definition.counters, `pending <${pending}>`).to.deep.equal({ + completed: 2, + discarded: 0, + }); + }); + }); + + Scenario('Two start events waiting to be signaled ending up in a parallel join', () => { + const source = ` + + + + + + + + + + + + + + + next(null, environment.output.start2) + + + + + + + `; + + let definition; + Given('a process with multiple start events, a joining task and an end event', async () => { + const context = await testHelpers.context(source); + definition = new Definition(context, { + extensions: { + output(element) { + if (element.type !== 'bpmn:Process') return; + + const { broker, environment } = element; + broker.subscribeTmp( + 'event', + 'activity.end', + (_, { content }) => { + environment.output[content.id] = 1; + }, + { noAck: true } + ); + }, + }, }); }); + + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + And('first start event is signaled', () => { + definition.signal(); + }); + + Then('the second start event is discarded as an alternative entry point', () => { + expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); + }); + + And('the parallel join fires once with the single token', () => { + expect(definition.getActivityById('join').counters).to.include({ taken: 1 }); + }); + + And('the default end event is taken and the process is completed', async () => { + await leave; + expect(definition.getActivityById('end').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('named-end').counters).to.include({ taken: 0 }); + expect(definition.counters).to.include({ completed: 1 }); + }); + + When('process is ran again and the second start event is signaled first', () => { + leave = definition.waitFor('leave'); + definition.run(); + definition.signal({ id: 'Message_1' }); + }); + + Then('the first start event is now discarded as the alternative', () => { + expect(definition.getActivityById('start1').counters).to.include({ discarded: 1 }); + }); + + And('the named end event is taken and the process is completed', async () => { + await leave; + expect(definition.getActivityById('named-end').counters).to.include({ taken: 1 }); + expect(definition.counters).to.include({ completed: 2 }); + }); + }); + + Scenario('Two start events joined by a task followed by a parallel fork', () => { + const source = ` + + + + + + + + + + + + + + + + + + + + `; + + let context; + /** @type {Definition} */ + let definition; + Given('a process with multiple signal start events, a joining task and a subsequent fork', async () => { + context = await testHelpers.context(source); + definition = new Definition(context); + }); + + And('the subsequent fork is a parallel gateway but not a parallel join', () => { + const fork = definition.getActivityById('fork'); + expect(fork.isParallelGateway, 'isParallelGateway').to.be.true; + expect(fork.isParallelJoin, 'isParallelJoin').to.be.false; + expect(fork.inbound).to.have.length(1); + expect(fork.outbound).to.have.length(2); + }); + + let leave; + When('process is ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + And('the first start event is signaled', () => { + definition.signal(); + }); + + Then('the second start event is discarded as an alternative entry point', () => { + expect(definition.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); + }); + + And('the joining task was taken once', () => { + expect(definition.getActivityById('task').counters).to.include({ taken: 1 }); + }); + + And('the fork fired once and both end events were taken once, completing the process', async () => { + await leave; + expect(definition.getActivityById('fork').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('end1').counters).to.include({ taken: 1 }); + expect(definition.getActivityById('end2').counters).to.include({ taken: 1 }); + expect(definition.counters).to.include({ completed: 1 }); + }); + + When('process is ran again and the second start event is signaled', () => { + leave = definition.waitFor('leave'); + definition.run(); + definition.signal({ id: 'Signal2' }); + }); + + Then('the first start event is now discarded as the alternative', () => { + expect(definition.getActivityById('start1').counters).to.include({ discarded: 1 }); + }); + + And('the process is completed and the task was taken once more', async () => { + await leave; + expect(definition.getActivityById('task').counters).to.include({ taken: 2 }); + expect(definition.getActivityById('fork').counters).to.include({ taken: 2 }); + expect(definition.counters).to.include({ completed: 2 }); + }); }); const startAndReceiveSource = ` diff --git a/test/feature/outbound-flows-feature.js b/test/feature/outbound-flows-feature.js index efa5be40..9a11933c 100644 --- a/test/feature/outbound-flows-feature.js +++ b/test/feature/outbound-flows-feature.js @@ -8,7 +8,7 @@ Feature('Outbound flows', () => { let definition; Given('a task with one default flow, flow with script condition, and a third with expression', async () => { const source = factory.resource('conditional-flows.bpmn'); - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); definition = new Definition(context); }); @@ -24,14 +24,14 @@ Feature('Outbound flows', () => { }); }); - And('the other two discarded', () => { + And('the other two stay dormant', () => { expect(definition.getActivityById('task3').counters).to.deep.equal({ taken: 0, - discarded: 1, + discarded: 0, }); expect(definition.getActivityById('task4').counters).to.deep.equal({ taken: 0, - discarded: 1, + discarded: 0, }); }); @@ -44,18 +44,18 @@ Feature('Outbound flows', () => { Then('expression flow is taken', () => { expect(definition.getActivityById('task4').counters).to.deep.equal({ taken: 1, - discarded: 1, + discarded: 0, }); }); - And('the other two discarded', () => { + And('the other two stay as before', () => { expect(definition.getActivityById('task2').counters).to.deep.equal({ taken: 1, - discarded: 1, + discarded: 0, }); expect(definition.getActivityById('task3').counters).to.deep.equal({ taken: 0, - discarded: 2, + discarded: 0, }); }); @@ -68,18 +68,18 @@ Feature('Outbound flows', () => { Then('default flow is taken', () => { expect(definition.getActivityById('task3').counters).to.deep.equal({ taken: 1, - discarded: 2, + discarded: 0, }); }); - And('the other two discarded', () => { + And('the other two stay as before', () => { expect(definition.getActivityById('task2').counters).to.deep.equal({ taken: 1, - discarded: 2, + discarded: 0, }); expect(definition.getActivityById('task4').counters).to.deep.equal({ taken: 1, - discarded: 2, + discarded: 0, }); }); }); diff --git a/test/feature/performance-feature.js b/test/feature/performance-feature.js index 1bd2fe78..e0834776 100644 --- a/test/feature/performance-feature.js +++ b/test/feature/performance-feature.js @@ -9,122 +9,111 @@ const extensions = { }; Feature('Performance', () => { - [true, false].forEach((skipDiscard) => { - describe(`${skipDiscard ? 'with' : 'without'} skipDiscard and lots of script conditions`, () => { - let context; - Given('a diagram with lots of script conditions and nested joins', async () => { - const source = factory.resource('nested-joins.bpmn'); - context = await testHelpers.context(source, { extensions }); - }); + describe('lots of script conditions', () => { + let context; + Given('a diagram with lots of script conditions and nested joins', async () => { + const source = factory.resource('nested-joins.bpmn'); + context = await testHelpers.context(source, { extensions }); + }); - let definition, ended; - When('run with default JavaScript', async () => { - definition = new Definition(await context.clone(), { settings: { skipDiscard } }); - ended = definition.waitFor('end'); - await definition.run(); - }); + let definition, ended; + When('run with default JavaScript', async () => { + definition = new Definition(await context.clone()); + ended = definition.waitFor('end'); + await definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - When('run again with default JavaScript', () => { - definition = new Definition(context.clone(), { settings: { skipDiscard } }); - ended = definition.waitFor('end'); - definition.run(); - }); + When('run again with default JavaScript', () => { + definition = new Definition(context.clone()); + ended = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - let endEvent; - And('end event was taken', () => { - endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.have.property('taken', 1); - }); + let endEvent; + And('end event was taken', () => { + endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.have.property('taken', 1); + }); - When('same definition is ran again', () => { - ended = definition.waitFor('end'); - definition.run(); - }); + When('same definition is ran again', () => { + ended = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - And('end event was taken again', () => { - endEvent = definition.getActivityById('end'); - expect(endEvent.counters).to.have.property('taken', 2); - }); + And('end event was taken again', () => { + endEvent = definition.getActivityById('end'); + expect(endEvent.counters).to.have.property('taken', 2); + }); - When('run with non-op JavaScript', () => { - definition = new Definition(context.clone(), { - settings: { - skipDiscard, + When('run with non-op JavaScript', () => { + definition = new Definition(context.clone(), { + scripts: { + register() {}, + getScript() { + return { + execute(...args) { + return args.pop()(); + }, + }; }, - scripts: { - register() {}, - getScript() { - return { - execute(...args) { - return args.pop()(); - }, - }; - }, - }, - }); - ended = definition.waitFor('end'); - definition.run(); + }, }); + ended = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - When('run without logger', () => { - definition = new Definition(context.clone(), { - settings: { - skipDiscard, - }, - Logger: null, - }); - ended = definition.waitFor('end'); - definition.run(); + When('run without logger', () => { + definition = new Definition(context.clone(), { + Logger: null, }); + ended = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - When('run with non-op JavaScript and no logger', () => { - definition = new Definition(context.clone(), { - settings: { - skipDiscard, + When('run with non-op JavaScript and no logger', () => { + definition = new Definition(context.clone(), { + Logger: null, + scripts: { + register() {}, + getScript() { + return { + execute(...args) { + return args.pop()(); + }, + }; }, - Logger: null, - scripts: { - register() {}, - getScript() { - return { - execute(...args) { - return args.pop()(); - }, - }; - }, - }, - }); - ended = definition.waitFor('end'); - definition.run(); + }, }); + ended = definition.waitFor('end'); + definition.run(); + }); - Then('run completes', () => { - return ended; - }); + Then('run completes', () => { + return ended; + }); - And('end event was taken', () => { - expect(definition.getActivityById('end').counters).to.have.property('taken', 1); - }); + And('end event was taken', () => { + expect(definition.getActivityById('end').counters).to.have.property('taken', 1); }); }); }); diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index e92fc197..78bb3f8a 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -758,43 +758,4 @@ Feature('Shaking', () => { expect(definition.getActivityById('join').counters).to.have.property('taken', 2); }); }); - - // [ - // 'join-paradox-1.bpmn', - // 'join-paradox-2.bpmn', - // 'join-paradox-3.bpmn', - // 'join-inbound.bpmn', - // 'issue-42-same-target-sequence-flows.bpmn', - // ].forEach((source) => { - // Scenario(`${source} with parallel join gateways should shake as expected`, () => { - // /** @type {Definition} */ - // let definition; - // Given('a process matching scenario', async () => { - // const context = await testHelpers.context(factory.resource(source)); - - // definition = new Definition(context, { - // settings: { skipDiscard: true }, - // variables: { input: 0 }, - // services: { - // takeFlow() { - // return true; - // }, - // takeOnce({ environment }) { - // const count = environment.variables[environment.variables.content.executionId] ?? 0; - // environment.variables[environment.variables.content.executionId] = count + 1; - // return count === 0; - // }, - // }, - // }); - // }); - - // When('shook', () => { - // console.log('---SHAKE', definition.shake()); - // }); - - // Then('join parallel gateway has expected inbound', () => { - // console.log(definition.getProcesses()[0].getActivityById('join').expectedInboundSources); - // }); - // }); - // }); }); diff --git a/test/feature/skip-discard-feature.js b/test/feature/skip-discard-feature.js index eb634610..c006d9bc 100644 --- a/test/feature/skip-discard-feature.js +++ b/test/feature/skip-discard-feature.js @@ -5,7 +5,7 @@ import testHelpers from '../helpers/testHelpers.js'; import factory from '../helpers/factory.js'; import CamundaExtension from '../resources/extensions/CamundaExtension.js'; -Feature('Skip discarding flows if parallel gateway is not used', () => { +Feature('Skip discarding sequence flows', () => { after(ck.reset); Scenario('A process with task splits', () => { @@ -18,7 +18,7 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { js: JsExtension, }, }); - definition = new Definition(context, { settings: { skipDiscard: true } }); + definition = new Definition(context); }); const discardedFlows = []; @@ -67,7 +67,7 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { js: JsExtension, }, }); - definition = new Definition(context, { settings: { skipDiscard: true }, variables: { input: 0 } }); + definition = new Definition(context, { variables: { input: 0 } }); }); const discardedFlows = []; @@ -115,7 +115,7 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { js: JsExtension, }, }); - definition = new Definition(context, { settings: { skipDiscard: true }, variables: { input: 0 } }); + definition = new Definition(context, { variables: { input: 0 } }); }); const discardedFlows = []; @@ -176,7 +176,6 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { }, }); definition = new Definition(context, { - settings: { skipDiscard: true }, variables: { input: 0 }, services: { takeFlow() { @@ -252,7 +251,6 @@ Feature('Skip discarding flows if parallel gateway is not used', () => { }, }); definition = new Definition(context, { - settings: { skipDiscard: true }, variables: { input: 0 }, services: { takeFlow() { diff --git a/test/feature/sub-process-feature.js b/test/feature/sub-process-feature.js index 14b3ba66..d916ea9a 100644 --- a/test/feature/sub-process-feature.js +++ b/test/feature/sub-process-feature.js @@ -155,9 +155,6 @@ Feature('Sub-process', () => { let leave; When('running definition with instruction to loop back', () => { definition = new Definition(context, { - settings: { - skipDiscard: true, - }, variables: { cardinality: 10, loopback: true, @@ -283,7 +280,7 @@ Feature('Sub-process', () => { And('sub process is taken twice', () => { sub = definition.getActivityById('sub'); expect(sub.counters).to.have.property('taken', 2); - expect(sub.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); + expect(sub.counters).to.have.property('discarded', 0); }); And('leaves no lingering references', () => { @@ -374,10 +371,10 @@ Feature('Sub-process', () => { }).timeout(10000); let sub; - And('sub process was taken twice and discarded once by gateway', () => { + And('sub process was taken twice and not discarded', () => { sub = definition.getActivityById('sub'); expect(sub.counters).to.have.property('taken', 2); - expect(sub.counters).to.have.property('discarded', definition.environment.settings.skipDiscard ? 0 : 1); + expect(sub.counters).to.have.property('discarded', 0); }); And('leaves no lingering references', () => { diff --git a/test/flows/SequenceFlow-test.js b/test/flows/SequenceFlow-test.js index c0f4709b..f010f93f 100644 --- a/test/flows/SequenceFlow-test.js +++ b/test/flows/SequenceFlow-test.js @@ -329,7 +329,7 @@ describe('SequenceFlow', () => { expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.include({ take: 0 }); }); - it('discards the outbound of a non-gateway activity with falsy conditions when skipDiscard is off', async () => { + it('neither takes nor discards the outbound of a non-gateway activity with falsy conditions', async () => { const source = ` @@ -348,15 +348,15 @@ describe('SequenceFlow', () => { `; - const ctx = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const ctx = await testHelpers.context(source); const activity = ctx.getActivityById('task'); const leave = activity.waitFor('leave'); activity.run(); await leave; - expect(activity.outbound.find((f) => f.id === 'flow2').counters).to.include({ take: 0, discard: 1 }); - expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.include({ take: 0, discard: 1 }); + expect(activity.outbound.find((f) => f.id === 'flow2').counters).to.include({ take: 0, discard: 0 }); + expect(activity.outbound.find((f) => f.id === 'flow3').counters).to.include({ take: 0, discard: 0 }); }); it('can handle external resource condition with custom script handler', async () => { diff --git a/test/gateways/EventBasedGateway-test.js b/test/gateways/EventBasedGateway-test.js index c72899a6..03d31576 100644 --- a/test/gateways/EventBasedGateway-test.js +++ b/test/gateways/EventBasedGateway-test.js @@ -66,7 +66,7 @@ describe('EventBasedGateway', () => { `; - const context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + const context = await testHelpers.context(source); const [bp] = context.getProcesses(); const gateway = bp.getActivityById('decision'); const usertask = bp.getActivityById('usertask'); @@ -98,11 +98,11 @@ describe('EventBasedGateway', () => { expect(bp.counters).to.have.property('completed', 1); expect(gateway.counters, 'gateway').to.have.property('taken', 3); - expect(gateway.counters, 'gateway').to.have.property('discarded', 1); + expect(gateway.counters, 'gateway').to.have.property('discarded', 0); expect(usertask.counters, 'usertask').to.have.property('taken', 2); expect(usertask.counters, 'usertask').to.have.property('discarded', 1); expect(receive.counters, 'receive').to.have.property('taken', 1); - expect(receive.counters, 'receive').to.have.property('discarded', 3); + expect(receive.counters, 'receive').to.have.property('discarded', 2); }); }); diff --git a/test/gateways/ParallelGateway-test.js b/test/gateways/ParallelGateway-test.js index eb6e3913..ee118087 100644 --- a/test/gateways/ParallelGateway-test.js +++ b/test/gateways/ParallelGateway-test.js @@ -20,7 +20,7 @@ describe('ParallelGateway', () => { let context; beforeEach(async () => { - context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + context = await testHelpers.context(source); }); it('takes all outbound', async () => { @@ -39,7 +39,7 @@ describe('ParallelGateway', () => { expect(activity.outbound[1].counters).to.have.property('discard', 0); }); - it('leaves and discards all outbound if inbound was discarded', async () => { + it('leaves without taking any outbound if inbound was discarded', async () => { const activity = context.getActivityById('fork'); activity.activate(); @@ -49,10 +49,11 @@ describe('ParallelGateway', () => { await leave; + expect(activity.counters).to.deep.equal({ taken: 0, discarded: 1 }); expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 1); + expect(activity.outbound[0].counters).to.have.property('discard', 0); expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 1); + expect(activity.outbound[1].counters).to.have.property('discard', 0); }); }); @@ -149,7 +150,7 @@ describe('ParallelGateway', () => { let context; beforeEach(async () => { - context = await testHelpers.context(sourceSameSourceId, { settings: { skipDiscard: false } }); + context = await testHelpers.context(sourceSameSourceId); }); it('waits for one inbound', async () => { @@ -169,7 +170,7 @@ describe('ParallelGateway', () => { expect(outboundFlow.counters).to.have.property('discard', 0); }); - it('discards outbound if one inbound were discarded', async () => { + it('leaves without taking outbound if one inbound were discarded', async () => { const activity = context.getActivityById('join'); activity.activate(); @@ -179,8 +180,9 @@ describe('ParallelGateway', () => { await leave; + expect(activity.counters).to.deep.equal({ taken: 0, discarded: 1 }); const outboundFlow = activity.outbound[0]; - expect(outboundFlow.counters).to.have.property('discard', 1); + expect(outboundFlow.counters).to.have.property('discard', 0); expect(outboundFlow.counters).to.have.property('take', 0); }); diff --git a/test/tasks/ServiceTask-test.js b/test/tasks/ServiceTask-test.js index 86a09d98..2b136a44 100644 --- a/test/tasks/ServiceTask-test.js +++ b/test/tasks/ServiceTask-test.js @@ -15,7 +15,7 @@ describe('ServiceTask', () => { `; - const context = await testHelpers.context(source, { settings: { skipDiscard: false, enableDummyService: false } }); + const context = await testHelpers.context(source, { settings: { enableDummyService: false } }); const task = context.getActivityById('task'); let error; @@ -290,7 +290,7 @@ describe('ServiceTask', () => { `; - context = await testHelpers.context(source, { settings: { skipDiscard: false } }); + context = await testHelpers.context(source); context.environment.addService('postMessage', (ctx, next) => { next(null, true); }); @@ -349,7 +349,7 @@ describe('ServiceTask', () => { await errored; - expect(task.outbound[0].counters).to.have.property('discard', 1); + expect(task.outbound[0].counters).to.have.property('discard', 0); }); it('caught error discards other boundary events', async () => { @@ -385,7 +385,7 @@ describe('ServiceTask', () => { await errored; - expect(task.outbound[0].counters).to.have.property('discard', 1); + expect(task.outbound[0].counters).to.have.property('discard', 0); }); it('times out if bound timeout event if callback is not called within timeout duration', () => { diff --git a/test/tasks/SubProcess-test.js b/test/tasks/SubProcess-test.js index b0e0a1da..752d2ece 100644 --- a/test/tasks/SubProcess-test.js +++ b/test/tasks/SubProcess-test.js @@ -117,7 +117,7 @@ describe('SubProcess', () => { }); it('discarded child activity still completes sub process', async () => { - context = await testHelpers.context(subProcessSource, { settings: { skipDiscard: false } }); + context = await testHelpers.context(subProcessSource); const subProcess = context.getActivityById('subProcess'); subProcess.activate(); @@ -147,8 +147,6 @@ describe('SubProcess', () => { assertMessage('activity.enter', 'subUserTask'); assertMessage('activity.start', 'subUserTask'); assertMessage('activity.wait', 'subUserTask'); - assertMessage('activity.discard', 'subScriptTask'); - assertMessage('activity.leave', 'subScriptTask'); assertMessage('activity.leave', 'subUserTask'); assertMessage('activity.end', 'subProcess'); assertMessage('activity.leave', 'subProcess'); diff --git a/types/index.d.ts b/types/index.d.ts index f5fbf75e..f1ea5920 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -196,11 +196,6 @@ declare module 'bpmn-elements' { * Defaults to falsy */ disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; [x: string]: any; } diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index 79679e89..fe2286dd 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -294,11 +294,6 @@ export interface EnvironmentSettings { * Defaults to falsy */ disableTrackState?: boolean; - /** - * Skip discarding outbound sequence flows. - * Defaults to false - */ - skipDiscard?: boolean; [x: string]: any; } From 80ec068cbcc04a6e49881a4e3026c6bf935afc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Fri, 12 Jun 2026 07:24:57 +0200 Subject: [PATCH 27/31] remove remnants of discarded flows --- dist/activity/Activity.js | 28 +- dist/flows/SequenceFlow.js | 5 +- dist/gateways/ParallelGateway.js | 13 +- dist/messageHelper.js | 4 - dist/process/ProcessExecution.js | 1 - src/activity/Activity.js | 21 +- src/flows/SequenceFlow.js | 5 +- src/gateways/ParallelGateway.js | 10 +- src/messageHelper.js | 5 +- src/process/ProcessExecution.js | 1 - test/activities-test.js | 28 +- test/activity/Activity-test.js | 60 +- test/events/BoundaryEvent-test.js | 12 +- test/events/EndEvent-test.js | 14 +- .../feature/backward-compatability-feature.js | 60 +- test/feature/call-activity-feature.js | 40 + test/feature/recover-resume-feature.js | 125 + test/feature/signal-feature.js | 36 + test/gateways/ExclusiveGateway-test.js | 6 +- test/gateways/InclusiveGateway-test.js | 6 +- test/gateways/ParallelGateway-test.js | 23 +- test/resources/activity-lifecycle.bpmn | 34 +- test/resources/mother-of-all-state-17.3.json | 4442 +++++++++++++++++ test/resources/mother-of-all-state-18.json | 4232 ++++++++++++++++ test/tasks/UserTask-test.js | 6 +- types/index.d.ts | 7 +- 26 files changed, 9032 insertions(+), 192 deletions(-) create mode 100644 test/resources/mother-of-all-state-17.3.json create mode 100644 test/resources/mother-of-all-state-18.json diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index f9069d54..3b032f8f 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -435,7 +435,7 @@ Activity.prototype.resume = function resume() { }; /** - * Discard the activity. Stops execution if running and discards outbound flows. + * Discard the activity. Stops execution if running; the activity leaves without taking any outbound flow. * @param {Record} [discardContent] Optional content propagated with the discard * @returns {void} */ @@ -707,16 +707,11 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { message: content.message, inbound }); - case 'flow.discard': case 'activity.discard': { - let discardSequence; - if (content.discardSequence) discardSequence = content.discardSequence.slice(); - const context = { - inbound, - discardSequence - }; - return this[K_FLAGS].isParallelGateway ? this.run(context) : this._runDiscard(context); + return this._runDiscard({ + inbound + }); } } }; @@ -768,7 +763,6 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message } case 'association.take': case 'flow.take': - case 'flow.discard': return inboundQ.queueMessage(fields, (0, _messageHelper.cloneContent)(content), properties); } }; @@ -972,7 +966,7 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, switch (routingKey) { case 'execution.outbound.take': { - return this._doOutbound(message, false, (err, outbound) => { + return this._doOutbound(message, (err, outbound) => { message.ack(); if (err) return this.emitFatal(err, content); broker.publish('run', 'run.execute.passthrough', (0, _messageHelper.cloneContent)(content, { @@ -1027,13 +1021,13 @@ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOut properties } = message; const correlationId = properties.correlationId; - if (content.ignoreOutbound) { + if (isDiscarded || content.ignoreOutbound) { this.broker.publish('run', 'run.leave', (0, _messageHelper.cloneContent)(content), { correlationId }); return onOutbound(); } - return this._doOutbound((0, _messageHelper.cloneMessage)(message), isDiscarded, (err, outbound) => { + return this._doOutbound((0, _messageHelper.cloneMessage)(message), (err, outbound) => { if (err) { return this._publishEvent('error', { ...content, @@ -1054,16 +1048,12 @@ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOut }; /** @internal */ -Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) { +Activity.prototype._doOutbound = function doOutbound(fromMessage, callback) { const outboundSequenceFlows = this[K_FLOWS].outboundSequenceFlows; if (!outboundSequenceFlows.length) return callback(null, []); const fromContent = fromMessage.content; let outboundFlows; - if (isDiscarded) { - outboundFlows = outboundSequenceFlows.map(flow => (0, _outboundEvaluator.formatFlowAction)(flow, { - action: 'discard' - })); - } else if (fromContent.outbound?.length) { + if (fromContent.outbound?.length) { outboundFlows = outboundSequenceFlows.map(flow => (0, _outboundEvaluator.formatFlowAction)(flow, fromContent.outbound.filter(f => f.id === flow.id).pop())); } if (outboundFlows) { diff --git a/dist/flows/SequenceFlow.js b/dist/flows/SequenceFlow.js index be643251..67953109 100644 --- a/dist/flows/SequenceFlow.js +++ b/dist/flows/SequenceFlow.js @@ -87,8 +87,9 @@ SequenceFlow.prototype.take = function take(content) { }; /** - * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits - * flow.looped instead when the target id is already in the sequence. + * Discard the flow and publish flow.discard. + * + * @deprecated The execution runtime no longer discards sequence flows, so this is a no-op during a run. It will be removed in a future version. * @param {Record} [content] */ SequenceFlow.prototype.discard = function discard(content = {}) { diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 8c7188e2..9feb906d 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -37,8 +37,7 @@ function ParallelGateway(activityDef, context) { const cachedPeers = context.getShakenPeers(id); if (cachedPeers) { for (const [flowId, sourceIds] of cachedPeers) { - let peer = peers.get(flowId); - if (!peer) peers.set(flowId, peer = new Set()); + const peer = peers.get(flowId); for (const sourceId of sourceIds) peer.add(sourceId); } activity[K_PEERS_DISCOVERED] = true; @@ -162,19 +161,15 @@ ParallelGatewayBehaviour.prototype._onPeerEnterMessage = function onPeerEnterMes if (peer) this.peerMonitor.running.set(message.content.id, peer); }; ParallelGatewayBehaviour.prototype._complete = function complete() { - const take = this.peerMonitor.inbound.some(({ - action - }) => action === 'take'); this.broker.cancel('_converging-inbound', false); this._stop(); - const state = take ? 'completed' : 'discard'; - this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring with state: ${state}`); + this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring`); const content = (0, _messageHelper.cloneContent)(this[_constants.K_EXECUTE_MESSAGE].content, { isRootScope: true, - state + state: 'completed' }); content.inbound = this.peerMonitor.inbound; - return this.broker.publish('execution', `execute.${state}`, content); + return this.broker.publish('execution', 'execute.completed', content); }; ParallelGatewayBehaviour.prototype._stop = function stop() { this.broker.cancel('_converging-inbound'); diff --git a/dist/messageHelper.js b/dist/messageHelper.js index 4d441148..1f300aef 100644 --- a/dist/messageHelper.js +++ b/dist/messageHelper.js @@ -17,7 +17,6 @@ exports.unshiftParent = unshiftParent; */ function cloneContent(content, extend) { const { - discardSequence, inbound, outbound, parent, @@ -32,9 +31,6 @@ function cloneContent(content, extend) { if (parent) { clone.parent = cloneParent(parent); } - if (discardSequence) { - clone.discardSequence = discardSequence.slice(); - } if (inbound) { clone.inbound = inbound.map(c => cloneContent(c)); } diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index 4af063e6..cc1d0982 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -712,7 +712,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, if (!prevMsg) return message.ack(); break; } - case 'flow.looped': case 'activity.leave': return this._onChildCompleted(message); } diff --git a/src/activity/Activity.js b/src/activity/Activity.js index 5f0f9ac8..018916c6 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -428,7 +428,7 @@ Activity.prototype.resume = function resume() { }; /** - * Discard the activity. Stops execution if running and discards outbound flows. + * Discard the activity. Stops execution if running; the activity leaves without taking any outbound flow. * @param {Record} [discardContent] Optional content propagated with the discard * @returns {void} */ @@ -677,12 +677,8 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { message: content.message, inbound, }); - case 'flow.discard': case 'activity.discard': { - let discardSequence; - if (content.discardSequence) discardSequence = content.discardSequence.slice(); - const context = { inbound, discardSequence }; - return this[K_FLAGS].isParallelGateway ? this.run(context) : this._runDiscard(context); + return this._runDiscard({ inbound }); } } }; @@ -721,7 +717,6 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message } case 'association.take': case 'flow.take': - case 'flow.discard': return inboundQ.queueMessage(fields, cloneContent(content), properties); } }; @@ -918,7 +913,7 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, switch (routingKey) { case 'execution.outbound.take': { - return this._doOutbound(message, false, (err, outbound) => { + return this._doOutbound(message, (err, outbound) => { message.ack(); if (err) return this.emitFatal(err, content); broker.publish('run', 'run.execute.passthrough', cloneContent(content, { outbound })); @@ -958,12 +953,12 @@ Activity.prototype._ackRunExecuteMessage = function ackRunExecuteMessage() { Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOutbound) { const { content, properties } = message; const correlationId = properties.correlationId; - if (content.ignoreOutbound) { + if (isDiscarded || content.ignoreOutbound) { this.broker.publish('run', 'run.leave', cloneContent(content), { correlationId }); return onOutbound(); } - return this._doOutbound(cloneMessage(message), isDiscarded, (err, outbound) => { + return this._doOutbound(cloneMessage(message), (err, outbound) => { if (err) { return this._publishEvent('error', { ...content, error: err }, { correlationId }); } @@ -982,16 +977,14 @@ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOut }; /** @internal */ -Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) { +Activity.prototype._doOutbound = function doOutbound(fromMessage, callback) { const outboundSequenceFlows = this[K_FLOWS].outboundSequenceFlows; if (!outboundSequenceFlows.length) return callback(null, []); const fromContent = fromMessage.content; let outboundFlows; - if (isDiscarded) { - outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, { action: 'discard' })); - } else if (fromContent.outbound?.length) { + if (fromContent.outbound?.length) { outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, fromContent.outbound.filter((f) => f.id === flow.id).pop())); } diff --git a/src/flows/SequenceFlow.js b/src/flows/SequenceFlow.js index d2c288df..e1305e42 100644 --- a/src/flows/SequenceFlow.js +++ b/src/flows/SequenceFlow.js @@ -68,8 +68,9 @@ SequenceFlow.prototype.take = function take(content) { }; /** - * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits - * flow.looped instead when the target id is already in the sequence. + * Discard the flow and publish flow.discard. + * + * @deprecated The execution runtime no longer discards sequence flows, so this is a no-op during a run. It will be removed in a future version. * @param {Record} [content] */ SequenceFlow.prototype.discard = function discard(content = {}) { diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index 363e9a41..731e8d3f 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -177,20 +177,16 @@ ParallelGatewayBehaviour.prototype._onPeerEnterMessage = function onPeerEnterMes }; ParallelGatewayBehaviour.prototype._complete = function complete() { - const take = this.peerMonitor.inbound.some(({ action }) => action === 'take'); - this.broker.cancel('_converging-inbound', false); this._stop(); - const state = take ? 'completed' : 'discard'; - - this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring with state: ${state}`); + this.activity.logger.debug(`<${this.executionId} (${this.id})> completed monitoring`); - const content = cloneContent(this[K_EXECUTE_MESSAGE].content, { isRootScope: true, state }); + const content = cloneContent(this[K_EXECUTE_MESSAGE].content, { isRootScope: true, state: 'completed' }); content.inbound = this.peerMonitor.inbound; - return this.broker.publish('execution', `execute.${state}`, content); + return this.broker.publish('execution', 'execute.completed', content); }; ParallelGatewayBehaviour.prototype._stop = function stop() { diff --git a/src/messageHelper.js b/src/messageHelper.js index dcf81196..93d5372d 100644 --- a/src/messageHelper.js +++ b/src/messageHelper.js @@ -5,7 +5,7 @@ * @returns cloned content */ export function cloneContent(content, extend) { - const { discardSequence, inbound, outbound, parent, sequence } = content; + const { inbound, outbound, parent, sequence } = content; /** @type {import('#types').ElementMessageContent} */ const clone = { @@ -16,9 +16,6 @@ export function cloneContent(content, extend) { if (parent) { clone.parent = cloneParent(parent); } - if (discardSequence) { - clone.discardSequence = discardSequence.slice(); - } if (inbound) { clone.inbound = inbound.map((c) => cloneContent(c)); } diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 42ca5e09..3d724b17 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -710,7 +710,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, if (!prevMsg) return message.ack(); break; } - case 'flow.looped': case 'activity.leave': return this._onChildCompleted(message); } diff --git a/test/activities-test.js b/test/activities-test.js index 5a305691..a833e884 100644 --- a/test/activities-test.js +++ b/test/activities-test.js @@ -887,7 +887,7 @@ describe('activity', () => { const stopped = activity.waitFor('stop'); activity.activate(); - activity.inbound[0].discard(); + activity.discard(); await stopped; @@ -929,7 +929,7 @@ describe('activity', () => { const stopped = activity.waitFor('stop'); activity.activate(); - activity.inbound[0].discard(); + activity.discard(); await stopped; @@ -992,7 +992,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('discards if inbound discarded', async function discards() { + it('ignores a discarded inbound', function discards() { if (activityType === 'bpmn:ParallelGateway') return this.skip(); const messages = []; @@ -1006,17 +1006,11 @@ describe('activity', () => { { noAck: true } ); - const completed = activity.waitFor('leave'); - activity.activate(); activity.inbound[0].discard(); - await completed; - - const assertMessage = AssertMessage(context, messages, true); - assertMessage('activity.discard'); - assertMessage('activity.leave'); - expect(messages, 'no more messages').to.have.length(0); + expect(messages, 'no activity messages').to.have.length(0); + expect(activity.counters).to.deep.include({ taken: 0, discarded: 0 }); }); }); }); @@ -1062,7 +1056,7 @@ describe('activity', () => { expect(messages, 'no more messages').to.have.length(0); }); - it('discards if first inbound discarded', async () => { + it('ignores a discarded first inbound', () => { const messages = []; activity.broker.subscribeTmp( 'event', @@ -1074,17 +1068,11 @@ describe('activity', () => { { noAck: true } ); - const completed = activity.waitFor('leave'); - activity.activate(); activity.inbound[0].discard(); - await completed; - - const assertMessage = AssertMessage(context, messages, true); - assertMessage('activity.discard'); - assertMessage('activity.leave'); - expect(messages, 'no more messages').to.have.length(0); + expect(messages, 'no activity messages').to.have.length(0); + expect(activity.counters).to.deep.include({ taken: 0, discarded: 0 }); }); }); }); diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index ac3732c1..2d1dc35e 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -238,7 +238,7 @@ describe('Activity', () => { expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); }); - it('publishes activity discard with discarded flow', () => { + it('ignores a discarded inbound flow', () => { const sequenceFlows = []; const context = getContext({ getInboundSequenceFlows() { @@ -270,13 +270,8 @@ describe('Activity', () => { sequenceFlow.discard(); - expect(message).to.be.ok; - expect(message.content.inbound).to.have.length(1); - expect(message.content.inbound[0]).to.include({ - id: 'flow', - type: 'sequenceflow', - action: 'discard', - }); + expect(message, 'no activity.discard').to.not.be.ok; + expect(activity.counters).to.have.property('discarded', 0); expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); }); @@ -388,7 +383,7 @@ describe('Activity', () => { expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); }); - it('postponed activity starts next run when first two were discarded', () => { + it('postponed activity starts run on taken inbound, ignoring earlier discards', () => { const sequenceFlows = []; const context = getContext({ getInboundSequenceFlows() { @@ -430,7 +425,7 @@ describe('Activity', () => { expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); }); - it('discards next run when completed with first', () => { + it('ignores discarded inbound after completing with first', () => { const sequenceFlows = []; const context = getContext({ getInboundSequenceFlows() { @@ -461,7 +456,7 @@ describe('Activity', () => { sequenceFlow.discard(); expect(activity.counters).to.have.property('taken', 1); - expect(activity.counters).to.have.property('discarded', 3); + expect(activity.counters).to.have.property('discarded', 0); }); it('forwards message from inbound to execution', () => { @@ -865,29 +860,22 @@ describe('Activity', () => { await leave; }); - it('next run can be discarded by discard', async () => { + it('running activity can be discarded by discard', () => { const activity = getActivity(undefined, behaviours.Behaviour); activity.activate(); - const leave = activity.waitFor('leave'); - - activity.inbound[0].discard(); activity.inbound[0].take(); - await leave; - expect(activity).to.have.property('status', 'executing'); - expect(activity.counters).to.have.property('discarded', 1); - expect(activity.broker.getExchange('api')).to.have.property('bindingCount', 2); activity.discard(); - expect(activity.counters).to.have.property('discarded', 2); + expect(activity.counters).to.have.property('discarded', 1); }); - it('next run can be discarded by api', async () => { + it('running activity can be discarded by api', () => { let executeMessage; function SpecialBehaviour() { return { @@ -900,21 +888,14 @@ describe('Activity', () => { activity.activate(); - const leave = activity.waitFor('leave'); - - activity.inbound[0].discard(); activity.inbound[0].take(); - await leave; - expect(activity).to.have.property('status', 'executing'); - expect(activity.counters).to.have.property('discarded', 1); - expect(activity.broker.getExchange('api')).to.have.property('bindingCount', 2); activity.getApi(executeMessage).discard(); - expect(activity.counters).to.have.property('discarded', 2); + expect(activity.counters).to.have.property('discarded', 1); }); }); @@ -988,20 +969,14 @@ describe('Activity', () => { expect(activity.broker.consumerCount, 'no consumers').to.equal(0); }); - it('next run can be stopped', async () => { + it('running activity can be stopped', () => { const activity = getActivity(undefined, behaviours.Behaviour); activity.activate(); - const leave = activity.waitFor('leave'); - - activity.inbound[0].discard(); activity.inbound[0].take(); - await leave; - expect(activity).to.have.property('status', 'executing'); - expect(activity.counters).to.have.property('discarded', 1); expect(activity.broker.getExchange('api')).to.have.property('bindingCount', 2); @@ -1012,7 +987,7 @@ describe('Activity', () => { expect(activity.broker.getQueue('format-run-q')).to.have.property('consumerCount', 0); }); - it('next run can be stopped by api', async () => { + it('running activity can be stopped by api', () => { let executeMessage; function SpecialBehaviour() { return { @@ -1025,15 +1000,9 @@ describe('Activity', () => { activity.activate(); - const leave = activity.waitFor('leave'); - - activity.inbound[0].discard(); activity.inbound[0].take(); - await leave; - expect(activity).to.have.property('status', 'executing'); - expect(activity.counters).to.have.property('discarded', 1); expect(activity.broker.getExchange('api')).to.have.property('bindingCount', 2); @@ -1711,7 +1680,7 @@ describe('Activity', () => { expect(activity.broker.getQueue('inbound-q')).to.have.property('messageCount', 0); }); - it('discards activity with discard sequence if attachedTo is discarded', () => { + it('discards activity if attachedTo is discarded', () => { const attachedTo = { id: 'task', parent: { @@ -1750,11 +1719,10 @@ describe('Activity', () => { message = msg; }); - attachedTo.broker.publish('event', 'activity.discard', { id: 'task', type: 'bpmn:ServiceTask', discardSequence: ['start'] }); + attachedTo.broker.publish('event', 'activity.discard', { id: 'task', type: 'bpmn:ServiceTask' }); expect(message).to.be.ok; expect(message.content.inbound).to.have.length(1); - expect(message.content.discardSequence).to.eql(['start']); expect(message.content.inbound[0]).to.include({ id: 'task', type: 'bpmn:ServiceTask', diff --git a/test/events/BoundaryEvent-test.js b/test/events/BoundaryEvent-test.js index 9dcc908a..104cfa21 100644 --- a/test/events/BoundaryEvent-test.js +++ b/test/events/BoundaryEvent-test.js @@ -864,7 +864,7 @@ describe('BoundaryEvent', () => { event.activate(); task.activate(); - task.inbound[0].discard(); + task.discard(); await leave; @@ -1019,7 +1019,7 @@ describe('BoundaryEvent', () => { event.activate(); task.activate(); - task.inbound[0].discard(); + task.discard(); await leave; @@ -1118,7 +1118,7 @@ describe('BoundaryEvent', () => { event.activate(); task.activate(); - task.inbound[0].discard(); + task.discard(); await leave; @@ -1220,7 +1220,7 @@ describe('BoundaryEvent', () => { event.activate(); task.activate(); - task.inbound[0].discard(); + task.discard(); await leave; @@ -1319,7 +1319,7 @@ describe('BoundaryEvent', () => { expect(task.counters).to.have.property('taken', 1); }); - it('is discarded if attached inbound is discarded', async () => { + it('is discarded when attached is discarded', async () => { const task = context.getActivityById('service'); const event = context.getActivityById('conditionalEvent'); @@ -1327,7 +1327,7 @@ describe('BoundaryEvent', () => { event.activate(); task.activate(); - task.inbound[0].discard(); + task.discard(); await leave; diff --git a/test/events/EndEvent-test.js b/test/events/EndEvent-test.js index 30e0db00..a836f034 100644 --- a/test/events/EndEvent-test.js +++ b/test/events/EndEvent-test.js @@ -112,7 +112,7 @@ describe('EndEvent', () => { }); describe('with multiple inbounds', () => { - it('publish enter or discard on each inbound', () => { + it('publishes enter only on taken inbound, ignoring discarded inbound', () => { const parent = { id: 'process' }; const context = testHelpers.emptyContext({ getInboundSequenceFlows() { @@ -170,17 +170,13 @@ describe('EndEvent', () => { context.getInboundSequenceFlows()[2].discard(); expect(event.counters).to.have.property('taken', 1); - expect(event.counters).to.have.property('discarded', 2); + expect(event.counters).to.have.property('discarded', 0); - expect(messages).to.have.length(3); + expect(messages).to.have.length(1); expect(messages[0].content).to.have.property('inbound').with.length(1); - expect(messages[0].content.inbound[0]).to.have.property('id', 'flow1'); - expect(messages[0].content.inbound[0]).to.have.property('action', 'discard'); - expect(messages[1].content.inbound[0]).to.have.property('id', 'flow2'); - expect(messages[1].content.inbound[0]).to.have.property('action', 'take'); - expect(messages[2].content.inbound[0]).to.have.property('id', 'flow3'); - expect(messages[2].content.inbound[0]).to.have.property('action', 'discard'); + expect(messages[0].content.inbound[0]).to.have.property('id', 'flow2'); + expect(messages[0].content.inbound[0]).to.have.property('action', 'take'); }); }); }); diff --git a/test/feature/backward-compatability-feature.js b/test/feature/backward-compatability-feature.js index 94ebde1a..2491dc21 100644 --- a/test/feature/backward-compatability-feature.js +++ b/test/feature/backward-compatability-feature.js @@ -5,8 +5,8 @@ import testHelpers from '../helpers/testHelpers.js'; const motherOfAllSource = factory.resource('mother-of-all.bpmn'); -Feature('Backward compatability 5.2', () => { - Scenario('Slimmer state', () => { +Feature('Backward compatability', () => { + Scenario('Slimmer state 5.2', () => { let context; before(async () => { context = await testHelpers.context(motherOfAllSource); @@ -33,4 +33,60 @@ Feature('Backward compatability 5.2', () => { return leave; }); }); + + Scenario('State 17.3', () => { + let context; + before(async () => { + context = await testHelpers.context(motherOfAllSource); + }); + + let definition, state; + Given('a state from version 17.3', async () => { + state = JSON.parse(await fs.readFile('./test/resources/mother-of-all-state-17.3.json')); + }); + + let leave; + When('recovered and resumed with state from version 17.3', () => { + definition = new Definition(context).recover(state); + leave = definition.waitFor('leave'); + definition.resume(); + }); + + And('waiting tasks are signaled', () => { + definition.signal({ id: 'userTask1' }); + definition.signal({ id: 'subUserTask1' }); + }); + + Then('run completes', () => { + return leave; + }); + }); + + Scenario('State 18', () => { + let context; + before(async () => { + context = await testHelpers.context(motherOfAllSource); + }); + + let definition, state; + Given('a state from version 18', async () => { + state = JSON.parse(await fs.readFile('./test/resources/mother-of-all-state-18.json')); + }); + + let leave; + When('recovered and resumed with state from version 18', () => { + definition = new Definition(context).recover(state); + leave = definition.waitFor('leave'); + definition.resume(); + }); + + And('waiting tasks are signaled', () => { + definition.signal({ id: 'userTask1' }); + definition.signal({ id: 'subUserTask1' }); + }); + + Then('run completes', () => { + return leave; + }); + }); }); diff --git a/test/feature/call-activity-feature.js b/test/feature/call-activity-feature.js index 5f11070d..05a70288 100644 --- a/test/feature/call-activity-feature.js +++ b/test/feature/call-activity-feature.js @@ -971,6 +971,46 @@ Feature('Call activity', () => { return end; }); }); + + Scenario('discard a called process that holds an association', () => { + let definition; + Given('a process whose call activity references a process with an annotated task', async () => { + const source = ` + + + + + + + + + + + do the task + + + `; + definition = new Definition(await testHelpers.context(source)); + }); + + let end; + When('ran', () => { + end = definition.waitFor('end'); + definition.run(); + }); + + Then('the call activity started the called process', () => { + expect(definition.getRunningProcesses()).to.have.length(2); + }); + + When('the called process is discarded', () => { + definition.getRunningProcesses()[1].getApi().discard(); + }); + + Then('the run completes, stopping the association along the way', () => { + return end; + }); + }); }); function processOutput(elm) { diff --git a/test/feature/recover-resume-feature.js b/test/feature/recover-resume-feature.js index 1f5447f6..2c1628d6 100644 --- a/test/feature/recover-resume-feature.js +++ b/test/feature/recover-resume-feature.js @@ -339,4 +339,129 @@ Feature('Recover resume', () => { return leave; }); }); + + Scenario('recover a converging parallel gateway with an updated source', () => { + const forkJoinSource = ` + + + + + + + + + + + + + + + + `; + + let context, definition; + Given('a process forking to two user tasks and joining on a parallel gateway', async () => { + context = await testHelpers.context(forkJoinSource); + definition = new Definition(context); + }); + + When('ran', () => { + definition.run(); + }); + + let state; + And('both parallel branches are waiting and state is saved', () => { + expect(definition.getPostponed().map((p) => p.id)).to.have.members(['t1', 't2']); + state = definition.getState(); + definition.stop(); + }); + + let leave; + const waiting = []; + When('recovered and resumed with an updated source that adds a task after the join', async () => { + const updatedSource = forkJoinSource.replace( + '', + ` + + ` + ); + + context = await testHelpers.context(updatedSource); + definition = new Definition(context).recover(state); + + leave = definition.waitFor('leave'); + definition.on('wait', (api) => waiting.push(api.content.id)); + definition.resume(); + }); + + And('both waiting tasks are signalled', () => { + definition.signal({ id: 't1' }); + definition.signal({ id: 't2' }); + }); + + Then('the recovered parallel gateway converges and the run reaches the added task', () => { + expect(definition.getActivityById('join').counters).to.include({ taken: 1 }); + expect(waiting, 'reached the task added in the updated source').to.include('review'); + }); + + When('the added task is signalled', () => { + definition.signal({ id: 'review' }); + }); + + Then('resumed run completes', () => { + return leave; + }); + }); + + Scenario('recover a process whose association is removed in the updated source', () => { + const annotatedSource = ` + + + + + + + + review carefully + + + `; + + let context, definition, state; + Given('a process with a task annotated through an association', async () => { + context = await testHelpers.context(annotatedSource); + definition = new Definition(context); + }); + + When('ran to the waiting task', () => { + definition.run(); + }); + + And('state is saved with the association', () => { + expect(definition.getPostponed().map((p) => p.id)).to.include('task'); + state = definition.getState(); + definition.stop(); + }); + + let leave; + When('recovered and resumed with a source where the annotation and association are removed', async () => { + const strippedSource = annotatedSource + .replace('review carefully', '') + .replace('', ''); + + context = await testHelpers.context(strippedSource); + definition = new Definition(context).recover(state); + + leave = definition.waitFor('leave'); + definition.resume(); + }); + + And('the waiting task is signalled', () => { + definition.signal({ id: 'task' }); + }); + + Then('resumed run completes despite the missing association', () => { + return leave; + }); + }); }); diff --git a/test/feature/signal-feature.js b/test/feature/signal-feature.js index 10f5d8b4..3f6079e3 100644 --- a/test/feature/signal-feature.js +++ b/test/feature/signal-feature.js @@ -1241,6 +1241,42 @@ Feature('Signals', () => { expect(output).to.have.property('namedMessageEvent').with.property('input', 1); }); }); + + Scenario('a thrown signal in a process with a text annotation', () => { + let definition; + Given('a process that throws a signal from an annotated throw event', async () => { + const source = ` + + + + + + + + + + + broadcasts a signal + + + `; + definition = new Definition(await testHelpers.context(source)); + }); + + let leave; + When('ran', () => { + leave = definition.waitFor('leave'); + definition.run(); + }); + + Then('the run completes, delegating the thrown signal past the annotation placeholder', () => { + return leave; + }); + + And('the signal was thrown', () => { + expect(definition.getActivityById('throw').counters).to.include({ taken: 1 }); + }); + }); }); async function prepareSource() { diff --git a/test/gateways/ExclusiveGateway-test.js b/test/gateways/ExclusiveGateway-test.js index 54149ad9..90446fd4 100644 --- a/test/gateways/ExclusiveGateway-test.js +++ b/test/gateways/ExclusiveGateway-test.js @@ -162,16 +162,14 @@ describe('ExclusiveGateway', () => { expect(activity.outbound[1].counters).to.have.property('take', 0); }); - it('discards all outbound if inbound was discarded', async () => { + it('ignores a discarded inbound and takes no outbound', () => { const activity = context.getActivityById('decision'); activity.activate(); - const leave = activity.waitFor('leave'); activity.inbound[0].discard(); - await leave; - + expect(activity.counters).to.deep.include({ taken: 0, discarded: 0 }); expect(activity.outbound[0].counters).to.have.property('take', 0); expect(activity.outbound[1].counters).to.have.property('take', 0); expect(activity.outbound[2].counters).to.have.property('take', 0); diff --git a/test/gateways/InclusiveGateway-test.js b/test/gateways/InclusiveGateway-test.js index ed3d94fc..af419f50 100644 --- a/test/gateways/InclusiveGateway-test.js +++ b/test/gateways/InclusiveGateway-test.js @@ -99,18 +99,16 @@ describe('InclusiveGateway', () => { expect(activity.outbound[2].counters).to.have.property('discard', 0); }); - it('discards all outbound if inbound was discarded', async () => { + it('ignores a discarded inbound and takes no outbound', () => { const activity = context.getActivityById('decisions'); context.environment.variables.condition1 = true; context.environment.variables.condition2 = true; activity.activate(); - const leave = activity.waitFor('leave'); activity.inbound[0].discard(); - await leave; - + expect(activity.counters).to.deep.include({ taken: 0, discarded: 0 }); expect(activity.outbound[0].counters).to.have.property('take', 0); expect(activity.outbound[1].counters).to.have.property('take', 0); expect(activity.outbound[2].counters).to.have.property('take', 0); diff --git a/test/gateways/ParallelGateway-test.js b/test/gateways/ParallelGateway-test.js index ee118087..8dc71264 100644 --- a/test/gateways/ParallelGateway-test.js +++ b/test/gateways/ParallelGateway-test.js @@ -39,21 +39,16 @@ describe('ParallelGateway', () => { expect(activity.outbound[1].counters).to.have.property('discard', 0); }); - it('leaves without taking any outbound if inbound was discarded', async () => { + it('ignores a discarded inbound and takes no outbound', () => { const activity = context.getActivityById('fork'); activity.activate(); - const leave = activity.waitFor('leave'); activity.inbound[0].discard(); - await leave; - - expect(activity.counters).to.deep.equal({ taken: 0, discarded: 1 }); - expect(activity.outbound[0].counters).to.have.property('take', 0); - expect(activity.outbound[0].counters).to.have.property('discard', 0); - expect(activity.outbound[1].counters).to.have.property('take', 0); - expect(activity.outbound[1].counters).to.have.property('discard', 0); + expect(activity.counters).to.deep.include({ taken: 0, discarded: 0 }); + expect(activity.outbound[0].counters).to.include({ take: 0, discard: 0 }); + expect(activity.outbound[1].counters).to.include({ take: 0, discard: 0 }); }); }); @@ -170,20 +165,16 @@ describe('ParallelGateway', () => { expect(outboundFlow.counters).to.have.property('discard', 0); }); - it('leaves without taking outbound if one inbound were discarded', async () => { + it('ignores a discarded inbound and takes no outbound', () => { const activity = context.getActivityById('join'); activity.activate(); - const leave = activity.waitFor('leave'); activity.inbound[0].discard(); - await leave; - - expect(activity.counters).to.deep.equal({ taken: 0, discarded: 1 }); + expect(activity.counters).to.deep.include({ taken: 0, discarded: 0 }); const outboundFlow = activity.outbound[0]; - expect(outboundFlow.counters).to.have.property('discard', 0); - expect(outboundFlow.counters).to.have.property('take', 0); + expect(outboundFlow.counters).to.include({ take: 0, discard: 0 }); }); it('takes outbound if one inbound is taken', async () => { diff --git a/test/resources/activity-lifecycle.bpmn b/test/resources/activity-lifecycle.bpmn index 9fbd1022..fa2ab1b1 100644 --- a/test/resources/activity-lifecycle.bpmn +++ b/test/resources/activity-lifecycle.bpmn @@ -1,5 +1,5 @@ - + @@ -46,8 +46,8 @@ toEnd - - + + isDiscarded Flow_0qy9l2f @@ -82,7 +82,7 @@ toTakeOutbound fromTakeOutbound - + Flow_0qy9l2f Flow_0jt910d fromDiscardOutbound @@ -138,6 +138,10 @@ + + + + @@ -159,16 +163,14 @@ + + + + - - - - - - @@ -223,12 +225,12 @@ - + - + @@ -260,15 +262,15 @@ + + + + - - - - diff --git a/test/resources/mother-of-all-state-17.3.json b/test/resources/mother-of-all-state-17.3.json new file mode 100644 index 00000000..6e7cab83 --- /dev/null +++ b/test/resources/mother-of-all-state-17.3.json @@ -0,0 +1,4442 @@ +{ + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88", + "status": "executing", + "stopped": false, + "counters": { + "completed": 0, + "discarded": 0 + }, + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": {}, + "output": {} + }, + "execution": { + "executionId": "Definitions_1_fb4323ec88", + "stopped": false, + "completed": false, + "status": "start", + "processes": [ + { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70", + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_process-run" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions" + } + }, + "properties": { + "messageId": "smq.mid-ae25061aa5", + "timestamp": 1781240158944 + }, + "stopLoop": true + }, + "output": {} + }, + "status": "executing", + "stopped": false, + "counters": { + "completed": 0, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_process-run" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions" + } + }, + "properties": { + "messageId": "smq.mid-ae25061aa5", + "timestamp": 1781240158944 + } + } + ] + }, + { + "name": "execute-motherOfAll_8cfc8dea70-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "activity.init", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_7e3d5f3b78", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isStart": true, + "state": "init" + }, + "properties": { + "persistent": true, + "type": "init", + "mandatory": false, + "messageId": "smq.mid-3ae195c472", + "timestamp": 1781240158947 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_7e3d5f3b78", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isStart": true, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-432b28876d", + "timestamp": 1781240158948 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_7e3d5f3b78", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isStart": true, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-0cfe43e8f6", + "timestamp": 1781240158948 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_7e3d5f3b78", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isStart": true, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-112b8985ab", + "timestamp": 1781240158948, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_7e3d5f3b78", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isStart": true, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-428f9bb6d3", + "timestamp": 1781240158949 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_7e3d5f3b78", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_4573e31a75", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-33df1160fe", + "timestamp": 1781240158949 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_7e3d5f3b78", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_4573e31a75", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_55191c4e0d", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-820cabe31d", + "timestamp": 1781240158949 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_7e3d5f3b78", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_4573e31a75", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_55191c4e0d", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-a67bfe3d27", + "timestamp": 1781240158949 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_7e3d5f3b78", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_4573e31a75", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_55191c4e0d", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-b2ec71df48", + "timestamp": 1781240158950, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_7e3d5f3b78", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_4573e31a75", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_55191c4e0d", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-091f2e20bd", + "timestamp": 1781240158950 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_45d24bac88", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-aa28dec914", + "timestamp": 1781240158950 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_45d24bac88", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bdf5b8c729", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-ef8736c756", + "timestamp": 1781240158950 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_45d24bac88", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bdf5b8c729", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-9a1397fba8", + "timestamp": 1781240158950 + } + }, + { + "fields": { + "routingKey": "activity.wait", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_45d24bac88", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bdf5b8c729", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "wait", + "isRootScope": true + }, + "properties": { + "persistent": true, + "messageId": "smq.mid-8131dc5714", + "timestamp": 1781240158950 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_45d24bac88", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bdf5b8c729", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "correlationId": "userTask1_signal_688539dc2b", + "messageId": "smq.mid-cdcb500fd3", + "timestamp": 1781240158951, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_45d24bac88", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bdf5b8c729", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "correlationId": "userTask1_signal_688539dc2b", + "type": "end", + "mandatory": false, + "messageId": "smq.mid-1aac38cb80", + "timestamp": 1781240158951 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b7a22ffb16", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-569f953f37", + "timestamp": 1781240158951 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b7a22ffb16", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "subProcess1_7acdf25adc", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isSubProcess": true, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-5725e91f06", + "timestamp": 1781240158951 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b7a22ffb16", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "subProcess1_7acdf25adc", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isSubProcess": true, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-3383ba4f0b", + "timestamp": 1781240158951 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b7a22ffb16", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "subProcess1_7acdf25adc", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isSubProcess": true, + "state": "execution.completed", + "isRootScope": true, + "output": {} + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-2eada7d000", + "timestamp": 1781240158958, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b7a22ffb16", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "subProcess1_7acdf25adc", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isSubProcess": true, + "state": "end", + "isRootScope": true, + "output": {} + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-8014e222d2", + "timestamp": 1781240158958 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "subProcess1_7acdf25adc", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_040aa3dd87", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-aa8a66d4e9", + "timestamp": 1781240158958 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_7acdf25adc", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_040aa3dd87", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "manyDecisions_96a1bd864b", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-b0259c0c7b", + "timestamp": 1781240158958 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_7acdf25adc", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_040aa3dd87", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "manyDecisions_96a1bd864b", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-2a13abb6aa", + "timestamp": 1781240158959 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_7acdf25adc", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_040aa3dd87", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "manyDecisions_96a1bd864b", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-7e40ff934e", + "timestamp": 1781240158959, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_7acdf25adc", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_040aa3dd87", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "manyDecisions_96a1bd864b", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-c5ba303d74", + "timestamp": 1781240158959 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_151c412361", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-3e34ce4637", + "timestamp": 1781240158959 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_151c412361", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "noPickMeTask_9e7c06bc8c", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-6f62ccc866", + "timestamp": 1781240158959 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_151c412361", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "noPickMeTask_9e7c06bc8c", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-55bd72be0d", + "timestamp": 1781240158959 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_151c412361", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "noPickMeTask_9e7c06bc8c", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-f88b976b00", + "timestamp": 1781240158959, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_151c412361", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "noPickMeTask_9e7c06bc8c", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-70a91b629f", + "timestamp": 1781240158959 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_9e7c06bc8c", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_4dc9137702", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-16b0c9579f", + "timestamp": 1781240158959 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_151c412361", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "noPickMeTask_9e7c06bc8c", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_9e7c06bc8c", + "id": "toJoin1", + "targetId": "join" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-94a6ae7386", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_7fae727cb3", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-f9e55abccc", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_7fae727cb3", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "pickMeTask_a733ccb3c2", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-21784d0f83", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_7fae727cb3", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "pickMeTask_a733ccb3c2", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-614851b1cb", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_7fae727cb3", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "pickMeTask_a733ccb3c2", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-63745400b0", + "timestamp": 1781240158960, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_7fae727cb3", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "pickMeTask_a733ccb3c2", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-dd2e05d943", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_a733ccb3c2", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_9b5c9aa964", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-cbd43f61d4", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_7fae727cb3", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "pickMeTask_a733ccb3c2", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_a733ccb3c2", + "id": "toJoin3", + "targetId": "join" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-729e3097fc", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "flow.discard", + "exchange": "event" + }, + "content": { + "action": "discard", + "id": "toPickMe2", + "targetId": "defaultTask", + "isDefault": true, + "sequenceId": "toPickMe2_discard_131f1f3f52", + "discardSequence": ["manyDecisions"], + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "discard", + "messageId": "smq.mid-0c2ab8cd15", + "timestamp": 1781240158960 + } + }, + { + "fields": { + "routingKey": "activity.discard", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "discard", + "id": "toPickMe2", + "targetId": "defaultTask", + "isDefault": true, + "sequenceId": "toPickMe2_discard_131f1f3f52", + "discardSequence": ["manyDecisions"], + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "discardSequence": ["manyDecisions"], + "executionId": "defaultTask_c30bad97c7", + "id": "defaultTask", + "type": "bpmn:Task", + "name": "Default task", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "discard" + }, + "properties": { + "persistent": true, + "type": "discard", + "mandatory": false, + "messageId": "smq.mid-450a3ad5e6", + "timestamp": 1781240158961 + } + }, + { + "fields": { + "routingKey": "flow.discard", + "exchange": "event" + }, + "content": { + "action": "discard", + "id": "toJoin2", + "targetId": "join", + "sequenceId": "toJoin2_discard_13eeb30cfd", + "discardSequence": ["manyDecisions", "defaultTask"], + "type": "bpmn:SequenceFlow", + "sourceId": "defaultTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "discard", + "messageId": "smq.mid-ff4569404c", + "timestamp": 1781240158961 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_9e7c06bc8c", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_4dc9137702", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_a733ccb3c2", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_9b5c9aa964", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "discard", + "id": "toJoin2", + "targetId": "join", + "sequenceId": "toJoin2_discard_13eeb30cfd", + "discardSequence": ["manyDecisions", "defaultTask"], + "type": "bpmn:SequenceFlow", + "sourceId": "defaultTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "join_9b95444db0", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isParallelJoin": true, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-3275d4d710", + "timestamp": 1781240158961 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_9e7c06bc8c", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_4dc9137702", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_a733ccb3c2", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_9b5c9aa964", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "discard", + "id": "toJoin2", + "targetId": "join", + "sequenceId": "toJoin2_discard_13eeb30cfd", + "discardSequence": ["manyDecisions", "defaultTask"], + "type": "bpmn:SequenceFlow", + "sourceId": "defaultTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "join_9b95444db0", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isParallelJoin": true, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-7ca3f8e907", + "timestamp": 1781240158961 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_9e7c06bc8c", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_4dc9137702", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_a733ccb3c2", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_9b5c9aa964", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "discard", + "id": "toJoin2", + "targetId": "join", + "sequenceId": "toJoin2_discard_13eeb30cfd", + "discardSequence": ["manyDecisions", "defaultTask"], + "type": "bpmn:SequenceFlow", + "sourceId": "defaultTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "join_9b95444db0", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isParallelJoin": true, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-1931d3fdfc", + "timestamp": 1781240158961, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_9e7c06bc8c", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_4dc9137702", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_a733ccb3c2", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_9b5c9aa964", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "discard", + "id": "toJoin2", + "targetId": "join", + "sequenceId": "toJoin2_discard_13eeb30cfd", + "discardSequence": ["manyDecisions", "defaultTask"], + "type": "bpmn:SequenceFlow", + "sourceId": "defaultTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "join_9b95444db0", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isParallelJoin": true, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-6be3477618", + "timestamp": 1781240158961 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "join_9b95444db0", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_2915900117", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-86bd39ff84", + "timestamp": 1781240158961 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_9b95444db0", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_2915900117", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "decision_34a894b32a", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-1fe16fb7e4", + "timestamp": 1781240158961 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_9b95444db0", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_2915900117", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "decision_34a894b32a", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-acd6c706b0", + "timestamp": 1781240158962 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_9b95444db0", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_2915900117", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "decision_34a894b32a", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true, + "outboundTakeOne": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-8ad714ecec", + "timestamp": 1781240158962, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_9b95444db0", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_2915900117", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "decision_34a894b32a", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true, + "outboundTakeOne": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-9053fe6328", + "timestamp": 1781240158962 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "decision_34a894b32a", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_3afd0c7d6d", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-7e9cef027c", + "timestamp": 1781240158962 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_34a894b32a", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_3afd0c7d6d", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask2_953981ed13", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-4bc97158e8", + "timestamp": 1781240158962 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_34a894b32a", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_3afd0c7d6d", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask2_953981ed13", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-5dbe94b119", + "timestamp": 1781240158962 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_34a894b32a", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_3afd0c7d6d", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask2_953981ed13", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-8b5030fb4c", + "timestamp": 1781240158963, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_34a894b32a", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_3afd0c7d6d", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask2_953981ed13", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-c85d1066a8", + "timestamp": 1781240158963 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_953981ed13", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_b5e3dbc995", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-fdcfde4538", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_34a894b32a", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_3afd0c7d6d", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask2_953981ed13", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_953981ed13", + "id": "toReturnScriptTask", + "targetId": "scriptTask1" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-eda857313a", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "flow.discard", + "exchange": "event" + }, + "content": { + "action": "discard", + "id": "toFinal", + "targetId": "theEnd", + "isDefault": true, + "sequenceId": "toFinal_discard_f899bf57dd", + "discardSequence": ["decision"], + "type": "bpmn:SequenceFlow", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "discard", + "messageId": "smq.mid-32cde91a17", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.discard", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "discard", + "id": "toFinal", + "targetId": "theEnd", + "isDefault": true, + "sequenceId": "toFinal_discard_f899bf57dd", + "discardSequence": ["decision"], + "type": "bpmn:SequenceFlow", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "discardSequence": ["decision"], + "executionId": "theEnd_c6290f7c94", + "id": "theEnd", + "type": "bpmn:EndEvent", + "name": "Final", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isEnd": true, + "isThrowing": true, + "state": "discard" + }, + "properties": { + "persistent": true, + "type": "discard", + "mandatory": false, + "messageId": "smq.mid-4af96dc0a2", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "discard", + "id": "toFinal", + "targetId": "theEnd", + "isDefault": true, + "sequenceId": "toFinal_discard_f899bf57dd", + "discardSequence": ["decision"], + "type": "bpmn:SequenceFlow", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "discardSequence": ["decision"], + "executionId": "theEnd_c6290f7c94", + "id": "theEnd", + "type": "bpmn:EndEvent", + "name": "Final", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isEnd": true, + "isThrowing": true, + "state": "leave" + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-5fcb927e3f", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_9b95444db0", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_2915900117", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "decision_34a894b32a", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "leave", + "isRootScope": true, + "outboundTakeOne": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_34a894b32a", + "id": "toLoop", + "targetId": "scriptTask2" + }, + { + "action": "discard", + "id": "toFinal", + "targetId": "theEnd", + "isDefault": true + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-12cad473e8", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_9e7c06bc8c", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_4dc9137702", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_a733ccb3c2", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_9b5c9aa964", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + { + "action": "discard", + "id": "toJoin2", + "targetId": "join", + "sequenceId": "toJoin2_discard_13eeb30cfd", + "discardSequence": ["manyDecisions", "defaultTask"], + "type": "bpmn:SequenceFlow", + "sourceId": "defaultTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "join_9b95444db0", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isParallelJoin": true, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_9b95444db0", + "id": "toDecision", + "targetId": "decision" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-decd32335d", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "discard", + "id": "toPickMe2", + "targetId": "defaultTask", + "isDefault": true, + "sequenceId": "toPickMe2_discard_131f1f3f52", + "discardSequence": ["manyDecisions"], + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "discardSequence": ["manyDecisions"], + "executionId": "defaultTask_c30bad97c7", + "id": "defaultTask", + "type": "bpmn:Task", + "name": "Default task", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "outbound": [ + { + "action": "discard", + "id": "toJoin2", + "targetId": "join" + } + ], + "state": "leave" + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-d329ceaff8", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_7acdf25adc", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_040aa3dd87", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "manyDecisions_96a1bd864b", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe1", + "targetId": "noPickMeTask" + }, + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_96a1bd864b", + "id": "toPickMe3", + "targetId": "pickMeTask" + }, + { + "action": "discard", + "id": "toPickMe2", + "targetId": "defaultTask", + "isDefault": true + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-c774d1ec07", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b7a22ffb16", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "subProcess1_7acdf25adc", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "isSubProcess": true, + "state": "leave", + "isRootScope": true, + "output": {}, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_7acdf25adc", + "id": "toInclusiveGateway", + "targetId": "manyDecisions" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-80ca13d5d3", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_45d24bac88", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bdf5b8c729", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1" + } + ] + }, + "properties": { + "persistent": true, + "correlationId": "userTask1_signal_688539dc2b", + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-ea261a3a11", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_7e3d5f3b78", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_4573e31a75", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_55191c4e0d", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_55191c4e0d", + "id": "toFirstUserTask", + "targetId": "userTask1" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-1945d74453", + "timestamp": 1781240158974 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_953981ed13", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_b5e3dbc995", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_3c0ab1af52", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-c80062092c", + "timestamp": 1781240158974 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_953981ed13", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_b5e3dbc995", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_3c0ab1af52", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-8b26fcfd76", + "timestamp": 1781240158974 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_953981ed13", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_b5e3dbc995", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_3c0ab1af52", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-1631903e65", + "timestamp": 1781240158974, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_953981ed13", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_b5e3dbc995", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_3c0ab1af52", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-2d52e51e24", + "timestamp": 1781240158974 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_3c0ab1af52", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_40bbd73f51", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-85d1dcc1a9", + "timestamp": 1781240158974 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_3c0ab1af52", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_40bbd73f51", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bf4f6ff158", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-17920eba56", + "timestamp": 1781240158974 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_3c0ab1af52", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_40bbd73f51", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bf4f6ff158", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-9c80f98c5c", + "timestamp": 1781240158974 + } + } + ] + } + ] + }, + "execution": { + "executionId": "motherOfAll_8cfc8dea70", + "stopped": false, + "completed": false, + "status": "executing", + "children": [ + { + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "status": "end", + "executionId": "StartEvent_1_7e3d5f3b78", + "counters": { + "taken": 1, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.leave", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "executionId": "StartEvent_1_7e3d5f3b78", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "isStart": true, + "state": "completed", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_7e3d5f3b78", + "id": "toFirstScriptTask", + "targetId": "scriptTask1" + } + ] + }, + "properties": { + "messageId": "smq.mid-ad5ee1dd60", + "timestamp": 1781240158949 + } + } + ] + } + ] + }, + "execution": { + "completed": true + } + }, + { + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "status": "end", + "executionId": "scriptTask1_3c0ab1af52", + "counters": { + "taken": 2, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.leave", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_953981ed13", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_b5e3dbc995", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "scriptTask1_3c0ab1af52", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "state": "completed", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_3c0ab1af52", + "id": "toFirstUserTask", + "targetId": "userTask1" + } + ] + }, + "properties": { + "messageId": "smq.mid-f3e9df900c", + "timestamp": 1781240158974 + } + } + ] + } + ] + }, + "execution": { + "completed": true + } + }, + { + "id": "userTask1", + "type": "bpmn:UserTask", + "status": "executing", + "executionId": "userTask1_bf4f6ff158", + "counters": { + "taken": 1, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_3c0ab1af52", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_40bbd73f51", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bf4f6ff158", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + } + }, + "properties": { + "messageId": "smq.mid-e60e211436", + "timestamp": 1781240158974 + } + } + ] + }, + { + "name": "execute-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "execute.start", + "exchange": "execution", + "consumerTag": "_activity-execute" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_3c0ab1af52", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_40bbd73f51", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "userTask1_bf4f6ff158", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "state": "start", + "isRootScope": true + }, + "properties": { + "messageId": "smq.mid-99fbe5f393", + "timestamp": 1781240158974 + } + } + ] + } + ] + }, + "execution": { + "completed": false + } + }, + { + "id": "subProcess1", + "type": "bpmn:SubProcess", + "executionId": "subProcess1_7acdf25adc", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true, + "executionId": "subProcess1_7acdf25adc", + "stopped": false, + "status": "completed", + "children": [ + { + "id": "subUserTask1", + "type": "bpmn:UserTask", + "executionId": "subUserTask1_8e7fc37ded", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "subUserTaskTimer", + "type": "bpmn:BoundaryEvent", + "executionId": "subUserTaskTimer_240306a315", + "counters": { + "taken": 0, + "discarded": 1 + }, + "execution": { + "completed": true + } + }, + { + "id": "subScriptTask1", + "type": "bpmn:ScriptTask", + "executionId": "subScriptTask1_d6f20eabf8", + "counters": { + "taken": 1, + "discarded": 1 + } + } + ], + "flows": [ + { + "id": "toSubScriptTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toSubScriptTaskTimeout", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 1 + } + } + ], + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": { + "fields": { + "routingKey": "execute.start", + "exchange": "execution", + "consumerTag": "_activity-execute" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_bdf5b8c729", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b7a22ffb16", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70" + } + } + ], + "executionId": "subProcess1_7acdf25adc", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "isSubProcess": true, + "state": "start", + "isRootScope": true + }, + "properties": { + "messageId": "smq.mid-f3d806e42b", + "timestamp": 1781240158951 + } + }, + "output": {} + } + } + }, + { + "id": "defaultTask", + "type": "bpmn:Task", + "executionId": "defaultTask_c30bad97c7", + "counters": { + "taken": 0, + "discarded": 1 + } + }, + { + "id": "join", + "type": "bpmn:ParallelGateway", + "executionId": "join_9b95444db0", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "pickMeTask", + "type": "bpmn:Task", + "executionId": "pickMeTask_a733ccb3c2", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "noPickMeTask", + "type": "bpmn:Task", + "executionId": "noPickMeTask_9e7c06bc8c", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "executionId": "decision_34a894b32a", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "executionId": "scriptTask2_953981ed13", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "executionId": "manyDecisions_96a1bd864b", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "theEnd", + "type": "bpmn:EndEvent", + "executionId": "theEnd_c6290f7c94", + "counters": { + "taken": 0, + "discarded": 1 + } + } + ], + "flows": [ + { + "id": "toDecision", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toFinal", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 1 + } + }, + { + "id": "toLoop", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toPickMe1", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toPickMe3", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toJoin3", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toJoin1", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toJoin2", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 1 + } + }, + { + "id": "toPickMe2", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 1 + } + }, + { + "id": "toInclusiveGateway", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toSubProcess", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toFirstUserTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 2, + "discard": 0 + } + }, + { + "id": "toReturnScriptTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toFirstScriptTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + } + ], + "messageFlows": [ + { + "id": "MessageFlow_0poeswc", + "type": "bpmn:MessageFlow", + "counters": { + "messages": 1 + } + } + ] + } + }, + { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_f628704cd5", + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_process-run" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_f628704cd5", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions" + } + }, + "properties": { + "messageId": "smq.mid-fe015229b7", + "timestamp": 1781240158969 + } + }, + "output": {} + }, + "stopped": false, + "counters": { + "completed": 2, + "discarded": 0 + }, + "execution": { + "executionId": "participantProcess_f628704cd5", + "stopped": false, + "completed": true, + "status": "completed", + "children": [ + { + "id": "messageStartEvent", + "type": "bpmn:StartEvent", + "executionId": "messageStartEvent_582014d0c1", + "counters": { + "taken": 2, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "participathEndEvent", + "type": "bpmn:EndEvent", + "executionId": "participathEndEvent_6fd9f75ca5", + "counters": { + "taken": 2, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "participathErrorEndEvent", + "type": "bpmn:EndEvent", + "executionId": "participathErrorEndEvent_5c26fdeed4", + "counters": { + "taken": 0, + "discarded": 2 + } + }, + { + "id": "participantServiceTask", + "type": "bpmn:ServiceTask", + "executionId": "participantServiceTask_0ba57d514a", + "counters": { + "taken": 2, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "serviceBoundErrorEvent", + "type": "bpmn:BoundaryEvent", + "executionId": "serviceBoundErrorEvent_1f8c38739a", + "counters": { + "taken": 0, + "discarded": 2 + }, + "execution": { + "completed": true + } + } + ], + "flows": [ + { + "id": "SequenceFlow_0o4woz0", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 2 + } + }, + { + "id": "SequenceFlow_1uyrch1", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 2, + "discard": 0 + } + }, + { + "id": "SequenceFlow_1ifeyo8", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 2, + "discard": 0 + } + } + ], + "associations": [ + { + "id": "Association_01m3i19", + "type": "bpmn:Association", + "counters": { + "take": 0, + "discard": 0 + } + } + ] + } + } + ] + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_definition-run" + }, + "content": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "properties": { + "messageId": "smq.mid-2d3aea9380", + "timestamp": 1781240158943 + } + } + ] + }, + { + "name": "execute-Definitions_1_fb4323ec88-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "process.init", + "exchange": "event" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "init" + }, + "properties": { + "type": "init", + "mandatory": false, + "messageId": "smq.mid-a81f9d0d4e", + "timestamp": 1781240158944 + } + }, + { + "fields": { + "routingKey": "process.enter", + "exchange": "event" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "enter" + }, + "properties": { + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-87f971821f", + "timestamp": 1781240158944 + } + }, + { + "fields": { + "routingKey": "process.start", + "exchange": "event" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_8cfc8dea70", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "start" + }, + "properties": { + "type": "start", + "mandatory": false, + "messageId": "smq.mid-464ec290e7", + "timestamp": 1781240158944 + } + }, + { + "fields": { + "routingKey": "process.init", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_0f5fac3d1c", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "init" + }, + "properties": { + "type": "init", + "mandatory": false, + "messageId": "smq.mid-9b87e1b7ec", + "timestamp": 1781240158963 + } + }, + { + "fields": { + "routingKey": "process.enter", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_0f5fac3d1c", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "enter" + }, + "properties": { + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-6176caa9b7", + "timestamp": 1781240158963 + } + }, + { + "fields": { + "routingKey": "process.start", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_0f5fac3d1c", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "start" + }, + "properties": { + "type": "start", + "mandatory": false, + "messageId": "smq.mid-39d2703877", + "timestamp": 1781240158963 + } + }, + { + "fields": { + "routingKey": "process.end", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_0f5fac3d1c", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "end", + "output": {} + }, + "properties": { + "type": "end", + "mandatory": false, + "messageId": "smq.mid-66d06db036", + "timestamp": 1781240158969 + } + }, + { + "fields": { + "routingKey": "process.leave", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_0f5fac3d1c", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "leave" + }, + "properties": { + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-3bcfd312ba", + "timestamp": 1781240158969 + } + }, + { + "fields": { + "routingKey": "process.enter", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_f628704cd5", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "enter" + }, + "properties": { + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-3a0362d1ec", + "timestamp": 1781240158969 + } + }, + { + "fields": { + "routingKey": "process.start", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_f628704cd5", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "start" + }, + "properties": { + "type": "start", + "mandatory": false, + "messageId": "smq.mid-4e577d481d", + "timestamp": 1781240158969 + } + }, + { + "fields": { + "routingKey": "process.end", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_f628704cd5", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "end", + "output": {} + }, + "properties": { + "type": "end", + "mandatory": false, + "messageId": "smq.mid-7d6495fd62", + "timestamp": 1781240158973 + } + }, + { + "fields": { + "routingKey": "process.leave", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_f628704cd5", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_fb4323ec88" + }, + "state": "leave" + }, + "properties": { + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-c5a2534452", + "timestamp": 1781240158973 + } + } + ] + } + ] + } +} diff --git a/test/resources/mother-of-all-state-18.json b/test/resources/mother-of-all-state-18.json new file mode 100644 index 00000000..2e3957e9 --- /dev/null +++ b/test/resources/mother-of-all-state-18.json @@ -0,0 +1,4232 @@ +{ + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b", + "status": "executing", + "stopped": false, + "counters": { + "completed": 0, + "discarded": 0 + }, + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": {}, + "output": {} + }, + "execution": { + "executionId": "Definitions_1_1f6f5fc71b", + "stopped": false, + "completed": false, + "status": "start", + "processes": [ + { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d", + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_process-run" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions" + } + }, + "properties": { + "messageId": "smq.mid-386b47554a", + "timestamp": 1781240127024 + }, + "stopLoop": true + }, + "output": {} + }, + "status": "executing", + "stopped": false, + "counters": { + "completed": 0, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_process-run" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions" + } + }, + "properties": { + "messageId": "smq.mid-386b47554a", + "timestamp": 1781240127024 + } + } + ] + }, + { + "name": "execute-motherOfAll_f433c3681d-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "activity.init", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isStart": true, + "isStartEvent": true, + "state": "init" + }, + "properties": { + "persistent": true, + "type": "init", + "mandatory": false, + "messageId": "smq.mid-b58a81717d", + "timestamp": 1781240127031 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isStart": true, + "isStartEvent": true, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-17a36df78d", + "timestamp": 1781240127031 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isStart": true, + "isStartEvent": true, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-4e119dbf0b", + "timestamp": 1781240127031 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isStart": true, + "isStartEvent": true, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-34f17b4002", + "timestamp": 1781240127032, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isStart": true, + "isStartEvent": true, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-043f7dde20", + "timestamp": 1781240127032 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_220a464bba", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-db67d78dd1", + "timestamp": 1781240127033 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_220a464bba", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f7496b4ed2", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-8f1c388851", + "timestamp": 1781240127033 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_220a464bba", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f7496b4ed2", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-3f1c38536f", + "timestamp": 1781240127033 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_220a464bba", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f7496b4ed2", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-0099b2a53a", + "timestamp": 1781240127034, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_220a464bba", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f7496b4ed2", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-f32f0aa293", + "timestamp": 1781240127034 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_e5a23b1beb", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-479ba20fcc", + "timestamp": 1781240127034 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_e5a23b1beb", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_60cc4123d7", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-a0efc581c2", + "timestamp": 1781240127034 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_e5a23b1beb", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_60cc4123d7", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-a4bf8f8de7", + "timestamp": 1781240127034 + } + }, + { + "fields": { + "routingKey": "activity.wait", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_e5a23b1beb", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_60cc4123d7", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "wait", + "isRootScope": true + }, + "properties": { + "persistent": true, + "messageId": "smq.mid-5a97266d3d", + "timestamp": 1781240127034 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_e5a23b1beb", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_60cc4123d7", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "correlationId": "userTask1_signal_c49d295ed9", + "messageId": "smq.mid-c1b5caa74c", + "timestamp": 1781240127035, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_e5a23b1beb", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_60cc4123d7", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "correlationId": "userTask1_signal_c49d295ed9", + "type": "end", + "mandatory": false, + "messageId": "smq.mid-f4f510df12", + "timestamp": 1781240127035 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b12e85aa82", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-c914659b01", + "timestamp": 1781240127035 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b12e85aa82", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "subProcess1_eb1472a86b", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isSubProcess": true, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-0cbb80bdd6", + "timestamp": 1781240127035 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b12e85aa82", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "subProcess1_eb1472a86b", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isSubProcess": true, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-354d3e16bc", + "timestamp": 1781240127035 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b12e85aa82", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "subProcess1_eb1472a86b", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isSubProcess": true, + "state": "execution.completed", + "isRootScope": true, + "output": {} + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-53c7e41b6e", + "timestamp": 1781240127040, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b12e85aa82", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "subProcess1_eb1472a86b", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isSubProcess": true, + "state": "end", + "isRootScope": true, + "output": {} + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-9734ae0d2a", + "timestamp": 1781240127041 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "subProcess1_eb1472a86b", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_f754ee527b", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-d644a0a1c8", + "timestamp": 1781240127041 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_eb1472a86b", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_f754ee527b", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "manyDecisions_536ba49711", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-70534056b7", + "timestamp": 1781240127041 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_eb1472a86b", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_f754ee527b", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "manyDecisions_536ba49711", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-75e540bac6", + "timestamp": 1781240127041 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_eb1472a86b", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_f754ee527b", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "manyDecisions_536ba49711", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true, + "requireOutbound": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-94477750ff", + "timestamp": 1781240127041, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_eb1472a86b", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_f754ee527b", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "manyDecisions_536ba49711", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true, + "requireOutbound": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-565d38931e", + "timestamp": 1781240127041 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_19c4c006aa", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-bf95af993f", + "timestamp": 1781240127041 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_19c4c006aa", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "noPickMeTask_645ae03a9f", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-f99fd62855", + "timestamp": 1781240127042 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_19c4c006aa", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "noPickMeTask_645ae03a9f", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-0c262cd491", + "timestamp": 1781240127042 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_19c4c006aa", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "noPickMeTask_645ae03a9f", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-79e362e4bb", + "timestamp": 1781240127042, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_19c4c006aa", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "noPickMeTask_645ae03a9f", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-b3bf29d1ed", + "timestamp": 1781240127042 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_c28a5431cb", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-966cd762c4", + "timestamp": 1781240127042 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_c28a5431cb", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "join_d303874c8d", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isParallelJoin": true, + "isParallelGateway": true, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-578b06e46e", + "timestamp": 1781240127042 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_c28a5431cb", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "join_d303874c8d", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isParallelJoin": true, + "isParallelGateway": true, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-747327bf24", + "timestamp": 1781240127042 + } + }, + { + "fields": { + "routingKey": "activity.converge", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_c28a5431cb", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "join_d303874c8d", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isParallelJoin": true, + "isParallelGateway": true, + "state": "start", + "isRootScope": true + }, + "properties": { + "persistent": true, + "messageId": "smq.mid-66ae6b509d", + "timestamp": 1781240127043 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe1", + "targetId": "noPickMeTask", + "sequenceId": "toPickMe1_take_19c4c006aa", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "noPickMeTask_645ae03a9f", + "id": "noPickMeTask", + "type": "bpmn:Task", + "name": "No! Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-a74bbe5669", + "timestamp": 1781240127043 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_e9be9834bd", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-a3519f9825", + "timestamp": 1781240127044 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_e9be9834bd", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "pickMeTask_161a1ad270", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-4bcc7c28e1", + "timestamp": 1781240127044 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_e9be9834bd", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "pickMeTask_161a1ad270", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-51551228d5", + "timestamp": 1781240127044 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_e9be9834bd", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "pickMeTask_161a1ad270", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-926f4e1d57", + "timestamp": 1781240127044, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_e9be9834bd", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "pickMeTask_161a1ad270", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-e09ddbbe99", + "timestamp": 1781240127044 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_161a1ad270", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_1965c89e61", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-364e986472", + "timestamp": 1781240127044 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe3", + "targetId": "pickMeTask", + "sequenceId": "toPickMe3_take_e9be9834bd", + "type": "bpmn:SequenceFlow", + "sourceId": "manyDecisions", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "pickMeTask_161a1ad270", + "id": "pickMeTask", + "type": "bpmn:Task", + "name": "Pick me", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_161a1ad270", + "id": "toJoin3", + "targetId": "join" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-ad7cb0d65a", + "timestamp": 1781240127044 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_eb1472a86b", + "id": "toInclusiveGateway", + "targetId": "manyDecisions", + "sequenceId": "toInclusiveGateway_take_f754ee527b", + "type": "bpmn:SequenceFlow", + "sourceId": "subProcess1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "manyDecisions_536ba49711", + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "leave", + "isRootScope": true, + "requireOutbound": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe1", + "targetId": "noPickMeTask" + }, + { + "action": "take", + "result": true, + "evaluationId": "manyDecisions_536ba49711", + "id": "toPickMe3", + "targetId": "pickMeTask" + }, + { + "action": "discard", + "id": "toPickMe2", + "targetId": "defaultTask", + "isDefault": true + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-a9419ce3a2", + "timestamp": 1781240127044 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b12e85aa82", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "subProcess1_eb1472a86b", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isSubProcess": true, + "state": "leave", + "isRootScope": true, + "output": {}, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "subProcess1_eb1472a86b", + "id": "toInclusiveGateway", + "targetId": "manyDecisions" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-9231949a6f", + "timestamp": 1781240127045 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_e5a23b1beb", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_60cc4123d7", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1" + } + ] + }, + "properties": { + "persistent": true, + "correlationId": "userTask1_signal_c49d295ed9", + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-234732321c", + "timestamp": 1781240127045 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toFirstScriptTask_take_220a464bba", + "type": "bpmn:SequenceFlow", + "sourceId": "StartEvent_1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f7496b4ed2", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f7496b4ed2", + "id": "toFirstUserTask", + "targetId": "userTask1" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-4115da809f", + "timestamp": 1781240127045 + } + }, + { + "fields": { + "routingKey": "activity.leave", + "exchange": "event" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isStart": true, + "isStartEvent": true, + "state": "leave", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1" + } + ] + }, + "properties": { + "persistent": true, + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-1ae180317f", + "timestamp": 1781240127045 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_c28a5431cb", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_161a1ad270", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_1965c89e61", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "join_d303874c8d", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isParallelJoin": true, + "isParallelGateway": true, + "state": "execution.completed", + "isRootScope": true, + "preventComplete": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-71a641ecb7", + "timestamp": 1781240127046, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_c28a5431cb", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_161a1ad270", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_1965c89e61", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "join_d303874c8d", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "isParallelJoin": true, + "isParallelGateway": true, + "state": "end", + "isRootScope": true, + "preventComplete": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-0cb2e70ef6", + "timestamp": 1781240127046 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "join_d303874c8d", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_c5903b6270", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-0274c529ad", + "timestamp": 1781240127046 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_d303874c8d", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_c5903b6270", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "decision_94707c23c7", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-32d45a77e9", + "timestamp": 1781240127046 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_d303874c8d", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_c5903b6270", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "decision_94707c23c7", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-e33fb7eea3", + "timestamp": 1781240127046 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_d303874c8d", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_c5903b6270", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "decision_94707c23c7", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true, + "outboundTakeOne": true, + "requireOutbound": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-b52480c78e", + "timestamp": 1781240127046, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_d303874c8d", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_c5903b6270", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "decision_94707c23c7", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true, + "outboundTakeOne": true, + "requireOutbound": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-cecc8e2434", + "timestamp": 1781240127047 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "decision_94707c23c7", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_59e63f2b77", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-a5b9fea7b9", + "timestamp": 1781240127047 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_94707c23c7", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_59e63f2b77", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask2_72058f260a", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-7a5b9270fb", + "timestamp": 1781240127047 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_94707c23c7", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_59e63f2b77", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask2_72058f260a", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-dc0a0d530f", + "timestamp": 1781240127048 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_94707c23c7", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_59e63f2b77", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask2_72058f260a", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-78b8b36537", + "timestamp": 1781240127048, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_94707c23c7", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_59e63f2b77", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask2_72058f260a", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-33ffb7309b", + "timestamp": 1781240127049 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_72058f260a", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_bc0d1264c8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-c47df54543", + "timestamp": 1781240127056 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_72058f260a", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_bc0d1264c8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f1dc371905", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-cb44a36e53", + "timestamp": 1781240127056 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_72058f260a", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_bc0d1264c8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f1dc371905", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-d21f5b8d26", + "timestamp": 1781240127056 + } + }, + { + "fields": { + "routingKey": "activity.execution.completed", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_72058f260a", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_bc0d1264c8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f1dc371905", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "execution.completed", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "execution.completed", + "messageId": "smq.mid-1f89702c05", + "timestamp": 1781240127057, + "mandatory": false + } + }, + { + "fields": { + "routingKey": "activity.end", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_72058f260a", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_bc0d1264c8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f1dc371905", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "end", + "isRootScope": true + }, + "properties": { + "persistent": true, + "type": "end", + "mandatory": false, + "messageId": "smq.mid-96557e8dd9", + "timestamp": 1781240127057 + } + }, + { + "fields": { + "routingKey": "flow.take", + "exchange": "event" + }, + "content": { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f1dc371905", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_4e8b1760f8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + "properties": { + "persistent": true, + "type": "take", + "messageId": "smq.mid-d4c4dc89f9", + "timestamp": 1781240127057 + } + }, + { + "fields": { + "routingKey": "activity.enter", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f1dc371905", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_4e8b1760f8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_2b253ccd28", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "enter" + }, + "properties": { + "persistent": true, + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-10f07be9e0", + "timestamp": 1781240127057 + } + }, + { + "fields": { + "routingKey": "activity.start", + "exchange": "event" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f1dc371905", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_4e8b1760f8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_2b253ccd28", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + }, + "state": "start" + }, + "properties": { + "persistent": true, + "type": "start", + "mandatory": false, + "messageId": "smq.mid-92c5602d0b", + "timestamp": 1781240127057 + } + } + ] + } + ] + }, + "execution": { + "executionId": "motherOfAll_f433c3681d", + "stopped": false, + "completed": false, + "status": "executing", + "children": [ + { + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "executionId": "StartEvent_1_d284030da4", + "counters": { + "taken": 1, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.leave", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "isStart": true, + "isStartEvent": true, + "state": "completed", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1" + } + ] + }, + "properties": { + "messageId": "smq.mid-3ce1503f47", + "timestamp": 1781240127032 + } + }, + { + "fields": { + "routingKey": "run.next", + "exchange": "run" + }, + "content": { + "executionId": "StartEvent_1_d284030da4", + "id": "StartEvent_1", + "type": "bpmn:StartEvent", + "name": "Start", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "isStart": true, + "isStartEvent": true, + "state": "completed", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "StartEvent_1_d284030da4", + "id": "toFirstScriptTask", + "targetId": "scriptTask1" + } + ] + }, + "properties": { + "persistent": false, + "messageId": "smq.mid-cb617df815", + "timestamp": 1781240127045 + } + } + ] + } + ] + }, + "execution": { + "completed": true + } + }, + { + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "status": "end", + "executionId": "scriptTask1_f1dc371905", + "counters": { + "taken": 2, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.leave", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_72058f260a", + "id": "toReturnScriptTask", + "targetId": "scriptTask1", + "sequenceId": "toReturnScriptTask_take_bc0d1264c8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask2", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask1_f1dc371905", + "id": "scriptTask1", + "type": "bpmn:ScriptTask", + "name": "Script\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "state": "completed", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f1dc371905", + "id": "toFirstUserTask", + "targetId": "userTask1" + } + ] + }, + "properties": { + "messageId": "smq.mid-99dc1347d2", + "timestamp": 1781240127057 + } + } + ] + } + ] + }, + "execution": { + "completed": true + } + }, + { + "id": "userTask1", + "type": "bpmn:UserTask", + "status": "executing", + "executionId": "userTask1_2b253ccd28", + "counters": { + "taken": 1, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f1dc371905", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_4e8b1760f8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_2b253ccd28", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + } + }, + "properties": { + "messageId": "smq.mid-5586d22af2", + "timestamp": 1781240127057 + } + } + ] + }, + { + "name": "execute-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "execute.start", + "exchange": "execution", + "consumerTag": "_activity-execute" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask1_f1dc371905", + "id": "toFirstUserTask", + "targetId": "userTask1", + "sequenceId": "toFirstUserTask_take_4e8b1760f8", + "type": "bpmn:SequenceFlow", + "sourceId": "scriptTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "userTask1_2b253ccd28", + "id": "userTask1", + "type": "bpmn:UserTask", + "name": "Wait for user", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "state": "start", + "isRootScope": true + }, + "properties": { + "messageId": "smq.mid-95e00c214e", + "timestamp": 1781240127057 + } + } + ] + } + ] + }, + "execution": { + "completed": false + } + }, + { + "id": "subProcess1", + "type": "bpmn:SubProcess", + "executionId": "subProcess1_eb1472a86b", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true, + "executionId": "subProcess1_eb1472a86b", + "stopped": false, + "status": "completed", + "children": [ + { + "id": "subUserTask1", + "type": "bpmn:UserTask", + "executionId": "subUserTask1_a929d0c770", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "subUserTaskTimer", + "type": "bpmn:BoundaryEvent", + "executionId": "subUserTaskTimer_1a400abbec", + "counters": { + "taken": 0, + "discarded": 1 + }, + "execution": { + "completed": true + } + }, + { + "id": "subScriptTask1", + "type": "bpmn:ScriptTask", + "executionId": "subScriptTask1_3b420e7559", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + } + ], + "flows": [ + { + "id": "toSubScriptTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toSubScriptTaskTimeout", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 0 + } + } + ], + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": { + "fields": { + "routingKey": "execute.start", + "exchange": "execution", + "consumerTag": "_activity-execute" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "userTask1_60cc4123d7", + "id": "toSubProcess", + "targetId": "subProcess1", + "sequenceId": "toSubProcess_take_b12e85aa82", + "type": "bpmn:SequenceFlow", + "sourceId": "userTask1", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "subProcess1_eb1472a86b", + "id": "subProcess1", + "type": "bpmn:SubProcess", + "name": "Sub process\n", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "isSubProcess": true, + "state": "start", + "isRootScope": true + }, + "properties": { + "messageId": "smq.mid-ac3b80967c", + "timestamp": 1781240127036 + } + }, + "output": {} + } + } + }, + { + "id": "defaultTask", + "type": "bpmn:Task", + "counters": { + "taken": 0, + "discarded": 0 + } + }, + { + "id": "join", + "type": "bpmn:ParallelGateway", + "status": "end", + "executionId": "join_d303874c8d", + "counters": { + "taken": 1, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.leave", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "noPickMeTask_645ae03a9f", + "id": "toJoin1", + "targetId": "join", + "sequenceId": "toJoin1_take_c28a5431cb", + "type": "bpmn:SequenceFlow", + "sourceId": "noPickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + }, + { + "action": "take", + "result": true, + "evaluationId": "pickMeTask_161a1ad270", + "id": "toJoin3", + "targetId": "join", + "sequenceId": "toJoin3_take_1965c89e61", + "type": "bpmn:SequenceFlow", + "sourceId": "pickMeTask", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "join_d303874c8d", + "id": "join", + "type": "bpmn:ParallelGateway", + "name": "Join", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "isParallelJoin": true, + "isParallelGateway": true, + "state": "completed", + "isRootScope": true, + "preventComplete": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_d303874c8d", + "id": "toDecision", + "targetId": "decision" + } + ] + }, + "properties": { + "messageId": "smq.mid-e70e31a659", + "timestamp": 1781240127046 + } + } + ] + } + ] + }, + "execution": { + "completed": true + } + }, + { + "id": "pickMeTask", + "type": "bpmn:Task", + "executionId": "pickMeTask_161a1ad270", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "noPickMeTask", + "type": "bpmn:Task", + "executionId": "noPickMeTask_645ae03a9f", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "status": "end", + "executionId": "decision_94707c23c7", + "counters": { + "taken": 1, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.leave", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "join_d303874c8d", + "id": "toDecision", + "targetId": "decision", + "sequenceId": "toDecision_take_c5903b6270", + "type": "bpmn:SequenceFlow", + "sourceId": "join", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "decision_94707c23c7", + "id": "decision", + "type": "bpmn:ExclusiveGateway", + "name": "Loop?", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "state": "completed", + "isRootScope": true, + "outboundTakeOne": true, + "requireOutbound": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_94707c23c7", + "id": "toLoop", + "targetId": "scriptTask2" + }, + { + "action": "discard", + "id": "toFinal", + "targetId": "theEnd", + "isDefault": true + } + ] + }, + "properties": { + "messageId": "smq.mid-b48e2024b7", + "timestamp": 1781240127047 + } + } + ] + } + ] + }, + "execution": { + "completed": true + } + }, + { + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "status": "end", + "executionId": "scriptTask2_72058f260a", + "counters": { + "taken": 1, + "discarded": 0 + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.leave", + "exchange": "run", + "consumerTag": "_activity-run" + }, + "content": { + "inbound": [ + { + "action": "take", + "result": true, + "evaluationId": "decision_94707c23c7", + "id": "toLoop", + "targetId": "scriptTask2", + "sequenceId": "toLoop_take_59e63f2b77", + "type": "bpmn:SequenceFlow", + "name": "Enter loop", + "sourceId": "decision", + "isSequenceFlow": true, + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d" + } + } + ], + "executionId": "scriptTask2_72058f260a", + "id": "scriptTask2", + "type": "bpmn:ScriptTask", + "name": "Only run me once", + "parent": { + "id": "motherOfAll", + "type": "bpmn:Process" + }, + "state": "completed", + "isRootScope": true, + "outbound": [ + { + "action": "take", + "result": true, + "evaluationId": "scriptTask2_72058f260a", + "id": "toReturnScriptTask", + "targetId": "scriptTask1" + } + ] + }, + "properties": { + "messageId": "smq.mid-bae379105a", + "timestamp": 1781240127049 + } + } + ] + } + ] + }, + "execution": { + "completed": true + } + }, + { + "id": "manyDecisions", + "type": "bpmn:InclusiveGateway", + "executionId": "manyDecisions_536ba49711", + "counters": { + "taken": 1, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "theEnd", + "type": "bpmn:EndEvent", + "counters": { + "taken": 0, + "discarded": 0 + } + } + ], + "flows": [ + { + "id": "toDecision", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toFinal", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 0 + } + }, + { + "id": "toLoop", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toPickMe1", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toPickMe3", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toJoin3", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toJoin1", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toJoin2", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 0 + } + }, + { + "id": "toPickMe2", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 0 + } + }, + { + "id": "toInclusiveGateway", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toSubProcess", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toFirstUserTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 2, + "discard": 0 + } + }, + { + "id": "toReturnScriptTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + }, + { + "id": "toFirstScriptTask", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 1, + "discard": 0 + } + } + ], + "messageFlows": [ + { + "id": "MessageFlow_0poeswc", + "type": "bpmn:MessageFlow", + "counters": { + "messages": 1 + } + } + ] + } + }, + { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_2faa608e59", + "environment": { + "settings": { + "enableDummyService": true + }, + "variables": { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_process-run" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_2faa608e59", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions" + } + }, + "properties": { + "messageId": "smq.mid-fe4c446d5e", + "timestamp": 1781240127053 + } + }, + "output": {} + }, + "stopped": false, + "counters": { + "completed": 2, + "discarded": 0 + }, + "execution": { + "executionId": "participantProcess_2faa608e59", + "stopped": false, + "completed": true, + "status": "completed", + "children": [ + { + "id": "messageStartEvent", + "type": "bpmn:StartEvent", + "executionId": "messageStartEvent_c223157405", + "counters": { + "taken": 2, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "participathEndEvent", + "type": "bpmn:EndEvent", + "executionId": "participathEndEvent_020e7dac93", + "counters": { + "taken": 2, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "participathErrorEndEvent", + "type": "bpmn:EndEvent", + "counters": { + "taken": 0, + "discarded": 0 + } + }, + { + "id": "participantServiceTask", + "type": "bpmn:ServiceTask", + "executionId": "participantServiceTask_a2420ffdb1", + "counters": { + "taken": 2, + "discarded": 0 + }, + "execution": { + "completed": true + } + }, + { + "id": "serviceBoundErrorEvent", + "type": "bpmn:BoundaryEvent", + "executionId": "serviceBoundErrorEvent_83084d41a2", + "counters": { + "taken": 0, + "discarded": 2 + }, + "execution": { + "completed": true + } + } + ], + "flows": [ + { + "id": "SequenceFlow_0o4woz0", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 0, + "discard": 0 + } + }, + { + "id": "SequenceFlow_1uyrch1", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 2, + "discard": 0 + } + }, + { + "id": "SequenceFlow_1ifeyo8", + "type": "bpmn:SequenceFlow", + "counters": { + "looped": 0, + "take": 2, + "discard": 0 + } + } + ], + "associations": [ + { + "id": "Association_01m3i19", + "type": "bpmn:Association", + "counters": { + "take": 0, + "discard": 0 + } + } + ] + } + } + ] + }, + "broker": { + "queues": [ + { + "name": "run-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "run.execute", + "exchange": "run", + "consumerTag": "_definition-run" + }, + "content": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "properties": { + "messageId": "smq.mid-cd45db9af8", + "timestamp": 1781240127022 + } + } + ] + }, + { + "name": "execute-Definitions_1_1f6f5fc71b-q", + "options": { + "autoDelete": false, + "durable": true + }, + "messages": [ + { + "fields": { + "routingKey": "process.init", + "exchange": "event" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "init" + }, + "properties": { + "type": "init", + "mandatory": false, + "messageId": "smq.mid-db789145d8", + "timestamp": 1781240127023 + } + }, + { + "fields": { + "routingKey": "process.enter", + "exchange": "event" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "enter" + }, + "properties": { + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-f11f10b94c", + "timestamp": 1781240127024 + } + }, + { + "fields": { + "routingKey": "process.start", + "exchange": "event" + }, + "content": { + "id": "motherOfAll", + "type": "bpmn:Process", + "executionId": "motherOfAll_f433c3681d", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "start" + }, + "properties": { + "type": "start", + "mandatory": false, + "messageId": "smq.mid-cfd788c911", + "timestamp": 1781240127024 + } + }, + { + "fields": { + "routingKey": "process.init", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_20c245f348", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "init" + }, + "properties": { + "type": "init", + "mandatory": false, + "messageId": "smq.mid-c522f0d962", + "timestamp": 1781240127049 + } + }, + { + "fields": { + "routingKey": "process.enter", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_20c245f348", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "enter" + }, + "properties": { + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-12be0946cf", + "timestamp": 1781240127049 + } + }, + { + "fields": { + "routingKey": "process.start", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_20c245f348", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "start" + }, + "properties": { + "type": "start", + "mandatory": false, + "messageId": "smq.mid-3a961df94b", + "timestamp": 1781240127049 + } + }, + { + "fields": { + "routingKey": "process.end", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_20c245f348", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "end", + "output": {} + }, + "properties": { + "type": "end", + "mandatory": false, + "messageId": "smq.mid-db5cdc6b34", + "timestamp": 1781240127053 + } + }, + { + "fields": { + "routingKey": "process.leave", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_20c245f348", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "leave" + }, + "properties": { + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-36596a8390", + "timestamp": 1781240127053 + } + }, + { + "fields": { + "routingKey": "process.enter", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_2faa608e59", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "enter" + }, + "properties": { + "type": "enter", + "mandatory": false, + "messageId": "smq.mid-37f279967e", + "timestamp": 1781240127053 + } + }, + { + "fields": { + "routingKey": "process.start", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_2faa608e59", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "start" + }, + "properties": { + "type": "start", + "mandatory": false, + "messageId": "smq.mid-71dfd34b74", + "timestamp": 1781240127053 + } + }, + { + "fields": { + "routingKey": "process.end", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_2faa608e59", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "end", + "output": {} + }, + "properties": { + "type": "end", + "mandatory": false, + "messageId": "smq.mid-a347311506", + "timestamp": 1781240127056 + } + }, + { + "fields": { + "routingKey": "process.leave", + "exchange": "event" + }, + "content": { + "id": "participantProcess", + "type": "bpmn:Process", + "executionId": "participantProcess_2faa608e59", + "parent": { + "id": "Definitions_1", + "type": "bpmn:Definitions", + "executionId": "Definitions_1_1f6f5fc71b" + }, + "state": "leave" + }, + "properties": { + "type": "leave", + "mandatory": false, + "messageId": "smq.mid-b09db02cf2", + "timestamp": 1781240127056 + } + } + ] + } + ] + } +} diff --git a/test/tasks/UserTask-test.js b/test/tasks/UserTask-test.js index d7954665..86b75440 100644 --- a/test/tasks/UserTask-test.js +++ b/test/tasks/UserTask-test.js @@ -77,7 +77,7 @@ describe('UserTask', () => { const left = task.waitFor('leave'); task.activate(); - task.inbound[0].discard(); + task.discard(); await left; @@ -215,7 +215,7 @@ describe('UserTask', () => { const left = task.waitFor('leave'); task.activate(); - task.inbound[0].discard(); + task.discard(); await left; @@ -434,7 +434,7 @@ describe('UserTask', () => { const left = task.waitFor('leave'); task.activate(); - task.inbound[0].discard(); + task.discard(); await left; diff --git a/types/index.d.ts b/types/index.d.ts index f1ea5920..8b526945 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -611,7 +611,7 @@ declare module 'bpmn-elements' { */ resume(): void; /** - * Discard the activity. Stops execution if running and discards outbound flows. + * Discard the activity. Stops execution if running; the activity leaves without taking any outbound flow. * @param discardContent Optional content propagated with the discard * */ discard(discardContent?: Record): void; @@ -1746,8 +1746,9 @@ declare module 'bpmn-elements' { */ take(content?: Record): boolean; /** - * Discard the flow and publish flow.discard. Detects loops via discardSequence and emits - * flow.looped instead when the target id is already in the sequence. + * Discard the flow and publish flow.discard. + * + * @deprecated The execution runtime no longer discards sequence flows, so this is a no-op during a run. It will be removed in a future version. * */ discard(content?: Record): void; From f0f88bb05a0bc21517ee6c4d2851d042d8c30a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Sat, 13 Jun 2026 08:16:43 +0200 Subject: [PATCH 28/31] enforce mutually exclusive start events on recover --- AGENTS.md | 10 ++ CHANGELOG.md | 10 ++ dist/constants.js | 10 +- dist/definition/Definition.js | 7 +- dist/definition/DefinitionExecution.js | 5 +- dist/gateways/ParallelGateway.js | 3 +- dist/process/Process.js | 5 +- dist/process/ProcessExecution.js | 56 +++++++-- package.json | 2 +- src/constants.js | 6 + src/definition/Definition.js | 9 +- src/definition/DefinitionExecution.js | 5 +- src/process/Process.js | 5 +- src/process/ProcessExecution.js | 62 ++++++++-- .../feature/backward-compatability-feature.js | 21 ++++ test/feature/multiple-startevent-feature.js | 115 ++++++++++++++++++ types/index.d.ts | 11 +- types/interfaces.d.ts | 2 + 18 files changed, 303 insertions(+), 41 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index efdbf5e5..8ab9a906 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,6 +6,7 @@ This file provides guidance to coding agents (Claude Code, and any tool that rea - **TDD is the default.** Red → green → refactor: write or adjust a failing test before changing implementation. Don't delete or weaken existing assertions to land a change — extend them. - **Performance and coverage are the project's USP.** Avoid regressions in either. On hot paths (broker dispatch, flow traversal, activity activation, joins, multi-instance loops), prefer existing `Context` Maps/refs over rebuilt scans, and avoid per-message allocations/closures where they can be hoisted. +- **JSDoc is concise.** Short intent descriptions are fine; never describe internal implementation. - Before declaring done: `npm test` (full suite + lint + `dist` rebuild). For coverage-sensitive work, also `npm run cov:html`. ## Commands @@ -46,6 +47,8 @@ An element type like `ServiceTask` is not a class. It is a factory function that When an activity is activated, `ActivityExecution` instantiates the Behaviour and calls its `execute`. To replace an element type entirely, supply a new Behaviour — see `docs/Extend.md`. +To identify an element's kind at runtime, compare its `Behaviour` (`entity.Behaviour === StartEvent`) rather than the `type` string — type strings can be customized via the `types` extension. + ### `Context` and `Environment` - `src/Context.js` is a per-execution **registry and lazy factory**. It stores activities, flows, and processes in `refs` Maps and instantiates them on first access via `upsertActivity` / `upsertSequenceFlow` / `upsertProcess`. It bridges the parsed moddle context (from `bpmn-moddle` via `moddle-context-serializer`) to runtime instances and wires extensions through `ExtensionsMapper`. Contexts are cheap to clone and are isolated per execution scope. @@ -62,6 +65,12 @@ Documented in `docs/Extend.md` and `docs/Extension.md`: 1. **Replace a Behaviour** by passing `{ types: { 'bpmn:StartEvent': MyStartEvent } }` to `Definition`. Use when you need full control over an element's execution. 2. **Non-invasive extension hooks** via `{ extensions: { myExt(activity, context) { … } } }`. Each extension runs once per activity after instantiation and typically attaches listeners or publishes format messages — used for cross-cutting concerns (forms, logging, output capture). +### State & behavioral invariants + +- **No flow discards.** Outbound sequence flows are never discarded; flow and activity `discarded` counters stay `0`. There is no `skipDiscard` setting. Parallel joins rely on cached gateway peers, not on discarded flows. +- **Multiple start events are mutually exclusive entry points.** The first start event to fire discards the others still armed, so two start branches can never both run. +- **`stateVersion`.** `Definition.getState()` stamps `stateVersion` (the package major, hardcoded in `src/constants.js`); recovering an older major triggers migrations (e.g. start event reconciliation on resume). Unstamped legacy states are treated as version `0`. Bump the constant on each major release. + ## Testing patterns - Framework: mocha + `mocha-cakes-2` BDD UI. `Feature` / `Scenario` / `Given` / `When` / `Then` / `And` / `But` are globals in test files (declared in `eslint.config.js`). Chai `expect` is registered globally via `test/helpers/setup.js`. @@ -69,3 +78,4 @@ Documented in `docs/Extend.md` and `docs/Extension.md`: - BPMN sources: raw XML templates in `test/helpers/factory.js` (helpers like `factory.valid()`, `factory.userTask()`, `factory.resource('name')`) plus `.bpmn` files under `test/resources/`. - Primary helper: `test/helpers/testHelpers.js` — `context(source, options)` parses BPMN via `bpmn-moddle`, serializes via `moddle-context-serializer`, and returns a runtime `Context`. Also exposes `Logger`, `emptyContext`, and `AssertMessage` for asserting broker message sequences. - `test/helpers/JavaScripts.js` is a mock Scripts engine for isolating ScriptTask tests. +- Don't assert on logging — captured `logger.warn`/`debug` output is not part of the tested contract. diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aa67043..99cad39c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v18.0.1 - 2026-06-13 + +### Fixes + +- enforce mutually exclusive start events on recover: a recovered state where one entry point already won, or a legacy state serialized before the `isStartEvent` flag existed, now correctly discards the start events still left armed instead of resuming them as live entry points + +### Additions + +- serialized definition state is stamped with a `stateVersion` tracking the package major; recovering an older major (legacy unstamped states are treated as version `0`) triggers migrations such as the start event reconciliation above + ## v18.0.0 - 2026-06-11 Refactor parallel converging and forking gateways, and treat multiple start events as mutually exclusive entry points. As a result of the parallel gateway keeping track of peers there is no need for discarding a sequence flows. diff --git a/dist/constants.js b/dist/constants.js index 473f17ec..4cba192b 100644 --- a/dist/constants.js +++ b/dist/constants.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.K_TARGETS = exports.K_STOPPED = exports.K_STATUS = exports.K_STATE_MESSAGE = exports.K_REFERENCE_INFO = exports.K_REFERENCE_ELEMENT = exports.K_MESSAGE_Q = exports.K_MESSAGE_HANDLERS = exports.K_EXTENSIONS = exports.K_EXECUTION = exports.K_EXECUTE_MESSAGE = exports.K_COUNTERS = exports.K_CONSUMING = exports.K_COMPLETED = exports.K_ACTIVATED = void 0; +exports.STATE_VERSION = exports.K_TARGETS = exports.K_STOPPED = exports.K_STATUS = exports.K_STATE_MESSAGE = exports.K_REFERENCE_INFO = exports.K_REFERENCE_ELEMENT = exports.K_MESSAGE_Q = exports.K_MESSAGE_HANDLERS = exports.K_EXTENSIONS = exports.K_EXECUTION = exports.K_EXECUTE_MESSAGE = exports.K_COUNTERS = exports.K_CONSUMING = exports.K_COMPLETED = exports.K_ACTIVATED = void 0; const K_ACTIVATED = exports.K_ACTIVATED = Symbol.for('activated'); const K_COMPLETED = exports.K_COMPLETED = Symbol.for('completed'); const K_CONSUMING = exports.K_CONSUMING = Symbol.for('consuming'); @@ -18,4 +18,10 @@ const K_REFERENCE_INFO = exports.K_REFERENCE_INFO = Symbol.for('referenceInfo'); const K_STATE_MESSAGE = exports.K_STATE_MESSAGE = Symbol.for('stateMessage'); const K_STATUS = exports.K_STATUS = Symbol.for('status'); const K_STOPPED = exports.K_STOPPED = Symbol.for('stopped'); -const K_TARGETS = exports.K_TARGETS = Symbol.for('targets'); \ No newline at end of file +const K_TARGETS = exports.K_TARGETS = Symbol.for('targets'); + +/** + * State version. Tracks the package major; bump on each major. Recovering an older major triggers + * migrations. Unstamped legacy states are treated as version 0. + */ +const STATE_VERSION = exports.STATE_VERSION = 18; \ No newline at end of file diff --git a/dist/definition/Definition.js b/dist/definition/Definition.js index 7bc573da..7605d7f1 100644 --- a/dist/definition/Definition.js +++ b/dist/definition/Definition.js @@ -176,6 +176,7 @@ Definition.prototype.resume = function resume(callback) { */ Definition.prototype.getState = function getState() { return this._createMessage({ + stateVersion: _constants.STATE_VERSION, status: this.status, stopped: this.stopped, counters: this.counters, @@ -194,6 +195,10 @@ Definition.prototype.getState = function getState() { Definition.prototype.recover = function recover(state) { if (this.isRunning) throw new Error('cannot recover running definition'); if (!state) return this; + const recoveredVersion = state.stateVersion || 0; + if (recoveredVersion !== _constants.STATE_VERSION) { + this.logger.debug(`<${this.id}> recover state version ${recoveredVersion} into runtime state version ${_constants.STATE_VERSION}`); + } this[_constants.K_STOPPED] = !!state.stopped; this[_constants.K_STATUS] = state.status; const exec = this[_constants.K_EXECUTION]; @@ -206,7 +211,7 @@ Definition.prototype.recover = function recover(state) { } this.environment.recover(state.environment); if (state.execution) { - exec.set('execution', new _DefinitionExecution.DefinitionExecution(this, this.context).recover(state.execution)); + exec.set('execution', new _DefinitionExecution.DefinitionExecution(this, this.context).recover(state.execution, recoveredVersion)); } this.broker.recover(state.broker); return this; diff --git a/dist/definition/DefinitionExecution.js b/dist/definition/DefinitionExecution.js index 167a0c29..9fd70649 100644 --- a/dist/definition/DefinitionExecution.js +++ b/dist/definition/DefinitionExecution.js @@ -186,9 +186,10 @@ DefinitionExecution.prototype.resume = function resume() { /** * Restore execution state captured by getState. Reinstates running processes from the snapshot. * @param {import('#types').DefinitionExecutionState} [state] + * @param {number} [recoveredVersion] State version * @returns {this} */ -DefinitionExecution.prototype.recover = function recover(state) { +DefinitionExecution.prototype.recover = function recover(state, recoveredVersion) { if (!state) return this; this.executionId = state.executionId; this[_constants.K_STOPPED] = state.stopped; @@ -208,7 +209,7 @@ DefinitionExecution.prototype.recover = function recover(state) { } if (!bp) continue; ids.add(bpid); - bp.recover(bpState); + bp.recover(bpState, recoveredVersion); running.add(bp); } return this; diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 9feb906d..277eedf5 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -37,7 +37,8 @@ function ParallelGateway(activityDef, context) { const cachedPeers = context.getShakenPeers(id); if (cachedPeers) { for (const [flowId, sourceIds] of cachedPeers) { - const peer = peers.get(flowId); + let peer = peers.get(flowId); + if (!peer) peers.set(flowId, peer = new Set()); for (const sourceId of sourceIds) peer.add(sourceId); } activity[K_PEERS_DISCOVERED] = true; diff --git a/dist/process/Process.js b/dist/process/Process.js index 2646f918..97e2ac75 100644 --- a/dist/process/Process.js +++ b/dist/process/Process.js @@ -191,10 +191,11 @@ Process.prototype.getState = function getState() { /** * Restore process state captured by getState. * @param {import('#types').ProcessState} [state] + * @param {number} [recoveredVersion] State version * @returns {this} * @throws {Error} when called on a running process */ -Process.prototype.recover = function recover(state) { +Process.prototype.recover = function recover(state, recoveredVersion) { if (this.isRunning) throw new Error(`cannot recover running process <${this.id}>`); if (!state) return this; this[_constants.K_STOPPED] = !!state.stopped; @@ -207,7 +208,7 @@ Process.prototype.recover = function recover(state) { }; this.environment.recover(state.environment); if (state.execution) { - exec.set('execution', new _ProcessExecution.ProcessExecution(this, this.context).recover(state.execution)); + exec.set('execution', new _ProcessExecution.ProcessExecution(this, this.context).recover(state.execution, recoveredVersion)); } this.broker.recover(state.broker); return this; diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index cc1d0982..bdae9206 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -14,6 +14,7 @@ const K_ELEMENTS = Symbol.for('elements'); const K_PARENT = Symbol.for('parent'); const K_TRACKER = Symbol.for('activity tracker'); const K_PEERS_DISCOVERED = Symbol.for('peers discovered'); +const K_RECOVERED_VERSION = Symbol.for('recovered version'); /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -163,6 +164,8 @@ ProcessExecution.prototype.resume = function resume() { activity.resume(); } if (this[_constants.K_COMPLETED]) return; + this._reconcileStartEvents(); + if (this[_constants.K_COMPLETED]) return; if (!postponed.size && status === 'executing') return this._complete('completed'); }; @@ -208,11 +211,13 @@ ProcessExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. * @param {import('#types').ProcessExecutionState} [state] + * @param {number} [recoveredVersion] State version * @returns {this} */ -ProcessExecution.prototype.recover = function recover(state) { +ProcessExecution.prototype.recover = function recover(state, recoveredVersion) { if (!state) return this; this.executionId = state.executionId; + this[K_RECOVERED_VERSION] = recoveredVersion; this[_constants.K_STOPPED] = state.stopped; this[_constants.K_COMPLETED] = state.completed; this[_constants.K_STATUS] = state.status; @@ -740,16 +745,9 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, } case 'activity.end': { - if (!content.isStartEvent) break; - const elements = this[K_ELEMENTS]; - if (elements.startEventCount <= 1) break; - const startPeers = new Set(); - for (const msg of elements.postponed) { - const peerId = msg.content.id; - if (peerId !== content.id && msg.content.isStartEvent) startPeers.add(msg); - } - elements.startEventCount = 0; - for (const msg of startPeers) this._getChildApi(msg).discard(); + if (!(content.isStartEvent || this.getActivityById(content.id)?.isStartEvent)) break; + if (this[K_ELEMENTS].startEventCount <= 1) break; + this._discardArmedStartEvents(content.id); break; } case 'activity.error': @@ -1041,6 +1039,42 @@ ProcessExecution.prototype._getChildById = function getChildById(childId) { return this.getActivityById(childId) || this._getFlowById(childId); }; +/** + * Discard the other armed start events once one mutually exclusive entry point wins. + * Resolves the start-event flag from the live activity so recovered pre-flag state is handled. + * @internal + */ +ProcessExecution.prototype._discardArmedStartEvents = function discardArmedStartEvents(winnerId) { + const elements = this[K_ELEMENTS]; + const startPeers = []; + for (const msg of elements.postponed) { + const peerId = msg.content.id; + if (peerId === winnerId) continue; + if (this.getActivityById(peerId)?.isStartEvent) startPeers.push(msg); + } + if (!startPeers.length) return; + elements.startEventCount = 0; + for (const msg of startPeers) this._getChildApi(msg).discard(); +}; + +/** + * On resume of a state from an older major, discard start events left armed when another entry + * point already won before recovery. The winning start event's `activity.end` cannot replay, so + * the live discard trigger never fires. + * @internal + */ +ProcessExecution.prototype._reconcileStartEvents = function reconcileStartEvents() { + const elements = this[K_ELEMENTS]; + if (elements.startEventCount <= 1) return; + if (!(this[K_RECOVERED_VERSION] < _constants.STATE_VERSION)) return; + for (const child of elements.children) { + if (child.isStartEvent && child.counters.taken) { + this._discardArmedStartEvents(); + return; + } + } +}; + /** @internal */ ProcessExecution.prototype._getChildApi = function getChildApi(message) { const content = message.content; diff --git a/package.json b/package.json index 734f7095..503c52de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bpmn-elements", - "version": "18.0.0", + "version": "18.0.1", "description": "Executable workflow elements based on BPMN 2.0", "type": "module", "main": "./dist/index.js", diff --git a/src/constants.js b/src/constants.js index 177110d1..c6ba5b1f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -13,3 +13,9 @@ export const K_STATE_MESSAGE = Symbol.for('stateMessage'); export const K_STATUS = Symbol.for('status'); export const K_STOPPED = Symbol.for('stopped'); export const K_TARGETS = Symbol.for('targets'); + +/** + * State version. Tracks the package major; bump on each major. Recovering an older major triggers + * migrations. Unstamped legacy states are treated as version 0. + */ +export const STATE_VERSION = 18; diff --git a/src/definition/Definition.js b/src/definition/Definition.js index 30e7d36b..48825dea 100644 --- a/src/definition/Definition.js +++ b/src/definition/Definition.js @@ -13,6 +13,7 @@ import { K_STATE_MESSAGE, K_STATUS, K_STOPPED, + STATE_VERSION, } from '../constants.js'; /** @@ -181,6 +182,7 @@ Definition.prototype.resume = function resume(callback) { */ Definition.prototype.getState = function getState() { return this._createMessage({ + stateVersion: STATE_VERSION, status: this.status, stopped: this.stopped, counters: this.counters, @@ -200,6 +202,11 @@ Definition.prototype.recover = function recover(state) { if (this.isRunning) throw new Error('cannot recover running definition'); if (!state) return this; + const recoveredVersion = state.stateVersion || 0; + if (recoveredVersion !== STATE_VERSION) { + this.logger.debug(`<${this.id}> recover state version ${recoveredVersion} into runtime state version ${STATE_VERSION}`); + } + this[K_STOPPED] = !!state.stopped; this[K_STATUS] = state.status; @@ -212,7 +219,7 @@ Definition.prototype.recover = function recover(state) { this.environment.recover(state.environment); if (state.execution) { - exec.set('execution', new DefinitionExecution(this, this.context).recover(state.execution)); + exec.set('execution', new DefinitionExecution(this, this.context).recover(state.execution, recoveredVersion)); } this.broker.recover(state.broker); diff --git a/src/definition/DefinitionExecution.js b/src/definition/DefinitionExecution.js index d52cdb49..3fb7b475 100644 --- a/src/definition/DefinitionExecution.js +++ b/src/definition/DefinitionExecution.js @@ -189,9 +189,10 @@ DefinitionExecution.prototype.resume = function resume() { /** * Restore execution state captured by getState. Reinstates running processes from the snapshot. * @param {import('#types').DefinitionExecutionState} [state] + * @param {number} [recoveredVersion] State version * @returns {this} */ -DefinitionExecution.prototype.recover = function recover(state) { +DefinitionExecution.prototype.recover = function recover(state, recoveredVersion) { if (!state) return this; this.executionId = state.executionId; @@ -216,7 +217,7 @@ DefinitionExecution.prototype.recover = function recover(state) { if (!bp) continue; ids.add(bpid); - bp.recover(bpState); + bp.recover(bpState, recoveredVersion); running.add(bp); } diff --git a/src/process/Process.js b/src/process/Process.js index 456c0639..fd7c6e3d 100644 --- a/src/process/Process.js +++ b/src/process/Process.js @@ -190,10 +190,11 @@ Process.prototype.getState = function getState() { /** * Restore process state captured by getState. * @param {import('#types').ProcessState} [state] + * @param {number} [recoveredVersion] State version * @returns {this} * @throws {Error} when called on a running process */ -Process.prototype.recover = function recover(state) { +Process.prototype.recover = function recover(state, recoveredVersion) { if (this.isRunning) throw new Error(`cannot recover running process <${this.id}>`); if (!state) return this; @@ -205,7 +206,7 @@ Process.prototype.recover = function recover(state) { this.environment.recover(state.environment); if (state.execution) { - exec.set('execution', new ProcessExecution(this, this.context).recover(state.execution)); + exec.set('execution', new ProcessExecution(this, this.context).recover(state.execution, recoveredVersion)); } this.broker.recover(state.broker); diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 3d724b17..af217dbb 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -2,13 +2,14 @@ import { ProcessApi } from '../Api.js'; import { cloneContent, cloneMessage, pushParent } from '../messageHelper.js'; import { getUniqueId } from '../shared.js'; import { ActivityTracker } from '../Tracker.js'; -import { K_ACTIVATED, K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS, K_STATUS, K_STOPPED } from '../constants.js'; +import { K_ACTIVATED, K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS, K_STATUS, K_STOPPED, STATE_VERSION } from '../constants.js'; const K_ACTIVITY_Q = Symbol.for('activityQ'); const K_ELEMENTS = Symbol.for('elements'); const K_PARENT = Symbol.for('parent'); const K_TRACKER = Symbol.for('activity tracker'); const K_PEERS_DISCOVERED = Symbol.for('peers discovered'); +const K_RECOVERED_VERSION = Symbol.for('recovered version'); /** * Drives the execution of a single process or sub-process: activates children, routes activity @@ -166,6 +167,10 @@ ProcessExecution.prototype.resume = function resume() { if (this[K_COMPLETED]) return; + this._reconcileStartEvents(); + + if (this[K_COMPLETED]) return; + if (!postponed.size && status === 'executing') return this._complete('completed'); }; @@ -204,11 +209,13 @@ ProcessExecution.prototype.getState = function getState() { /** * Restore execution state captured by getState. * @param {import('#types').ProcessExecutionState} [state] + * @param {number} [recoveredVersion] State version * @returns {this} */ -ProcessExecution.prototype.recover = function recover(state) { +ProcessExecution.prototype.recover = function recover(state, recoveredVersion) { if (!state) return this; this.executionId = state.executionId; + this[K_RECOVERED_VERSION] = recoveredVersion; this[K_STOPPED] = state.stopped; this[K_COMPLETED] = state.completed; @@ -738,17 +745,9 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, break; } case 'activity.end': { - if (!content.isStartEvent) break; - const elements = this[K_ELEMENTS]; - if (elements.startEventCount <= 1) break; - - const startPeers = new Set(); - for (const msg of elements.postponed) { - const peerId = msg.content.id; - if (peerId !== content.id && msg.content.isStartEvent) startPeers.add(msg); - } - elements.startEventCount = 0; - for (const msg of startPeers) this._getChildApi(msg).discard(); + if (!(content.isStartEvent || this.getActivityById(content.id)?.isStartEvent)) break; + if (this[K_ELEMENTS].startEventCount <= 1) break; + this._discardArmedStartEvents(content.id); break; } case 'activity.error': { @@ -1055,6 +1054,43 @@ ProcessExecution.prototype._getChildById = function getChildById(childId) { return this.getActivityById(childId) || this._getFlowById(childId); }; +/** + * Discard the other armed start events once one mutually exclusive entry point wins. + * Resolves the start-event flag from the live activity so recovered pre-flag state is handled. + * @internal + */ +ProcessExecution.prototype._discardArmedStartEvents = function discardArmedStartEvents(winnerId) { + const elements = this[K_ELEMENTS]; + const startPeers = []; + for (const msg of elements.postponed) { + const peerId = msg.content.id; + if (peerId === winnerId) continue; + if (this.getActivityById(peerId)?.isStartEvent) startPeers.push(msg); + } + if (!startPeers.length) return; + elements.startEventCount = 0; + for (const msg of startPeers) this._getChildApi(msg).discard(); +}; + +/** + * On resume of a state from an older major, discard start events left armed when another entry + * point already won before recovery. The winning start event's `activity.end` cannot replay, so + * the live discard trigger never fires. + * @internal + */ +ProcessExecution.prototype._reconcileStartEvents = function reconcileStartEvents() { + const elements = this[K_ELEMENTS]; + if (elements.startEventCount <= 1) return; + if (!(this[K_RECOVERED_VERSION] < STATE_VERSION)) return; + + for (const child of elements.children) { + if (child.isStartEvent && child.counters.taken) { + this._discardArmedStartEvents(); + return; + } + } +}; + /** @internal */ ProcessExecution.prototype._getChildApi = function getChildApi(message) { const content = message.content; diff --git a/test/feature/backward-compatability-feature.js b/test/feature/backward-compatability-feature.js index 2491dc21..f55e308d 100644 --- a/test/feature/backward-compatability-feature.js +++ b/test/feature/backward-compatability-feature.js @@ -89,4 +89,25 @@ Feature('Backward compatability', () => { return leave; }); }); + + Scenario('State is stamped with a state version', () => { + let context; + before(async () => { + context = await testHelpers.context(motherOfAllSource); + }); + + let definition, state; + Given('a running definition', () => { + definition = new Definition(context); + definition.run(); + }); + + When('state is saved', () => { + state = definition.getState(); + }); + + Then('it is stamped with a positive state version', () => { + expect(state.stateVersion).to.be.a('number').that.is.above(0); + }); + }); }); diff --git a/test/feature/multiple-startevent-feature.js b/test/feature/multiple-startevent-feature.js index e7a09f63..80230f5b 100644 --- a/test/feature/multiple-startevent-feature.js +++ b/test/feature/multiple-startevent-feature.js @@ -454,6 +454,121 @@ Feature('Multiple start events', () => { }); }); + Scenario('Recover a pre-flag state where the start events are still armed', () => { + // State saved before the isStartEvent flag existed lacks it on persisted messages. + function stripStartEventFlag(value) { + if (Array.isArray(value)) return value.forEach(stripStartEventFlag); + if (value && typeof value === 'object') { + delete value.isStartEvent; + for (const key of Object.keys(value)) stripStartEventFlag(value[key]); + } + } + + let state; + Given('a stopped process state without the isStartEvent flag while all entry points are armed', async () => { + const definition = new Definition(await testHelpers.context(startAndReceiveSource)); + definition.run(); + definition.stop(); + state = JSON.parse(JSON.stringify(definition.getState())); + stripStartEventFlag(state); + delete state.stateVersion; + }); + + let recovered, leave; + When('the legacy state is recovered and resumed', async () => { + recovered = new Definition(await testHelpers.context(startAndReceiveSource)).recover(state); + leave = recovered.waitFor('leave'); + recovered.resume(); + }); + + Then('all entry points are armed in the recovered definition', () => { + expect(recovered.getPostponed().map(({ id }) => id)).to.have.members(['start1', 'start2', 'receive']); + }); + + When('the first start event is signaled after resume', () => { + recovered.signal({ id: 'Signal1' }); + }); + + Then('the first start event ran and the second is discarded as an alternative entry point', () => { + expect(recovered.getActivityById('start1').counters).to.include({ taken: 1 }); + expect(recovered.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); + }); + + And('only the receive task is left armed', () => { + expect(recovered.getPostponed().map(({ id }) => id)).to.deep.equal(['receive']); + }); + + When('the receive task is signaled with its message', () => { + recovered.sendMessage({ id: 'Message1' }); + }); + + Then('the recovered process completed', async () => { + await leave; + expect(recovered.counters).to.include({ completed: 1 }); + }); + }); + + Scenario('Recover a state where one entry point already won before recovery', () => { + let state; + Given('a stopped process state where the first start event already ran but the second is still armed', async () => { + // Pre-mutual-exclusion behaviour left alternative entry points concurrently armed. + // Reconstruct it: the winning start event has left, the losing start event is still armed. + const armedDefinition = new Definition(await testHelpers.context(startAndReceiveSource)); + armedDefinition.run(); + armedDefinition.stop(); + const armed = JSON.parse(JSON.stringify(armedDefinition.getState())); + + const advancedDefinition = new Definition(await testHelpers.context(startAndReceiveSource)); + advancedDefinition.run(); + advancedDefinition.signal({ id: 'Signal1' }); + advancedDefinition.stop(); + state = JSON.parse(JSON.stringify(advancedDefinition.getState())); + + const armedProc = armed.execution.processes[0]; + const proc = state.execution.processes[0]; + + const armedStart2 = armedProc.execution.children.find((c) => c.id === 'start2'); + const children = proc.execution.children; + children[children.findIndex((c) => c.id === 'start2')] = armedStart2; + + const armedQueue = armedProc.broker.queues.find((q) => /execute-/.test(q.name)); + const queue = proc.broker.queues.find((q) => /execute-/.test(q.name)); + queue.messages = queue.messages.filter((m) => m.content?.id !== 'start2'); + queue.messages.push(armedQueue.messages.find((m) => m.content.id === 'start2')); + + // This shape only arises from a major before start events became mutually exclusive. + delete state.stateVersion; + }); + + let recovered, leave; + When('the state is recovered and resumed', async () => { + recovered = new Definition(await testHelpers.context(startAndReceiveSource)).recover(JSON.parse(JSON.stringify(state))); + leave = recovered.waitFor('leave'); + recovered.resume(); + }); + + Then('the start event that already won is kept', () => { + expect(recovered.getActivityById('start1').counters).to.include({ taken: 1 }); + }); + + And('the start event still armed is discarded as an alternative entry point', () => { + expect(recovered.getActivityById('start2').counters).to.include({ taken: 0, discarded: 1 }); + }); + + And('only the receive task is left armed', () => { + expect(recovered.getPostponed().map(({ id }) => id)).to.deep.equal(['receive']); + }); + + When('the receive task is signaled with its message', () => { + recovered.sendMessage({ id: 'Message1' }); + }); + + Then('the recovered process completed', async () => { + await leave; + expect(recovered.counters).to.include({ completed: 1 }); + }); + }); + Scenario('A timer start event combined with a signal start event', () => { const source = ` diff --git a/types/index.d.ts b/types/index.d.ts index 8b526945..0eed39fb 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -407,6 +407,8 @@ declare module 'bpmn-elements' { } export interface DefinitionState extends ElementState { + /** State version. Absent on states saved before versioning. */ + stateVersion?: number; status: DefinitionStatus; stopped: boolean; executionId?: string; @@ -1046,8 +1048,9 @@ declare module 'bpmn-elements' { resume(): number | undefined; /** * Restore execution state captured by getState. Reinstates running processes from the snapshot. + * @param recoveredVersion State version * */ - recover(state?: DefinitionExecutionState): this; + recover(state?: DefinitionExecutionState, recoveredVersion?: number): this; /** * Stop the running execution via the api. */ @@ -1472,9 +1475,10 @@ declare module 'bpmn-elements' { getState(): ProcessState; /** * Restore process state captured by getState. + * @param recoveredVersion State version * @throws {Error} when called on a running process */ - recover(state?: ProcessState): this; + recover(state?: ProcessState, recoveredVersion?: number): this; /** * Walk activity graph from the given start id, or every start activity when omitted. * */ @@ -1660,8 +1664,9 @@ declare module 'bpmn-elements' { getState(): ProcessExecutionState; /** * Restore execution state captured by getState. + * @param recoveredVersion State version * */ - recover(state?: ProcessExecutionState): this; + recover(state?: ProcessExecutionState, recoveredVersion?: number): this; /** * Walk activity graph from the given start id, or every start activity when omitted. * */ diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index fe2286dd..b20dfae7 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -505,6 +505,8 @@ export interface DefinitionExecutionState { } export interface DefinitionState extends ElementState { + /** State version. Absent on states saved before versioning. */ + stateVersion?: number; status: DefinitionStatus; stopped: boolean; executionId?: string; From 44345e425d8bd7236c9ccc5322cee91d459684e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Tue, 16 Jun 2026 06:30:10 +0200 Subject: [PATCH 29/31] cleanup some parallel gateway instance props --- dist/events/BoundaryEvent.js | 4 +- dist/gateways/ParallelGateway.js | 38 ++++-- src/events/BoundaryEvent.js | 4 +- src/gateways/ParallelGateway.js | 35 ++++-- test/feature/parallel-gateway-feature.js | 140 +++++++++++++++++++++++ types/index.d.ts | 49 +++++--- 6 files changed, 232 insertions(+), 38 deletions(-) diff --git a/dist/events/BoundaryEvent.js b/dist/events/BoundaryEvent.js index 2e96fb82..34a3da64 100644 --- a/dist/events/BoundaryEvent.js +++ b/dist/events/BoundaryEvent.js @@ -44,9 +44,9 @@ Object.defineProperty(BoundaryEventBehaviour.prototype, 'executionId', { } }); Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', { + /** @returns {boolean} */ get() { - const behaviour = this.activity.behaviour || {}; - return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true; + return this.activity.behaviour?.cancelActivity ?? true; } }); diff --git a/dist/gateways/ParallelGateway.js b/dist/gateways/ParallelGateway.js index 277eedf5..8303a3f2 100644 --- a/dist/gateways/ParallelGateway.js +++ b/dist/gateways/ParallelGateway.js @@ -76,11 +76,15 @@ function ParallelGatewayBehaviour(activity) { this.type = activity.type; this.activity = activity; this.broker = activity.broker; + /** + * Inbound taken sequence flow sequences + * @type {Set [...v]).flat()); this[_constants.K_TARGETS] = new Map([...peerIds].map(pid => [pid, this.activity.getActivityById(pid)])); @@ -142,9 +152,7 @@ ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { exclusive: true, prefetch: 10000 }); - if (this.isConverging) { - this.broker.publish('event', 'activity.converge', (0, _messageHelper.cloneContent)(executeContent)); - } + this.broker.publish('event', 'activity.converge', (0, _messageHelper.cloneContent)(executeContent)); return this.broker.publish('execution', 'execute.start', (0, _messageHelper.cloneContent)(executeMessage.content, { preventComplete: true, state: STATE_SETUP @@ -179,17 +187,19 @@ ParallelGatewayBehaviour.prototype._stop = function stop() { this.broker.cancel('_parallel-execution-peer-enter-tag'); this.peerMonitor.stop(); }; + +/** + * Peer monitor + * @param {import('#types').Activity} activity parallel gateway activity + * @param {Map 0; } }); + +/** + * Execute peer monitor + * @param {import('#types').ElementBrokerMessage} executeMessage + * @returns {number} number of running peers + */ PeerMonitor.prototype.execute = function execute(executeMessage) { const message = (0, _messageHelper.cloneMessage)(executeMessage); const inbound = message.content.inbound.pop(); @@ -208,12 +224,16 @@ PeerMonitor.prototype.execute = function execute(executeMessage) { state: STATE_MONTITORING, preventComplete: true }); - this.touched.add(inbound.sourceId); for (const target of this.targets.values()) { this.monitor(target); } return this.running.size; }; + +/** + * Monitor peer activity + * @param {import('#types').Activity} peerActivity + */ PeerMonitor.prototype.monitor = function monitor(peerActivity) { if (this.watching.has(peerActivity.id)) return; this.activity.logger.debug(`<${this.id}> monitor <${peerActivity.id}> with status: ${peerActivity.status}`); diff --git a/src/events/BoundaryEvent.js b/src/events/BoundaryEvent.js index dae9f6e6..c724f5d5 100644 --- a/src/events/BoundaryEvent.js +++ b/src/events/BoundaryEvent.js @@ -41,9 +41,9 @@ Object.defineProperty(BoundaryEventBehaviour.prototype, 'executionId', { }); Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', { + /** @returns {boolean} */ get() { - const behaviour = this.activity.behaviour || {}; - return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true; + return this.activity.behaviour?.cancelActivity ?? true; }, }); diff --git a/src/gateways/ParallelGateway.js b/src/gateways/ParallelGateway.js index 731e8d3f..67beba67 100644 --- a/src/gateways/ParallelGateway.js +++ b/src/gateways/ParallelGateway.js @@ -74,13 +74,17 @@ export function ParallelGatewayBehaviour(activity) { this.type = activity.type; this.activity = activity; this.broker = activity.broker; + /** + * Inbound taken sequence flow sequences + * @type {Set [...v]).flat()); this[K_TARGETS] = new Map([...peerIds].map((pid) => [pid, this.activity.getActivityById(pid)])); @@ -152,9 +161,7 @@ ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) { { consumerTag: '_converging-inbound', exclusive: true, prefetch: 10000 } ); - if (this.isConverging) { - this.broker.publish('event', 'activity.converge', cloneContent(executeContent)); - } + this.broker.publish('event', 'activity.converge', cloneContent(executeContent)); return this.broker.publish( 'execution', @@ -197,17 +204,18 @@ ParallelGatewayBehaviour.prototype._stop = function stop() { this.peerMonitor.stop(); }; +/** + * Peer monitor + * @param {import('#types').Activity} activity parallel gateway activity + * @param {Map { }); }); + Scenario('A process with a single parallel gateway with one inbound and one outbound fed by task peers wrapped in a loopback', () => { + const source = ` + + + + + + + + + + + + + + + + + + \${environment.services.takeOnce()} + + + + + `; + + let context; + /** @type {Definition} */ + let definition; + Given('a definition matching the scenario', async () => { + context = await testHelpers.context(source); + definition = new Definition(context, { services: getTakeServices() }); + }); + + let leave; + let endMsg; + When('definition is ran', () => { + leave = definition.waitFor('leave'); + + definition.broker.subscribeTmp( + 'event', + 'activity.end', + (_, msg) => { + if (msg.content.id === 'gateway') endMsg = msg; + }, + { noAck: true } + ); + + definition.run(); + }); + + Then('run completes', () => { + return leave; + }); + + let gateway; + And('parallel gateway was taken twice, once per loop', () => { + gateway = definition.getActivityById('gateway'); + expect(gateway.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + + And('gateway has one inbound and one outbound flow', () => { + expect(gateway.inbound).to.have.length(1); + expect(gateway.outbound).to.have.length(1); + }); + + And('gateway end message has the taken inbound sequence flow', () => { + expect(endMsg.content.inbound).to.have.length(1); + }); + + And('each upstream task peer was taken twice', () => { + for (const id of ['task1', 'task2', 'task3']) { + expect(definition.getActivityById(id).counters, id).to.deep.equal({ taken: 2, discarded: 0 }); + } + }); + + And('no pending inbound exists', () => { + expect(gateway.broker.getQueue('inbound-q').messageCount).to.equal(0); + }); + + And('end event was taken once', () => { + expect(definition.getActivityById('end').counters).to.deep.equal({ taken: 1, discarded: 0 }); + }); + + let stopped; + let state; + When('ran again with a listener stopping run when gateway has started monitoring', () => { + definition = new Definition(context.clone(), { services: getTakeServices() }); + + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'gateway') { + definition.broker.cancel(msg.fields.consumerTag); + definition.stop(); + state = definition.getState(); + } + }, + { noAck: true, priority: 10000 } + ); + + stopped = definition.waitFor('stop'); + + definition.run(); + }); + + Then('run is stopped and state saved', async () => { + await stopped; + }); + + When('recovered and resumed from gateway', () => { + definition = new Definition(context.clone(), { services: getTakeServices() }).recover(state); + + leave = definition.waitFor('leave'); + + definition.resume(); + }); + + Then('run completes', () => { + return leave; + }); + + And('parallel gateway completed both loops', () => { + gateway = definition.getActivityById('gateway'); + expect(gateway.counters).to.deep.equal({ taken: 2, discarded: 0 }); + }); + }); + Scenario('Multiple asynchronous tasks joining in parallel join with some inbound touched more than once', () => { let context; /** @type {Definition} */ @@ -306,3 +435,14 @@ Feature('Parallel gateway', () => { }); }); }); + +function getTakeServices() { + return { + takeOnce({ content, environment }) { + const onceId = `${environment.variables.content.executionId}_${content.id}`; + const count = environment.variables[onceId] ?? 0; + environment.variables[onceId] = count + 1; + return count === 0; + }, + }; +} diff --git a/types/index.d.ts b/types/index.d.ts index 0eed39fb..7ec5b86e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1950,7 +1950,7 @@ declare module 'bpmn-elements' { environment: Environment; broker: ElementBroker; get executionId(): string | undefined; - get cancelActivity(): any; + get cancelActivity(): boolean; execute(executeMessage: ElementBrokerMessage): void; } @@ -2106,29 +2106,48 @@ declare module 'bpmn-elements' { type: string; activity: Activity; broker: ElementBroker; - inbound: Set; - isConverging: boolean; - get executionId(): any; + /** + * Inbound taken sequence flow sequences + * */ + inbound: Set; + get executionId(): string | undefined; execute(executeMessage: ElementBrokerMessage): void; - setup(executeMessage: any): number | undefined; + /** + * Setup peer monitor + * */ + setup(executeMessage: ElementBrokerMessage): void; peerMonitor: PeerMonitor | undefined; } + /** + * Peer monitor + * @param activity parallel gateway activity + * @param targets parallel gateway peer target activities + */ class PeerMonitor { - constructor(activity: any, targets: any); - activity: any; - id: any; - broker: any; + /** + * Peer monitor + * @param activity parallel gateway activity + * @param targets parallel gateway peer target activities + */ + constructor(activity: Activity, targets: Map); + activity: Activity; + id: string | undefined; + broker: ElementBroker; running: Map; - index: number; - discarded: number; watching: Map; - targets: any; - touched: Set; + targets: Map; inbound: any[]; get isRunning(): boolean; - execute(executeMessage: any): number; - monitor(peerActivity: any): void; + /** + * Execute peer monitor + * @returns number of running peers + */ + execute(executeMessage: ElementBrokerMessage): number; + /** + * Monitor peer activity + * */ + monitor(peerActivity: Activity): void; stop(): void; } /** From 293ceb2e7a159b28d74e1d216c6e57ab11216012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Tue, 23 Jun 2026 09:50:30 +0200 Subject: [PATCH 30/31] link catch events and start event emit init - queue inbound init message to trigger run --- AGENTS.md | 2 + CHANGELOG.md | 4 ++ dist/activity/Activity.js | 90 ++++++++++++++-------------- dist/process/ProcessExecution.js | 2 +- docs/Activity.md | 3 +- docs/Extend.md | 2 +- package.json | 2 +- src/activity/Activity.js | 62 +++++++++---------- src/process/ProcessExecution.js | 2 +- test/activity/Activity-test.js | 7 ++- test/feature/link-as-goto-feature.js | 18 ++++++ types/index.d.ts | 3 +- 12 files changed, 111 insertions(+), 86 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8ab9a906..4d2486cc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,6 +68,8 @@ Documented in `docs/Extend.md` and `docs/Extension.md`: ### State & behavioral invariants - **No flow discards.** Outbound sequence flows are never discarded; flow and activity `discarded` counters stay `0`. There is no `skipDiscard` setting. Parallel joins rely on cached gateway peers, not on discarded flows. +- **Activities are armed through the inbound queue, then run consumer-driven.** Both start activities (`isStart`, no inbound trigger) and link catch events are armed by `Activity.init()`: it mints an executionId, emits the `init` event (whose placeholder in the process's `postponed` set blocks premature completion), increments an `initialized` counter, and queues a non-persistent `activity.init` message carrying that id (plus the activity `id`) on the activity's own `inbound-q`. The run is then driven by the inbound consumer: `_consumeInbound` asserts the consumer when the queue has a pending message even without sequence-flow triggers, and `_onInbound`'s `activity.init` case decrements the counter and calls `run()` with the carried id. `ProcessExecution._start` arms start activities this way (`init()` then `_consumeInbound()`, no direct `run()`). A throwing link publishes `activity.link`; the catch's construction-time inbound-trigger handler calls the catch's own `init()` to arm it identically — there is no `activity.relink`. The `initialized` getter reads the counter (exec-state, not persisted); since the `activity.init` trigger is `persistent: false` it is dropped on recover and never re-consumed, so counter and trigger reset together (a stop/resume while armed cannot desync them). +- **`run()` executionId resolution.** `run(runContent)` uses `runContent.initExecutionId` when `runContent.id` equals the activity's own id, otherwise mints a fresh `getUniqueId(id)`. The init/link handoff (`_onInbound`) always passes a matching `id`, so the reserved id is honoured; every other caller (e.g. delegated event runs passing `run(content.message)`) carries no matching id and gets a fresh one. `run()` does **not** peek the inbound queue, and there is no `initExecutionId` exec-state key. `initExecutionId` is **destructured out** of `runContent` so it never reaches the `run.enter`/`run.start` content (it would otherwise leak through `_createMessage`, which only overwrites `id`/`type`/flags, into every downstream message and saved state). - **Multiple start events are mutually exclusive entry points.** The first start event to fire discards the others still armed, so two start branches can never both run. - **`stateVersion`.** `Definition.getState()` stamps `stateVersion` (the package major, hardcoded in `src/constants.js`); recovering an older major triggers migrations (e.g. start event reconciliation on resume). Unstamped legacy states are treated as version `0`. Bump the constant on each major release. diff --git a/CHANGELOG.md b/CHANGELOG.md index 99cad39c..a27f6e68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v18.0.2 - 2026-06-24 + +- Refactor catching `LinkEventDefinition` trigger and start event init handling. Both publishes `activity.init` to reserve process attention and queues messages on inbound queue that are eventually handled + ## v18.0.1 - 2026-06-13 ### Fixes diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index 3b032f8f..e97619f7 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -268,7 +268,7 @@ Object.defineProperties(Activity.prototype, { }, initialized: { get() { - return !!this[K_EXEC]?.get('initExecutionId'); + return this[K_EXEC].get('initialized') > 0; } } }); @@ -280,7 +280,8 @@ Object.defineProperties(Activity.prototype, { Activity.prototype.activate = function activate() { if (this[_constants.K_ACTIVATED]) return; this[_constants.K_ACTIVATED] = true; - return this.addInboundListeners() && this._consumeInbound(); + this.addInboundListeners(); + return this._consumeInbound(); }; /** @internal */ @@ -326,17 +327,28 @@ Activity.prototype.deactivate = function deactivate() { /** * Initialise activity executionId and emit init event without starting the run. * @param {Record} [initContent] Optional content merged into the init message + * @param {import('smqp').MessageProperties} [properties] Optional message properties merged into the init message properties */ -Activity.prototype.init = function init(initContent) { +Activity.prototype.init = function init(initContent, properties) { const id = this.id; const exec = this[K_EXEC]; - const executionId = exec.has('initExecutionId') ? exec.get('initExecutionId') : (0, _shared.getUniqueId)(id); - exec.set('initExecutionId', executionId); + exec.set('initialized', (exec.get('initialized') || 0) + 1); + const executionId = (0, _shared.getUniqueId)(id); this.logger.debug(`<${id}> initialized with executionId <${executionId}>`); this._publishEvent('init', this._createMessage({ ...initContent, executionId })); + this.broker.getQueue('inbound-q').queueMessage({ + routingKey: 'activity.init' + }, { + ...initContent, + id, + executionId + }, { + persistent: false, + ...properties + }); }; /** @@ -347,13 +359,15 @@ Activity.prototype.init = function init(initContent) { Activity.prototype.run = function run(runContent) { const id = this.id; if (this.isRunning) throw new Error(`activity <${id}> is already running`); - const exec = this[K_EXEC]; - const executionId = exec.get('initExecutionId') || (0, _shared.getUniqueId)(id); - exec.set('executionId', executionId); - exec.delete('initExecutionId'); + const { + initExecutionId, + ...runMessage + } = runContent || {}; + const executionId = runMessage?.id === id && initExecutionId ? initExecutionId : (0, _shared.getUniqueId)(id); + this[K_EXEC].set('executionId', executionId); this._consumeApi(); const content = this._createMessage({ - ...runContent, + ...runMessage, executionId }); const broker = this.broker; @@ -558,10 +572,8 @@ Activity.prototype.getActivityById = function getActivityById(elementId) { /** @internal */ Activity.prototype._runDiscard = function runDiscard(discardContent) { - const exec = this[K_EXEC]; - const executionId = exec.get('initExecutionId') || (0, _shared.getUniqueId)(this.id); - exec.set('executionId', executionId); - exec.delete('initExecutionId'); + const executionId = (0, _shared.getUniqueId)(this.id); + this[K_EXEC].set('executionId', executionId); this._consumeApi(); const content = this._createMessage({ ...discardContent, @@ -677,8 +689,9 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { /** @internal */ Activity.prototype._consumeInbound = function consumeInbound() { if (!this[_constants.K_ACTIVATED]) return; - if (this.status || !this._getInboundTriggers().length) return; + if (this.status) return; const inboundQ = this.broker.getQueue('inbound-q'); + if (!inboundQ.messageCount && !this._getInboundTriggers().length) return; const onInbound = this[_constants.K_MESSAGE_HANDLERS].onInbound; return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' @@ -691,26 +704,32 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { const broker = this.broker; broker.cancel('_run-on-inbound'); const content = message.content; - const inbound = [(0, _messageHelper.cloneContent)(content)]; switch (routingKey) { - case 'activity.relink': - if (content.executionId) this[K_EXEC].set('initExecutionId', content.executionId); - return this.run({ - message: content.message, - inbound - }); + case 'activity.init': + { + const exec = this[K_EXEC]; + exec.set('initialized', (exec.get('initialized') || 0) - 1); + return this.run({ + initExecutionId: content.executionId, + id: content.id, + message: content.message, + ...(content.inbound?.length && { + inbound: content.inbound + }) + }); + } case 'association.take': case 'flow.take': case 'activity.restart': case 'activity.enter': return this.run({ message: content.message, - inbound + inbound: [(0, _messageHelper.cloneContent)(content)] }); case 'activity.discard': { return this._runDiscard({ - inbound + inbound: [(0, _messageHelper.cloneContent)(content)] }); } } @@ -740,26 +759,9 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message { const linkName = content.message?.linkName; if (!this[K_FLAGS].linkNames?.includes(linkName)) break; - const executionId = (0, _shared.getUniqueId)(this.id); - this.broker.publish('event', 'activity.enter', (0, _messageHelper.cloneContent)(content, { - id: this.id, - type: this.type, - executionId, - state: 'enter', - message: { - ...content.message - } - })); - inboundQ.queueMessage({ - routingKey: 'activity.relink' - }, (0, _messageHelper.cloneContent)(content, { - id: this.id, - executionId, - message: { - ...content.message - } - }), properties); - return; + return this.init({ + inbound: [(0, _messageHelper.cloneContent)(content)] + }); } case 'association.take': case 'flow.take': diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index bdae9206..dd753bb6 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -391,7 +391,7 @@ ProcessExecution.prototype._start = function start() { this._shakeOnStart(); for (const a of startActivities) a.init(); this[_constants.K_STATUS] = 'executing'; - for (const a of startActivities) a.run(); + for (const a of startActivities) a._consumeInbound(); if (!startActivities.size) { for (const a of this[K_ELEMENTS].triggeredByEvent) { if (a.isCatching && !a.isRunning) a.run(); diff --git a/docs/Activity.md b/docs/Activity.md index 30aa1af0..f116b023 100644 --- a/docs/Activity.md +++ b/docs/Activity.md @@ -97,11 +97,12 @@ Get activity state. If `environment.settings.disableTrackState === true` the sta ### `init([initContent])` -Initialize the activity without running. Publishes an `activity.init` event with an execution id reserved for the next run. +Initialize the activity without running. Publishes an `activity.init` event with an execution id reserved for the next run, and queues a non-persistent `activity.init` message on the activity's inbound queue. When the inbound queue is consumed the activity runs with that reserved id. This is how start activities and link catch events are armed. Arguments: - `initContent`: optional object merged into the init message content +- `properties`: optional message properties merged into the queued inbound message ### `addInboundListeners()` diff --git a/docs/Extend.md b/docs/Extend.md index b4717077..77d732f0 100644 --- a/docs/Extend.md +++ b/docs/Extend.md @@ -181,7 +181,7 @@ Link catches are wired to their matching throws at activity construction. The wi - The moddle entity's `type` must end with `LinkEventDefinition` (e.g. `bpmn:LinkEventDefinition`, `myns:LinkEventDefinition`). This is the only string-based check — once the first matching definition is found, all subsequent matches compare against the resolved `Behaviour` reference, so any rename is honoured. - Expose the link name on `behaviour.name` (the moddle default). - The Behaviour signature is `(activity, eventDefinition, context, index)`. -- When throwing (`activity.isThrowing`), publish `activity.link` on the activity's `event` exchange with `content.message.linkName` set. The catch's construction-time inbound trigger listens for this and queues an `activity.relink` to drive the catch's run cycle. +- When throwing (`activity.isThrowing`), publish `activity.link` on the activity's `event` exchange with `content.message.linkName` set. The catch's construction-time inbound trigger listens for this and calls the catch's `init()`, which queues an `activity.init` message on the catch's inbound queue to drive its run cycle. - Publish `execute.completed` on the `execution` exchange so the throwing activity terminates. - When catching, publish `activity.catch` on the `event` exchange and complete with `execute.completed`. `Activity` drives the rest of the lifecycle. diff --git a/package.json b/package.json index 503c52de..d13da792 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bpmn-elements", - "version": "18.0.1", + "version": "18.0.2", "description": "Executable workflow elements based on BPMN 2.0", "type": "module", "main": "./dist/index.js", diff --git a/src/activity/Activity.js b/src/activity/Activity.js index 018916c6..aa137407 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -262,7 +262,7 @@ Object.defineProperties(Activity.prototype, { }, initialized: { get() { - return !!this[K_EXEC]?.get('initExecutionId'); + return this[K_EXEC].get('initialized') > 0; }, }, }); @@ -274,7 +274,8 @@ Object.defineProperties(Activity.prototype, { Activity.prototype.activate = function activate() { if (this[K_ACTIVATED]) return; this[K_ACTIVATED] = true; - return this.addInboundListeners() && this._consumeInbound(); + this.addInboundListeners(); + return this._consumeInbound(); }; /** @internal */ @@ -319,14 +320,18 @@ Activity.prototype.deactivate = function deactivate() { /** * Initialise activity executionId and emit init event without starting the run. * @param {Record} [initContent] Optional content merged into the init message + * @param {import('smqp').MessageProperties} [properties] Optional message properties merged into the init message properties */ -Activity.prototype.init = function init(initContent) { +Activity.prototype.init = function init(initContent, properties) { const id = this.id; const exec = this[K_EXEC]; - const executionId = exec.has('initExecutionId') ? exec.get('initExecutionId') : getUniqueId(id); - exec.set('initExecutionId', executionId); + exec.set('initialized', (exec.get('initialized') || 0) + 1); + const executionId = getUniqueId(id); this.logger.debug(`<${id}> initialized with executionId <${executionId}>`); this._publishEvent('init', this._createMessage({ ...initContent, executionId })); + this.broker + .getQueue('inbound-q') + .queueMessage({ routingKey: 'activity.init' }, { ...initContent, id, executionId }, { persistent: false, ...properties }); }; /** @@ -338,14 +343,13 @@ Activity.prototype.run = function run(runContent) { const id = this.id; if (this.isRunning) throw new Error(`activity <${id}> is already running`); - const exec = this[K_EXEC]; - const executionId = exec.get('initExecutionId') || getUniqueId(id); - exec.set('executionId', executionId); - exec.delete('initExecutionId'); + const { initExecutionId, ...runMessage } = runContent || {}; + const executionId = runMessage?.id === id && initExecutionId ? initExecutionId : getUniqueId(id); + this[K_EXEC].set('executionId', executionId); this._consumeApi(); - const content = this._createMessage({ ...runContent, executionId }); + const content = this._createMessage({ ...runMessage, executionId }); const broker = this.broker; broker.publish('run', 'run.enter', content); @@ -541,10 +545,8 @@ Activity.prototype.getActivityById = function getActivityById(elementId) { /** @internal */ Activity.prototype._runDiscard = function runDiscard(discardContent) { - const exec = this[K_EXEC]; - const executionId = exec.get('initExecutionId') || getUniqueId(this.id); - exec.set('executionId', executionId); - exec.delete('initExecutionId'); + const executionId = getUniqueId(this.id); + this[K_EXEC].set('executionId', executionId); this._consumeApi(); @@ -645,9 +647,11 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { Activity.prototype._consumeInbound = function consumeInbound() { if (!this[K_ACTIVATED]) return; - if (this.status || !this._getInboundTriggers().length) return; + if (this.status) return; const inboundQ = this.broker.getQueue('inbound-q'); + if (!inboundQ.messageCount && !this._getInboundTriggers().length) return; + const onInbound = this[K_MESSAGE_HANDLERS].onInbound; return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); @@ -660,25 +664,28 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) { broker.cancel('_run-on-inbound'); const content = message.content; - const inbound = [cloneContent(content)]; switch (routingKey) { - case 'activity.relink': - if (content.executionId) this[K_EXEC].set('initExecutionId', content.executionId); + case 'activity.init': { + const exec = this[K_EXEC]; + exec.set('initialized', (exec.get('initialized') || 0) - 1); return this.run({ + initExecutionId: content.executionId, + id: content.id, message: content.message, - inbound, + ...(content.inbound?.length && { inbound: content.inbound }), }); + } case 'association.take': case 'flow.take': case 'activity.restart': case 'activity.enter': return this.run({ message: content.message, - inbound, + inbound: [cloneContent(content)], }); case 'activity.discard': { - return this._runDiscard({ inbound }); + return this._runDiscard({ inbound: [cloneContent(content)] }); } } }; @@ -702,18 +709,7 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message case 'activity.link': { const linkName = content.message?.linkName; if (!this[K_FLAGS].linkNames?.includes(linkName)) break; - const executionId = getUniqueId(this.id); - this.broker.publish( - 'event', - 'activity.enter', - cloneContent(content, { id: this.id, type: this.type, executionId, state: 'enter', message: { ...content.message } }) - ); - inboundQ.queueMessage( - { routingKey: 'activity.relink' }, - cloneContent(content, { id: this.id, executionId, message: { ...content.message } }), - properties - ); - return; + return this.init({ inbound: [cloneContent(content)] }); } case 'association.take': case 'flow.take': diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index af217dbb..3f6e51c9 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -400,7 +400,7 @@ ProcessExecution.prototype._start = function start() { for (const a of startActivities) a.init(); this[K_STATUS] = 'executing'; - for (const a of startActivities) a.run(); + for (const a of startActivities) a._consumeInbound(); if (!startActivities.size) { for (const a of this[K_ELEMENTS].triggeredByEvent) { diff --git a/test/activity/Activity-test.js b/test/activity/Activity-test.js index 2d1dc35e..ce43d347 100644 --- a/test/activity/Activity-test.js +++ b/test/activity/Activity-test.js @@ -1083,7 +1083,7 @@ describe('Activity', () => { return initialized; }); - it('runs with execution id from init', async () => { + it('activate runs with execution id from init', async () => { let executionId; function SpecialBehaviour() { return { @@ -1096,7 +1096,7 @@ describe('Activity', () => { const initialized = activity.waitFor('init'); activity.init(); - activity.run(); + activity.activate(); const init = await initialized; expect(init.content.executionId).to.be.ok; @@ -1129,8 +1129,9 @@ describe('Activity', () => { expect(messages[0].fields).to.have.property('routingKey', 'activity.init'); expect(messages[0].content).to.have.property('executionId').that.is.ok; expect(messages[1].fields).to.have.property('routingKey', 'activity.init'); - expect(messages[1].content).to.have.property('executionId').that.is.ok.and.equal(messages[0].content.executionId); + expect(messages[1].content).to.have.property('executionId').that.is.ok.and.not.equal(messages[0].content.executionId); expect(messages[2].fields).to.have.property('routingKey', 'activity.init'); + expect(messages[2].content).to.have.property('executionId').that.is.ok.and.not.equal(messages[1].content.executionId); }); }); diff --git a/test/feature/link-as-goto-feature.js b/test/feature/link-as-goto-feature.js index ca7a44e9..87de7c70 100644 --- a/test/feature/link-as-goto-feature.js +++ b/test/feature/link-as-goto-feature.js @@ -34,7 +34,19 @@ Feature('Link as goto', () => { }); let end; + const linkCatch = []; When('definition is ran', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.start', + (_, msg) => { + if (msg.content.id === 'catch') { + linkCatch.push(msg); + } + }, + { noAck: true } + ); + end = definition.waitFor('end'); definition.run(); }); @@ -51,6 +63,12 @@ Feature('Link as goto', () => { expect(definition.getActivityById('catch').counters).to.deep.equal({ taken: 1, discarded: 0 }); }); + And('catch event has throw event as inbound', () => { + expect(linkCatch, 'catch start events').to.have.length(1); + expect(linkCatch[0].content.inbound, 'inbound length').to.have.length(1); + expect(linkCatch[0]?.content.inbound[0]).to.deep.include({ id: 'throw' }); + }); + And('downstream end after catch was reached', () => { expect(definition.getActivityById('end2').counters).to.have.property('taken', 1); }); diff --git a/types/index.d.ts b/types/index.d.ts index 7ec5b86e..65e4ab7d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -587,8 +587,9 @@ declare module 'bpmn-elements' { /** * Initialise activity executionId and emit init event without starting the run. * @param initContent Optional content merged into the init message + * @param properties Optional message properties merged into the init message properties */ - init(initContent?: Record): void; + init(initContent?: Record, properties?: import("smqp").MessageProperties): void; /** * Start running the activity by publishing run.enter and run.start. * @param runContent Optional content merged into the run message From c617843950c7e9f624c2d4d375010ba3f439c524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Wed, 24 Jun 2026 08:03:21 +0200 Subject: [PATCH 31/31] intermediage throw event with link is not isEnd --- AGENTS.md | 4 ++- CHANGELOG.md | 2 ++ dist/activity/Activity.js | 36 ++++++++++--------- dist/process/ProcessExecution.js | 4 +-- src/activity/Activity.js | 41 ++++++++++++---------- src/process/ProcessExecution.js | 4 +-- test/feature/shake-feature.js | 60 ++++++++++++++++++++++++++++++++ types/index.d.ts | 5 +++ 8 files changed, 117 insertions(+), 39 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 4d2486cc..8a32199c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,6 +38,8 @@ All coordination is async message passing on an in-memory AMQP-like broker (`smq Execution is driven by publishing routing keys like `execute.start`, `execute.completed`, `execute.error`, `run.enter`, `run.end`, `run.discard`, and subscribing via `broker.subscribeTmp()` / `subscribeOnce()`. Messages with `mandatory: true` surface errors if undelivered. The `EventBroker` exposes convenience methods: `on`, `once`, `waitFor`, `emit`, `emitFatal`. If you try to read `ActivityExecution` or `ProcessExecution` as imperative code you will get lost — keep the publish/subscribe model in mind. +**Do not read synchronous queue/exchange state off the broker** (`queue.messageCount`, `consumerCount`, `peek`, etc.). These are `smqp` conveniences a host that swaps in a real AMQP-compliant broker will not provide. Track what you need in execution state instead — e.g. `consumeInbound` keys the consumer assertion off the `initialized` counter, not a pending-message count on `inbound-q`. Publishing, subscribing, asserting/cancelling consumers, and `queueMessage` are all fine; reading queue depth is not. + ### Activity vs Behaviour An element type like `ServiceTask` is not a class. It is a factory function that returns an `Activity` constructed with a `Behaviour` class: @@ -68,7 +70,7 @@ Documented in `docs/Extend.md` and `docs/Extension.md`: ### State & behavioral invariants - **No flow discards.** Outbound sequence flows are never discarded; flow and activity `discarded` counters stay `0`. There is no `skipDiscard` setting. Parallel joins rely on cached gateway peers, not on discarded flows. -- **Activities are armed through the inbound queue, then run consumer-driven.** Both start activities (`isStart`, no inbound trigger) and link catch events are armed by `Activity.init()`: it mints an executionId, emits the `init` event (whose placeholder in the process's `postponed` set blocks premature completion), increments an `initialized` counter, and queues a non-persistent `activity.init` message carrying that id (plus the activity `id`) on the activity's own `inbound-q`. The run is then driven by the inbound consumer: `_consumeInbound` asserts the consumer when the queue has a pending message even without sequence-flow triggers, and `_onInbound`'s `activity.init` case decrements the counter and calls `run()` with the carried id. `ProcessExecution._start` arms start activities this way (`init()` then `_consumeInbound()`, no direct `run()`). A throwing link publishes `activity.link`; the catch's construction-time inbound-trigger handler calls the catch's own `init()` to arm it identically — there is no `activity.relink`. The `initialized` getter reads the counter (exec-state, not persisted); since the `activity.init` trigger is `persistent: false` it is dropped on recover and never re-consumed, so counter and trigger reset together (a stop/resume while armed cannot desync them). +- **Activities are armed through the inbound queue, then run consumer-driven.** Both start activities (`isStart`, no inbound trigger) and link catch events are armed by `Activity.init()`: it mints an executionId, emits the `init` event (whose placeholder in the process's `postponed` set blocks premature completion), increments an `initialized` counter, and queues a non-persistent `activity.init` message carrying that id (plus the activity `id`) on the activity's own `inbound-q`. The run is then driven by the inbound consumer: the idempotent `consumeInbound()` asserts the consumer when there are inbound triggers, or — even without sequence-flow triggers — when the activity is `initialized` (it reads the `initialized` counter rather than probing `inbound-q` for a pending-message count, so no synchronous smqp-only property is touched), and `_onInbound`'s `activity.init` case decrements the counter and calls `run()` with the carried id. `ProcessExecution._start` arms start activities this way (`init()` then `consumeInbound()`, no direct `run()`). A throwing link publishes `activity.link`; the catch's construction-time inbound-trigger handler calls the catch's own `init()` to arm it identically — there is no `activity.relink`. The `initialized` getter reads the counter (exec-state, not persisted); since the `activity.init` trigger is `persistent: false` it is dropped on recover and never re-consumed, so counter and trigger reset together (a stop/resume while armed cannot desync them). - **`run()` executionId resolution.** `run(runContent)` uses `runContent.initExecutionId` when `runContent.id` equals the activity's own id, otherwise mints a fresh `getUniqueId(id)`. The init/link handoff (`_onInbound`) always passes a matching `id`, so the reserved id is honoured; every other caller (e.g. delegated event runs passing `run(content.message)`) carries no matching id and gets a fresh one. `run()` does **not** peek the inbound queue, and there is no `initExecutionId` exec-state key. `initExecutionId` is **destructured out** of `runContent` so it never reaches the `run.enter`/`run.start` content (it would otherwise leak through `_createMessage`, which only overwrites `id`/`type`/flags, into every downstream message and saved state). - **Multiple start events are mutually exclusive entry points.** The first start event to fire discards the others still armed, so two start branches can never both run. - **`stateVersion`.** `Definition.getState()` stamps `stateVersion` (the package major, hardcoded in `src/constants.js`); recovering an older major triggers migrations (e.g. start event reconciliation on resume). Unstamped legacy states are treated as version `0`. Bump the constant on each major release. diff --git a/CHANGELOG.md b/CHANGELOG.md index a27f6e68..54fa1af6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## v18.0.2 - 2026-06-24 - Refactor catching `LinkEventDefinition` trigger and start event init handling. Both publishes `activity.init` to reserve process attention and queues messages on inbound queue that are eventually handled +- a throwing link `IntermediateThrowEvent` is no longer marked as an end (`isEnd`); it has no outbound sequence flows but continues at its catch, so a shake no longer records it as a dead-end sequence +- a converging parallel gateway now publishes `activity.shake.converge` during a shake (previously `activity.shake.join`), matching the runtime `activity.converge` event ## v18.0.1 - 2026-06-13 diff --git a/dist/activity/Activity.js b/dist/activity/Activity.js index e97619f7..027ab55e 100644 --- a/dist/activity/Activity.js +++ b/dist/activity/Activity.js @@ -97,8 +97,9 @@ function Activity(Behaviour, activityDef, context) { outboundSequenceFlows, outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows) }; + const isThrowingLink = activityDef.isThrowing && activityDef.linkNames?.length; this[K_FLAGS] = { - isEnd: !outboundSequenceFlows.length, + isEnd: !outboundSequenceFlows.length && !isThrowingLink, isStart: !hasInboundTrigger && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, isMultiInstance: !!behaviour.loopCharacteristics, @@ -281,7 +282,22 @@ Activity.prototype.activate = function activate() { if (this[_constants.K_ACTIVATED]) return; this[_constants.K_ACTIVATED] = true; this.addInboundListeners(); - return this._consumeInbound(); + return this.consumeInbound(); +}; + +/** + * Assert the inbound queue consumer when the activity has a trigger or is initialized. + * Idempotent: asserting the consumer again while one is active is a no-op. + * @returns {void} + */ +Activity.prototype.consumeInbound = function consumeInbound() { + if (!this[_constants.K_ACTIVATED]) return; + if (this.status) return; + if (!this._getInboundTriggers().length && !this.initialized) return; + const onInbound = this[_constants.K_MESSAGE_HANDLERS].onInbound; + return this.broker.getQueue('inbound-q').assertConsumer(onInbound, { + consumerTag: '_run-on-inbound' + }); }; /** @internal */ @@ -625,7 +641,7 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { id: this.id, type: this.type }); - return this.broker.publish('event', 'activity.shake.join', message.content, { + return this.broker.publish('event', 'activity.shake.converge', message.content, { persistent: false, type: 'shake' }); @@ -686,18 +702,6 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { for (const t of targets.values()) t.shake(message); }; -/** @internal */ -Activity.prototype._consumeInbound = function consumeInbound() { - if (!this[_constants.K_ACTIVATED]) return; - if (this.status) return; - const inboundQ = this.broker.getQueue('inbound-q'); - if (!inboundQ.messageCount && !this._getInboundTriggers().length) return; - const onInbound = this[_constants.K_MESSAGE_HANDLERS].onInbound; - return inboundQ.assertConsumer(onInbound, { - consumerTag: '_run-on-inbound' - }); -}; - /** @internal */ Activity.prototype._onInbound = function onInbound(routingKey, message) { message.ack(); @@ -944,7 +948,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, case 'run.next': message.ack(); this._pauseRunQ(); - return this._consumeInbound(); + return this.consumeInbound(); } if (!step) message.ack(); }; diff --git a/dist/process/ProcessExecution.js b/dist/process/ProcessExecution.js index dd753bb6..1822e3bf 100644 --- a/dist/process/ProcessExecution.js +++ b/dist/process/ProcessExecution.js @@ -391,7 +391,7 @@ ProcessExecution.prototype._start = function start() { this._shakeOnStart(); for (const a of startActivities) a.init(); this[_constants.K_STATUS] = 'executing'; - for (const a of startActivities) a._consumeInbound(); + for (const a of startActivities) a.consumeInbound(); if (!startActivities.size) { for (const a of this[K_ELEMENTS].triggeredByEvent) { if (a.isCatching && !a.isRunning) a.run(); @@ -556,7 +556,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { }) => { if (content.parent.id !== this.id) return; switch (routingKey) { - case 'activity.shake.join': + case 'activity.shake.converge': { const join = convergingGateways.get(content.join); if (!join) { diff --git a/src/activity/Activity.js b/src/activity/Activity.js index aa137407..2749878d 100644 --- a/src/activity/Activity.js +++ b/src/activity/Activity.js @@ -91,8 +91,10 @@ export function Activity(Behaviour, activityDef, context) { outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows), }; + const isThrowingLink = activityDef.isThrowing && activityDef.linkNames?.length; + this[K_FLAGS] = { - isEnd: !outboundSequenceFlows.length, + isEnd: !outboundSequenceFlows.length && !isThrowingLink, isStart: !hasInboundTrigger && !behaviour.triggeredByEvent && !activityDef.isCatching, isSubProcess: activityDef.isSubProcess, isMultiInstance: !!behaviour.loopCharacteristics, @@ -275,7 +277,24 @@ Activity.prototype.activate = function activate() { if (this[K_ACTIVATED]) return; this[K_ACTIVATED] = true; this.addInboundListeners(); - return this._consumeInbound(); + return this.consumeInbound(); +}; + +/** + * Assert the inbound queue consumer when the activity has a trigger or is initialized. + * Idempotent: asserting the consumer again while one is active is a no-op. + * @returns {void} + */ +Activity.prototype.consumeInbound = function consumeInbound() { + if (!this[K_ACTIVATED]) return; + + if (this.status) return; + + if (!this._getInboundTriggers().length && !this.initialized) return; + + const onInbound = this[K_MESSAGE_HANDLERS].onInbound; + + return this.broker.getQueue('inbound-q').assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); }; /** @internal */ @@ -596,7 +615,7 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) { if (this[K_FLAGS].isParallelGateway) { const message = cloneMessage(sourceMessage, { join: this.id }); message.content.sequence.push({ id: this.id, type: this.type }); - return this.broker.publish('event', 'activity.shake.join', message.content, { + return this.broker.publish('event', 'activity.shake.converge', message.content, { persistent: false, type: 'shake', }); @@ -643,20 +662,6 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) { for (const t of targets.values()) t.shake(message); }; -/** @internal */ -Activity.prototype._consumeInbound = function consumeInbound() { - if (!this[K_ACTIVATED]) return; - - if (this.status) return; - - const inboundQ = this.broker.getQueue('inbound-q'); - if (!inboundQ.messageCount && !this._getInboundTriggers().length) return; - - const onInbound = this[K_MESSAGE_HANDLERS].onInbound; - - return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' }); -}; - /** @internal */ Activity.prototype._onInbound = function onInbound(routingKey, message) { message.ack(); @@ -886,7 +891,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, case 'run.next': message.ack(); this._pauseRunQ(); - return this._consumeInbound(); + return this.consumeInbound(); } if (!step) message.ack(); diff --git a/src/process/ProcessExecution.js b/src/process/ProcessExecution.js index 3f6e51c9..a5e6838f 100644 --- a/src/process/ProcessExecution.js +++ b/src/process/ProcessExecution.js @@ -400,7 +400,7 @@ ProcessExecution.prototype._start = function start() { for (const a of startActivities) a.init(); this[K_STATUS] = 'executing'; - for (const a of startActivities) a._consumeInbound(); + for (const a of startActivities) a.consumeInbound(); if (!startActivities.size) { for (const a of this[K_ELEMENTS].triggeredByEvent) { @@ -571,7 +571,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) { if (content.parent.id !== this.id) return; switch (routingKey) { - case 'activity.shake.join': { + case 'activity.shake.converge': { const join = convergingGateways.get(content.join); if (!join) { convergingGateways.set(content.join, content); diff --git a/test/feature/shake-feature.js b/test/feature/shake-feature.js index 78bb3f8a..1041f927 100644 --- a/test/feature/shake-feature.js +++ b/test/feature/shake-feature.js @@ -695,6 +695,22 @@ Feature('Shaking', () => { const sequenceIds = result.start.map((s) => s.sequence.map((e) => e.id)); expect(sequenceIds.some((ids) => ids.includes('throw') && ids.includes('catch') && ids.includes('end'))).to.be.true; }); + + And('the throwing link event is not marked as an end', () => { + expect(definition.getActivityById('throw')).to.have.property('isEnd', false); + }); + + And('the throw does not terminate a shake sequence as a dead end', () => { + for (const msg of shakeEndMessages) { + const ids = msg.content.sequence.map((s) => s.id); + expect(ids[ids.length - 1], ids.join()).to.not.equal('throw'); + } + const resultIds = result.start.map((s) => s.sequence.map((e) => e.id)); + expect( + resultIds.every((ids) => ids[ids.length - 1] !== 'throw'), + resultIds.join(' | ') + ).to.be.true; + }); }); Scenario('a converging parallel gateway discovers its peers once and reuses them', () => { @@ -758,4 +774,48 @@ Feature('Shaking', () => { expect(definition.getActivityById('join').counters).to.have.property('taken', 2); }); }); + + Scenario('a shaken converging parallel gateway emits activity.shake.converge', () => { + let definition; + Given('a process with a parallel fork and join', async () => { + const source = ` + + + + + + + + + + + + + + + + `; + definition = new Definition(await testHelpers.context(source)); + }); + + const convergeMessages = []; + When('definition is shaken from start', () => { + definition.broker.subscribeTmp( + 'event', + 'activity.shake.converge', + (_, msg) => { + convergeMessages.push(msg); + }, + { noAck: true } + ); + + definition.shake('start'); + }); + + Then('each parallel gateway emitted a shake converge event identified by its own id', () => { + const joins = convergeMessages.map((m) => m.content.join); + expect(joins, joins.join()).to.include('fork'); + expect(joins, joins.join()).to.include('join'); + }); + }); }); diff --git a/types/index.d.ts b/types/index.d.ts index 65e4ab7d..84df943d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -580,6 +580,11 @@ declare module 'bpmn-elements' { * Subscribe to inbound flows and start consuming the inbound queue. * */ activate(): void; + /** + * Assert the inbound queue consumer when the activity has a trigger or is initialized. + * Idempotent: asserting the consumer again while one is active is a no-op. + * */ + consumeInbound(): void; /** * Cancel inbound subscriptions and any pending run/format consumers. */