bpmn-elements 17.2.2 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +3 -1
  2. package/dist/Api.js +83 -0
  3. package/dist/Context.js +228 -22
  4. package/dist/Environment.js +111 -31
  5. package/dist/EventBroker.js +57 -1
  6. package/dist/Expressions.js +3 -4
  7. package/dist/MessageFormatter.js +29 -16
  8. package/dist/Timers.js +13 -9
  9. package/dist/Tracker.js +1 -0
  10. package/dist/activity/Activity.js +458 -254
  11. package/dist/activity/ActivityExecution.js +113 -40
  12. package/dist/activity/Dummy.js +6 -1
  13. package/dist/activity/Escalation.js +36 -24
  14. package/dist/activity/ExecutionScope.js +1 -1
  15. package/dist/activity/Message.js +36 -24
  16. package/dist/activity/Signal.js +36 -24
  17. package/dist/activity/outbound-evaluator.js +1 -1
  18. package/dist/condition.js +12 -6
  19. package/dist/constants.js +21 -0
  20. package/dist/definition/Definition.js +182 -64
  21. package/dist/definition/DefinitionExecution.js +195 -82
  22. package/dist/error/BpmnError.js +12 -1
  23. package/dist/error/Errors.js +50 -9
  24. package/dist/eventDefinitions/CancelEventDefinition.js +29 -11
  25. package/dist/eventDefinitions/CompensateEventDefinition.js +51 -31
  26. package/dist/eventDefinitions/ConditionalEventDefinition.js +21 -9
  27. package/dist/eventDefinitions/ErrorEventDefinition.js +46 -30
  28. package/dist/eventDefinitions/EscalationEventDefinition.js +44 -27
  29. package/dist/eventDefinitions/EventDefinitionExecution.js +30 -23
  30. package/dist/eventDefinitions/LinkEventDefinition.js +45 -120
  31. package/dist/eventDefinitions/MessageEventDefinition.js +44 -29
  32. package/dist/eventDefinitions/SignalEventDefinition.js +46 -31
  33. package/dist/eventDefinitions/TerminateEventDefinition.js +10 -1
  34. package/dist/eventDefinitions/TimerEventDefinition.js +57 -37
  35. package/dist/eventDefinitions/index.js +20 -21
  36. package/dist/events/BoundaryEvent.js +52 -40
  37. package/dist/events/EndEvent.js +22 -8
  38. package/dist/events/IntermediateCatchEvent.js +26 -8
  39. package/dist/events/IntermediateThrowEvent.js +24 -9
  40. package/dist/events/StartEvent.js +30 -14
  41. package/dist/events/index.js +10 -11
  42. package/dist/flows/Association.js +50 -7
  43. package/dist/flows/MessageFlow.js +49 -10
  44. package/dist/flows/SequenceFlow.js +93 -22
  45. package/dist/flows/index.js +6 -7
  46. package/dist/gateways/EventBasedGateway.js +29 -15
  47. package/dist/gateways/ExclusiveGateway.js +20 -5
  48. package/dist/gateways/InclusiveGateway.js +21 -5
  49. package/dist/gateways/ParallelGateway.js +253 -15
  50. package/dist/gateways/index.js +8 -9
  51. package/dist/getPropertyValue.js +2 -2
  52. package/dist/index.js +42 -43
  53. package/dist/io/BpmnIO.js +15 -1
  54. package/dist/io/EnvironmentDataObject.js +29 -1
  55. package/dist/io/EnvironmentDataStore.js +24 -1
  56. package/dist/io/EnvironmentDataStoreReference.js +24 -1
  57. package/dist/io/InputOutputSpecification.js +21 -11
  58. package/dist/io/Properties.js +28 -17
  59. package/dist/messageHelper.js +41 -4
  60. package/dist/process/Lane.js +15 -4
  61. package/dist/process/Process.js +174 -76
  62. package/dist/process/ProcessExecution.js +362 -177
  63. package/dist/shared.js +2 -0
  64. package/dist/tasks/CallActivity.js +19 -4
  65. package/dist/tasks/LoopCharacteristics.js +94 -9
  66. package/dist/tasks/ReceiveTask.js +36 -21
  67. package/dist/tasks/ScriptTask.js +22 -6
  68. package/dist/tasks/ServiceImplementation.js +7 -4
  69. package/dist/tasks/ServiceTask.js +19 -4
  70. package/dist/tasks/SignalTask.js +19 -4
  71. package/dist/tasks/StandardLoopCharacteristics.js +8 -4
  72. package/dist/tasks/SubProcess.js +44 -29
  73. package/dist/tasks/Task.js +19 -4
  74. package/dist/tasks/Transaction.js +8 -4
  75. package/dist/tasks/index.js +16 -18
  76. package/package.json +31 -13
  77. package/src/Api.js +70 -0
  78. package/src/Context.js +200 -19
  79. package/src/Environment.js +99 -30
  80. package/src/EventBroker.js +46 -1
  81. package/src/Expressions.js +2 -3
  82. package/src/MessageFormatter.js +24 -16
  83. package/src/Timers.js +12 -9
  84. package/src/Tracker.js +1 -0
  85. package/src/activity/Activity.js +388 -231
  86. package/src/activity/ActivityExecution.js +93 -42
  87. package/src/activity/Dummy.js +6 -1
  88. package/src/activity/Escalation.js +25 -18
  89. package/src/activity/ExecutionScope.js +1 -1
  90. package/src/activity/Message.js +25 -18
  91. package/src/activity/Signal.js +25 -18
  92. package/src/activity/outbound-evaluator.js +1 -1
  93. package/src/condition.js +11 -5
  94. package/src/constants.js +15 -0
  95. package/src/definition/Definition.js +157 -62
  96. package/src/definition/DefinitionExecution.js +161 -83
  97. package/src/error/BpmnError.js +11 -1
  98. package/src/error/Errors.js +44 -5
  99. package/src/eventDefinitions/CancelEventDefinition.js +27 -13
  100. package/src/eventDefinitions/CompensateEventDefinition.js +48 -32
  101. package/src/eventDefinitions/ConditionalEventDefinition.js +20 -10
  102. package/src/eventDefinitions/ErrorEventDefinition.js +44 -33
  103. package/src/eventDefinitions/EscalationEventDefinition.js +39 -26
  104. package/src/eventDefinitions/EventDefinitionExecution.js +30 -24
  105. package/src/eventDefinitions/LinkEventDefinition.js +34 -120
  106. package/src/eventDefinitions/MessageEventDefinition.js +42 -31
  107. package/src/eventDefinitions/SignalEventDefinition.js +43 -32
  108. package/src/eventDefinitions/TerminateEventDefinition.js +9 -1
  109. package/src/eventDefinitions/TimerEventDefinition.js +53 -35
  110. package/src/eventDefinitions/index.js +10 -23
  111. package/src/events/BoundaryEvent.js +50 -39
  112. package/src/events/EndEvent.js +19 -7
  113. package/src/events/IntermediateCatchEvent.js +24 -8
  114. package/src/events/IntermediateThrowEvent.js +24 -8
  115. package/src/events/StartEvent.js +25 -14
  116. package/src/events/index.js +5 -18
  117. package/src/flows/Association.js +43 -9
  118. package/src/flows/MessageFlow.js +41 -10
  119. package/src/flows/SequenceFlow.js +82 -19
  120. package/src/flows/index.js +3 -4
  121. package/src/gateways/EventBasedGateway.js +27 -15
  122. package/src/gateways/ExclusiveGateway.js +16 -3
  123. package/src/gateways/InclusiveGateway.js +16 -3
  124. package/src/gateways/ParallelGateway.js +301 -10
  125. package/src/gateways/index.js +4 -4
  126. package/src/getPropertyValue.js +2 -2
  127. package/src/index.js +19 -19
  128. package/src/io/BpmnIO.js +13 -1
  129. package/src/io/EnvironmentDataObject.js +26 -1
  130. package/src/io/EnvironmentDataStore.js +22 -1
  131. package/src/io/EnvironmentDataStoreReference.js +22 -1
  132. package/src/io/InputOutputSpecification.js +17 -8
  133. package/src/io/Properties.js +23 -13
  134. package/src/messageHelper.js +36 -4
  135. package/src/process/Lane.js +14 -4
  136. package/src/process/Process.js +154 -72
  137. package/src/process/ProcessExecution.js +326 -175
  138. package/src/shared.js +1 -0
  139. package/src/tasks/CallActivity.js +16 -2
  140. package/src/tasks/LoopCharacteristics.js +77 -11
  141. package/src/tasks/ReceiveTask.js +33 -22
  142. package/src/tasks/ScriptTask.js +17 -3
  143. package/src/tasks/ServiceImplementation.js +6 -3
  144. package/src/tasks/ServiceTask.js +16 -2
  145. package/src/tasks/SignalTask.js +16 -2
  146. package/src/tasks/StandardLoopCharacteristics.js +7 -3
  147. package/src/tasks/SubProcess.js +37 -23
  148. package/src/tasks/Task.js +16 -2
  149. package/src/tasks/Transaction.js +7 -3
  150. package/src/tasks/index.js +8 -9
  151. package/types/bundle-errors.d.ts +1 -0
  152. package/types/bundle.d.ts +97 -0
  153. package/types/index.d.ts +2614 -84
  154. package/types/interfaces.d.ts +636 -0
  155. package/types/types.d.ts +0 -765
@@ -1,4 +1,4 @@
1
- import ActivityExecution from './ActivityExecution.js';
1
+ import { ActivityExecution } from './ActivityExecution.js';
2
2
  import { getUniqueId } from '../shared.js';
3
3
  import { ActivityApi } from '../Api.js';
4
4
  import { ActivityBroker } from '../EventBroker.js';
@@ -6,39 +6,55 @@ import { Formatter } from '../MessageFormatter.js';
6
6
  import { cloneContent, cloneParent, cloneMessage } from '../messageHelper.js';
7
7
  import { makeErrorFromMessage, ActivityError } from '../error/Errors.js';
8
8
  import { OutboundEvaluator, formatFlowAction } from './outbound-evaluator.js';
9
-
10
- const kActivityDef = Symbol.for('activityDefinition');
11
- const kConsuming = Symbol.for('consuming');
12
- const kConsumingRunQ = Symbol.for('run queue consumer');
13
- const kCounters = Symbol.for('counters');
14
- const kEventDefinitions = Symbol.for('eventDefinitions');
15
- const kExec = Symbol.for('exec');
16
- const kExecuteMessage = Symbol.for('executeMessage');
17
- const kExtensions = Symbol.for('extensions');
18
- const kFlags = Symbol.for('flags');
19
- const kFlows = Symbol.for('flows');
20
- const kFormatter = Symbol.for('formatter');
21
- const kMessageHandlers = Symbol.for('messageHandlers');
22
- const kStateMessage = Symbol.for('stateMessage');
23
- const kActivated = Symbol.for('activated');
24
-
25
- export default Activity;
26
-
27
- function Activity(Behaviour, activityDef, context) {
9
+ import {
10
+ K_ACTIVATED,
11
+ K_CONSUMING,
12
+ K_COUNTERS,
13
+ K_EXECUTE_MESSAGE,
14
+ K_EXTENSIONS,
15
+ K_MESSAGE_HANDLERS,
16
+ K_STATE_MESSAGE,
17
+ } from '../constants.js';
18
+
19
+ const K_ACTIVITY_DEF = Symbol.for('activityDefinition');
20
+ const K_CONSUMING_RUN_Q = Symbol.for('run queue consumer');
21
+ const K_EVENT_DEFINITIONS = Symbol.for('eventDefinitions');
22
+ const K_EXEC = Symbol.for('exec');
23
+ const K_FLAGS = Symbol.for('flags');
24
+ const K_FLOWS = Symbol.for('flows');
25
+ const K_FORMATTER = Symbol.for('formatter');
26
+
27
+ /**
28
+ * Activity wraps any element (task, event, gateway) and orchestrates its lifecycle through the broker.
29
+ * @param {import('#types').IActivityBehaviour} Behaviour Element-specific behaviour constructor invoked per execution
30
+ * @param {import('moddle-context-serializer').Activity} activityDef Parsed BPMN element definition
31
+ * @param {import('#types').ContextInstance} context Per-execution registry and factory
32
+ */
33
+ export function Activity(Behaviour, activityDef, context) {
28
34
  const { id, type = 'activity', name, behaviour = {} } = activityDef;
29
35
  const { attachedTo: attachedToRef, eventDefinitions } = behaviour;
30
36
 
31
- this[kActivityDef] = activityDef;
37
+ this[K_ACTIVITY_DEF] = activityDef;
32
38
  this.id = id;
33
39
  this.type = type;
34
40
  this.name = name;
35
- this.behaviour = { ...behaviour, eventDefinitions };
41
+ /** @type {import('moddle-context-serializer').ActivityBehaviour} */
42
+ this.behaviour = {
43
+ ...behaviour,
44
+ eventDefinitions,
45
+ ...(activityDef.linkNames && { linkNames: activityDef.linkNames, linkBehaviour: activityDef.linkBehaviour }),
46
+ };
36
47
  this.Behaviour = Behaviour;
48
+ /** @type {import('moddle-context-serializer').Parent} */
37
49
  this.parent = activityDef.parent ? cloneParent(activityDef.parent) : {};
50
+ /** @type {import('#types').ILogger} */
38
51
  this.logger = context.environment.Logger(type.toLowerCase());
39
52
  this.environment = context.environment;
40
53
  this.context = context;
41
- this[kCounters] = {
54
+ /** @type {import('#types').ActivityStatus | undefined} */
55
+ this.status = undefined;
56
+
57
+ this[K_COUNTERS] = {
42
58
  taken: 0,
43
59
  discarded: 0,
44
60
  };
@@ -60,159 +76,175 @@ function Activity(Behaviour, activityDef, context) {
60
76
 
61
77
  const inboundSequenceFlows = context.getInboundSequenceFlows(id);
62
78
  const inboundAssociations = context.getInboundAssociations(id);
63
- let inboundTriggers;
64
- if (attachedToActivity) {
65
- inboundTriggers = [attachedToActivity];
66
- } else if (isForCompensation) {
67
- inboundTriggers = inboundAssociations.slice();
68
- } else {
69
- inboundTriggers = inboundSequenceFlows.slice();
70
- }
79
+ const hasInboundTrigger = attachedToActivity ? true : isForCompensation ? !!inboundAssociations.length : !!inboundSequenceFlows.length;
80
+
71
81
  const outboundSequenceFlows = context.getOutboundSequenceFlows(id);
72
82
 
73
- const isParallelJoin = activityDef.isParallelGateway && inboundSequenceFlows.length > 1;
83
+ const inboundSourceIds = new Set(inboundSequenceFlows.map(({ sourceId }) => sourceId));
84
+ const isParallelJoin = activityDef.isParallelGateway && inboundSourceIds.size > 1;
74
85
 
75
- const flows = (this[kFlows] = {
86
+ this[K_FLOWS] = {
76
87
  inboundSequenceFlows,
77
88
  inboundAssociations,
78
- inboundTriggers,
89
+ inboundTriggers: undefined,
79
90
  outboundSequenceFlows,
80
91
  outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows),
81
- ...(isParallelJoin && {
82
- inboundJoinFlows: new Set(),
83
- inboundSourceIds: new Set(inboundSequenceFlows.map(({ sourceId }) => sourceId)),
84
- }),
85
- });
92
+ };
86
93
 
87
- this[kFlags] = {
88
- isEnd: flows.outboundSequenceFlows.length === 0,
89
- isStart: flows.inboundSequenceFlows.length === 0 && !attachedTo && !behaviour.triggeredByEvent && !isForCompensation,
94
+ this[K_FLAGS] = {
95
+ isEnd: !outboundSequenceFlows.length,
96
+ isStart: !hasInboundTrigger && !behaviour.triggeredByEvent && !activityDef.isCatching,
90
97
  isSubProcess: activityDef.isSubProcess,
91
98
  isMultiInstance: !!behaviour.loopCharacteristics,
92
99
  isForCompensation,
93
100
  attachedTo,
94
101
  isTransaction: activityDef.isTransaction,
95
102
  isParallelJoin,
103
+ isParallelGateway: activityDef.isParallelGateway,
104
+ isStartEvent: !!activityDef.isStartEvent,
96
105
  isThrowing: activityDef.isThrowing,
106
+ linkNames: activityDef.linkNames,
107
+ linkBehaviour: activityDef.linkBehaviour,
108
+ isCatching: activityDef.isCatching,
97
109
  lane: activityDef.lane?.id,
98
110
  };
99
- this[kExec] = new Map();
111
+ this[K_EXEC] = new Map();
100
112
 
101
- this[kMessageHandlers] = {
102
- onInbound: isParallelJoin ? this._onJoinInbound.bind(this) : this._onInbound.bind(this),
113
+ this[K_MESSAGE_HANDLERS] = {
114
+ onInbound: this._onInbound.bind(this),
103
115
  onRunMessage: this._onRunMessage.bind(this),
104
116
  onApiMessage: this._onApiMessage.bind(this),
105
117
  onExecutionMessage: this._onExecutionMessage.bind(this),
106
118
  };
107
119
 
108
- this[kEventDefinitions] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx));
109
- this[kExtensions] = context.loadExtensions(this);
110
- this[kConsuming] = false;
111
- this[kConsumingRunQ] = undefined;
120
+ /** @type {import('#types').EventDefinition[] | undefined} */
121
+ this[K_EVENT_DEFINITIONS] = eventDefinitions?.map((ed, idx) => new ed.Behaviour(this, ed, context, idx));
122
+ this[K_EXTENSIONS] = context.loadExtensions(this);
123
+ this[K_CONSUMING] = false;
124
+ this[K_CONSUMING_RUN_Q] = undefined;
112
125
  }
113
126
 
114
127
  Object.defineProperties(Activity.prototype, {
115
128
  counters: {
116
129
  get() {
117
- return { ...this[kCounters] };
130
+ return { ...this[K_COUNTERS] };
118
131
  },
119
132
  },
120
133
  execution: {
121
134
  get() {
122
- return this[kExec].get('execution');
135
+ return this[K_EXEC].get('execution');
123
136
  },
124
137
  },
125
138
  executionId: {
126
139
  get() {
127
- return this[kExec].get('executionId');
140
+ return this[K_EXEC].get('executionId');
128
141
  },
129
142
  },
130
143
  extensions: {
131
144
  get() {
132
- return this[kExtensions];
145
+ return this[K_EXTENSIONS];
133
146
  },
134
147
  },
135
148
  bpmnIo: {
136
149
  get() {
137
- const extensions = this[kExtensions];
150
+ const extensions = this[K_EXTENSIONS];
138
151
  return extensions?.extensions.find((e) => e.type === 'bpmnio');
139
152
  },
140
153
  },
141
154
  formatter: {
142
155
  get() {
143
- let formatter = this[kFormatter];
156
+ let formatter = this[K_FORMATTER];
144
157
  if (formatter) return formatter;
145
-
146
- formatter = this[kFormatter] = new Formatter(this);
158
+ formatter = this[K_FORMATTER] = new Formatter(this);
147
159
  return formatter;
148
160
  },
149
161
  },
150
162
  isRunning: {
151
163
  get() {
152
- if (!this[kConsuming]) return false;
164
+ if (!this[K_CONSUMING]) return false;
153
165
  return !!this.status;
154
166
  },
155
167
  },
156
168
  outbound: {
157
169
  get() {
158
- return this[kFlows].outboundSequenceFlows;
170
+ return this[K_FLOWS].outboundSequenceFlows;
159
171
  },
160
172
  },
161
173
  inbound: {
162
174
  get() {
163
- return this[kFlows].inboundSequenceFlows;
175
+ return this[K_FLOWS].inboundSequenceFlows;
164
176
  },
165
177
  },
166
178
  isEnd: {
167
179
  get() {
168
- return this[kFlags].isEnd;
180
+ return this[K_FLAGS].isEnd;
169
181
  },
170
182
  },
171
183
  isStart: {
172
184
  get() {
173
- return this[kFlags].isStart;
185
+ return this[K_FLAGS].isStart;
174
186
  },
175
187
  },
176
188
  isSubProcess: {
177
189
  get() {
178
- return this[kFlags].isSubProcess;
190
+ return this[K_FLAGS].isSubProcess;
179
191
  },
180
192
  },
181
193
  isTransaction: {
182
194
  get() {
183
- return this[kFlags].isTransaction;
195
+ return this[K_FLAGS].isTransaction;
184
196
  },
185
197
  },
186
198
  isMultiInstance: {
187
199
  get() {
188
- return this[kFlags].isMultiInstance;
200
+ return this[K_FLAGS].isMultiInstance;
189
201
  },
190
202
  },
191
203
  isThrowing: {
192
204
  get() {
193
- return this[kFlags].isThrowing;
205
+ return this[K_FLAGS].isThrowing;
206
+ },
207
+ },
208
+ isCatching: {
209
+ get() {
210
+ return this[K_FLAGS].isCatching;
194
211
  },
195
212
  },
196
213
  isForCompensation: {
197
214
  get() {
198
- return this[kFlags].isForCompensation;
215
+ return this[K_FLAGS].isForCompensation;
216
+ },
217
+ },
218
+ isParallelJoin: {
219
+ get() {
220
+ return this[K_FLAGS].isParallelJoin;
221
+ },
222
+ },
223
+ isParallelGateway: {
224
+ get() {
225
+ return this[K_FLAGS].isParallelGateway;
226
+ },
227
+ },
228
+ isStartEvent: {
229
+ get() {
230
+ return this[K_FLAGS].isStartEvent;
199
231
  },
200
232
  },
201
233
  triggeredByEvent: {
202
234
  get() {
203
- return this[kActivityDef].triggeredByEvent;
235
+ return this[K_ACTIVITY_DEF].triggeredByEvent;
204
236
  },
205
237
  },
206
238
  attachedTo: {
207
239
  get() {
208
- const attachedToId = this[kFlags].attachedTo;
240
+ const attachedToId = this[K_FLAGS].attachedTo;
209
241
  if (!attachedToId) return null;
210
242
  return this.getActivityById(attachedToId);
211
243
  },
212
244
  },
213
245
  lane: {
214
246
  get() {
215
- const laneId = this[kFlags].lane;
247
+ const laneId = this[K_FLAGS].lane;
216
248
  if (!laneId) return undefined;
217
249
  const parent = this.parentElement;
218
250
  return parent.getLaneById && parent.getLaneById(laneId);
@@ -220,7 +252,7 @@ Object.defineProperties(Activity.prototype, {
220
252
  },
221
253
  eventDefinitions: {
222
254
  get() {
223
- return this[kEventDefinitions];
255
+ return this[K_EVENT_DEFINITIONS];
224
256
  },
225
257
  },
226
258
  parentElement: {
@@ -228,37 +260,85 @@ Object.defineProperties(Activity.prototype, {
228
260
  return this.context.getActivityParentById(this.id);
229
261
  },
230
262
  },
263
+ initialized: {
264
+ get() {
265
+ return !!this[K_EXEC]?.get('initExecutionId');
266
+ },
267
+ },
231
268
  });
232
269
 
270
+ /**
271
+ * Subscribe to inbound flows and start consuming the inbound queue.
272
+ * @returns {void}
273
+ */
233
274
  Activity.prototype.activate = function activate() {
234
- if (this[kActivated]) return;
235
- this[kActivated] = true;
236
- this.addInboundListeners();
237
- return this._consumeInbound();
275
+ if (this[K_ACTIVATED]) return;
276
+ this[K_ACTIVATED] = true;
277
+ return this.addInboundListeners() && this._consumeInbound();
278
+ };
279
+
280
+ /** @internal */
281
+ Activity.prototype._getInboundTriggers = function _getInboundTriggers() {
282
+ const flows = this[K_FLOWS];
283
+ if (flows.inboundTriggers) return flows.inboundTriggers;
284
+
285
+ const flags = this[K_FLAGS];
286
+ let triggers;
287
+ if (flags.attachedTo) {
288
+ triggers = [this.context.getActivityById(flags.attachedTo)];
289
+ } else if (flags.isForCompensation) {
290
+ triggers = flows.inboundAssociations.slice();
291
+ } else {
292
+ triggers = flows.inboundSequenceFlows.slice();
293
+ }
294
+
295
+ const { isCatching, linkNames, linkBehaviour } = flags;
296
+ if (isCatching && linkNames?.length) {
297
+ const known = new Set(triggers.map((t) => t.id));
298
+ for (const source of this.context.getActivitiesByEventDefinitionBehaviour(linkBehaviour, linkNames)) {
299
+ if (source.id === this.id || !source.isThrowing || known.has(source.id)) continue;
300
+ triggers.push(source);
301
+ known.add(source.id);
302
+ }
303
+ }
304
+
305
+ return (flows.inboundTriggers = triggers);
238
306
  };
239
307
 
308
+ /**
309
+ * Cancel inbound subscriptions and any pending run/format consumers.
310
+ */
240
311
  Activity.prototype.deactivate = function deactivate() {
241
- this[kActivated] = false;
312
+ this[K_ACTIVATED] = false;
242
313
  const broker = this.broker;
243
314
  this.removeInboundListeners();
244
315
  broker.cancel('_run-on-inbound');
245
316
  broker.cancel('_format-consumer');
246
317
  };
247
318
 
319
+ /**
320
+ * Initialise activity executionId and emit init event without starting the run.
321
+ * @param {Record<string, any>} [initContent] Optional content merged into the init message
322
+ */
248
323
  Activity.prototype.init = function init(initContent) {
249
324
  const id = this.id;
250
- const exec = this[kExec];
325
+ const exec = this[K_EXEC];
251
326
  const executionId = exec.has('initExecutionId') ? exec.get('initExecutionId') : getUniqueId(id);
252
327
  exec.set('initExecutionId', executionId);
253
328
  this.logger.debug(`<${id}> initialized with executionId <${executionId}>`);
254
329
  this._publishEvent('init', this._createMessage({ ...initContent, executionId }));
255
330
  };
256
331
 
332
+ /**
333
+ * Start running the activity by publishing run.enter and run.start.
334
+ * @param {Record<string, any>} [runContent] Optional content merged into the run message
335
+ * @throws {Error} if the activity is already running
336
+ */
257
337
  Activity.prototype.run = function run(runContent) {
258
338
  const id = this.id;
259
339
  if (this.isRunning) throw new Error(`activity <${id}> is already running`);
260
340
 
261
- const exec = this[kExec];
341
+ const exec = this[K_EXEC];
262
342
  const executionId = exec.get('initExecutionId') || getUniqueId(id);
263
343
  exec.set('executionId', executionId);
264
344
  exec.delete('initExecutionId');
@@ -271,13 +351,18 @@ Activity.prototype.run = function run(runContent) {
271
351
  broker.publish('run', 'run.enter', content);
272
352
  broker.publish('run', 'run.start', cloneContent(content));
273
353
 
274
- this[kConsuming] = true;
354
+ this[K_CONSUMING] = true;
275
355
  this._consumeRunQ();
276
356
  };
277
357
 
358
+ /**
359
+ * Snapshot activity state for recover.
360
+ * Returns undefined when nothing is running and `disableTrackState` is set.
361
+ * @returns {import('#types').ActivityState}
362
+ */
278
363
  Activity.prototype.getState = function getState() {
279
364
  const status = this.status;
280
- const exec = this[kExec];
365
+ const exec = this[K_EXEC];
281
366
  const execution = exec.get('execution');
282
367
  const executionId = exec.get('executionId');
283
368
  const brokerState = this.broker.getState(true);
@@ -295,16 +380,22 @@ Activity.prototype.getState = function getState() {
295
380
  };
296
381
  };
297
382
 
383
+ /**
384
+ * Restore activity state captured by getState. Cannot be called while running.
385
+ * @param {import('#types').ActivityState} [state]
386
+ * @returns {this} this when state was applied
387
+ * @throws {Error} when activity is currently running
388
+ */
298
389
  Activity.prototype.recover = function recover(state) {
299
390
  if (this.isRunning) throw new Error(`cannot recover running activity <${this.id}>`);
300
- if (!state) return;
391
+ if (!state) return this;
301
392
 
302
393
  this.stopped = state.stopped;
303
394
  this.status = state.status;
304
- const exec = this[kExec];
395
+ const exec = this[K_EXEC];
305
396
  exec.set('executionId', state.executionId);
306
397
 
307
- this[kCounters] = { ...this[kCounters], ...state.counters };
398
+ this[K_COUNTERS] = { ...this[K_COUNTERS], ...state.counters };
308
399
 
309
400
  if (state.execution) {
310
401
  exec.set('execution', new ActivityExecution(this, this.context).recover(state.execution));
@@ -315,8 +406,12 @@ Activity.prototype.recover = function recover(state) {
315
406
  return this;
316
407
  };
317
408
 
409
+ /**
410
+ * Resume after recover. If no run has been started, falls back to activate.
411
+ * @throws {Error} when called on a running activity
412
+ */
318
413
  Activity.prototype.resume = function resume() {
319
- if (this[kConsuming]) {
414
+ if (this[K_CONSUMING]) {
320
415
  throw new Error(`cannot resume running activity <${this.id}>`);
321
416
  }
322
417
  if (!this.status) return this.activate();
@@ -328,52 +423,77 @@ Activity.prototype.resume = function resume() {
328
423
  const content = this._createMessage();
329
424
  this.broker.publish('run', 'run.resume', content, { persistent: false });
330
425
 
331
- this[kConsuming] = true;
426
+ this[K_CONSUMING] = true;
332
427
  this._consumeRunQ();
333
428
  };
334
429
 
430
+ /**
431
+ * Discard the activity. Stops execution if running; the activity leaves without taking any outbound flow.
432
+ * @param {Record<string, any>} [discardContent] Optional content propagated with the discard
433
+ * @returns {void}
434
+ */
335
435
  Activity.prototype.discard = function discard(discardContent) {
336
436
  if (!this.status) return this._runDiscard(discardContent);
337
- const execution = this[kExec].get('execution');
437
+ const execution = this[K_EXEC].get('execution');
338
438
  if (execution && !execution.completed) return execution.discard();
339
439
 
340
440
  this._deactivateRunConsumers();
341
441
  const broker = this.broker;
342
442
  broker.getQueue('run-q').purge();
343
- broker.publish('run', 'run.discard', cloneContent(this[kStateMessage].content));
344
- this[kConsuming] = true;
443
+ broker.publish('run', 'run.discard', cloneContent(this[K_STATE_MESSAGE].content));
444
+ this[K_CONSUMING] = true;
345
445
  this._consumeRunQ();
346
446
  };
347
447
 
448
+ /**
449
+ * Subscribe to inbound triggers (sequence flows, attached activity, or compensation associations).
450
+ * @returns {number} count of subscribed triggers
451
+ */
348
452
  Activity.prototype.addInboundListeners = function addInboundListeners() {
349
- const onInboundEvent = this._onInboundEvent.bind(this);
350
- const triggerConsumerTag = `_inbound-${this.id}`;
351
- for (const trigger of this[kFlows].inboundTriggers) {
352
- if (trigger.isSequenceFlow) {
353
- trigger.broker.subscribeTmp('event', 'flow.#', onInboundEvent, { noAck: true, consumerTag: triggerConsumerTag });
354
- } else if (this.isForCompensation) {
355
- trigger.broker.subscribeTmp('event', 'association.#', onInboundEvent, { noAck: true, consumerTag: triggerConsumerTag });
356
- } else {
357
- trigger.broker.subscribeTmp('event', 'activity.#', onInboundEvent, { noAck: true, consumerTag: triggerConsumerTag });
453
+ const triggers = this._getInboundTriggers();
454
+ if (triggers.length) {
455
+ const onInboundEvent = this._onInboundEvent.bind(this);
456
+ const triggerConsumerTag = `_inbound-${this.id}`;
457
+ for (const trigger of triggers) {
458
+ if (trigger.isSequenceFlow) {
459
+ trigger.broker.subscribeTmp('event', 'flow.#', onInboundEvent, { noAck: true, consumerTag: triggerConsumerTag });
460
+ } else if (this.isForCompensation) {
461
+ trigger.broker.subscribeTmp('event', 'association.#', onInboundEvent, { noAck: true, consumerTag: triggerConsumerTag });
462
+ } else {
463
+ trigger.broker.subscribeTmp('event', 'activity.#', onInboundEvent, { noAck: true, consumerTag: triggerConsumerTag });
464
+ }
358
465
  }
359
466
  }
467
+ return triggers.length;
360
468
  };
361
469
 
470
+ /**
471
+ * Cancel inbound trigger subscriptions added by addInboundListeners.
472
+ */
362
473
  Activity.prototype.removeInboundListeners = function removeInboundListeners() {
474
+ const triggers = this[K_FLOWS].inboundTriggers;
475
+ if (!triggers) return;
363
476
  const triggerConsumerTag = `_inbound-${this.id}`;
364
- for (const trigger of this[kFlows].inboundTriggers) {
477
+ for (const trigger of triggers) {
365
478
  trigger.broker.cancel(triggerConsumerTag);
366
479
  }
367
480
  };
368
481
 
482
+ /**
483
+ * Stop the activity. If not currently running, just cancels the inbound consumer.
484
+ */
369
485
  Activity.prototype.stop = function stop() {
370
- if (!this[kConsuming]) return this.broker.cancel('_run-on-inbound');
371
- return this.getApi(this[kStateMessage]).stop();
486
+ if (!this[K_CONSUMING]) return this.broker.cancel('_run-on-inbound');
487
+ return this.getApi(this[K_STATE_MESSAGE]).stop();
372
488
  };
373
489
 
490
+ /**
491
+ * Advance one run-step when the environment runs in step mode. No-op otherwise.
492
+ */
374
493
  Activity.prototype.next = function next() {
375
494
  if (!this.environment.settings.step) return;
376
- const stateMessage = this[kStateMessage];
495
+ /** @type {import('#types').ElementBrokerMessage} */
496
+ const stateMessage = this[K_STATE_MESSAGE];
377
497
  if (!stateMessage) return;
378
498
  if (this.status === 'executing') return false;
379
499
  if (this.status === 'formatting') return false;
@@ -382,26 +502,46 @@ Activity.prototype.next = function next() {
382
502
  return current;
383
503
  };
384
504
 
505
+ /**
506
+ * Walk outbound flows to discover the activity graph from this point.
507
+ */
385
508
  Activity.prototype.shake = function shake() {
386
509
  this._shakeOutbound({ content: this._createMessage() });
387
510
  };
388
511
 
512
+ /**
513
+ * Evaluate outbound sequence flows for the given source message.
514
+ * @param {import('#types').ElementBrokerMessage} fromMessage Source run message
515
+ * @param {boolean} discardRestAtTake When true, take only the first matching flow and discard the rest
516
+ * @param {(err: Error, evaluationResult: any) => void} callback
517
+ * @returns {void}
518
+ */
389
519
  Activity.prototype.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) {
390
- return this[kFlows].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback);
520
+ return this[K_FLOWS].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback);
391
521
  };
392
522
 
523
+ /**
524
+ * Resolve an Api wrapper for the activity, preferring the running execution if any.
525
+ * @param {import('#types').ElementBrokerMessage} [message]
526
+ * @returns {import('#types').IApi<import('./Activity.js').Activity>}
527
+ */
393
528
  Activity.prototype.getApi = function getApi(message) {
394
- const execution = this[kExec].get('execution');
529
+ const execution = this[K_EXEC].get('execution');
395
530
  if (execution && !execution.completed) return execution.getApi(message);
396
- return ActivityApi(this.broker, message || this[kStateMessage]);
531
+ return ActivityApi(this.broker, message || this[K_STATE_MESSAGE]);
397
532
  };
398
533
 
534
+ /**
535
+ * Look up another activity in the same context.
536
+ * @param {string} elementId
537
+ */
399
538
  Activity.prototype.getActivityById = function getActivityById(elementId) {
400
539
  return this.context.getActivityById(elementId);
401
540
  };
402
541
 
542
+ /** @internal */
403
543
  Activity.prototype._runDiscard = function runDiscard(discardContent) {
404
- const exec = this[kExec];
544
+ const exec = this[K_EXEC];
405
545
  const executionId = exec.get('initExecutionId') || getUniqueId(this.id);
406
546
  exec.set('executionId', executionId);
407
547
  exec.delete('initExecutionId');
@@ -411,15 +551,16 @@ Activity.prototype._runDiscard = function runDiscard(discardContent) {
411
551
  const content = this._createMessage({ ...discardContent, executionId });
412
552
  this.broker.publish('run', 'run.discard', content);
413
553
 
414
- this[kConsuming] = true;
554
+ this[K_CONSUMING] = true;
415
555
  this._consumeRunQ();
416
556
  };
417
557
 
558
+ /** @internal */
418
559
  Activity.prototype._discardRun = function discardRun() {
419
560
  const status = this.status;
420
561
  if (!status) return;
421
562
 
422
- const execution = this[kExec].get('execution');
563
+ const execution = this[K_EXEC].get('execution');
423
564
  if (execution && !execution.completed) return;
424
565
 
425
566
  let discardRoutingKey = 'run.discard';
@@ -437,47 +578,82 @@ Activity.prototype._discardRun = function discardRun() {
437
578
 
438
579
  this._deactivateRunConsumers();
439
580
 
440
- const stateMessage = this[kStateMessage];
581
+ const stateMessage = this[K_STATE_MESSAGE];
441
582
  if (this.extensions) this.extensions.deactivate(cloneMessage(stateMessage));
442
583
 
443
584
  const broker = this.broker;
444
585
  broker.getQueue('run-q').purge();
445
586
 
446
587
  broker.publish('run', discardRoutingKey, cloneContent(stateMessage.content), { correlationId: stateMessage.properties.correlationId });
447
- this[kConsuming] = true;
588
+ this[K_CONSUMING] = true;
448
589
  this._consumeRunQ();
449
590
  };
450
591
 
592
+ /** @internal */
593
+ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) {
594
+ if (this[K_FLAGS].isParallelGateway) {
595
+ const message = cloneMessage(sourceMessage, { join: this.id });
596
+ message.content.sequence.push({ id: this.id, type: this.type });
597
+ return this.broker.publish('event', 'activity.shake.join', message.content, {
598
+ persistent: false,
599
+ type: 'shake',
600
+ });
601
+ }
602
+
603
+ this._shakeOutbound(sourceMessage);
604
+ };
605
+
606
+ /** @internal */
451
607
  Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) {
452
608
  const message = cloneMessage(sourceMessage);
453
- message.content.sequence = message.content.sequence || [];
454
- message.content.sequence.push({ id: this.id, type: this.type });
609
+ const sequence = (message.content.sequence = message.content.sequence || []);
610
+ const count = 1;
611
+ const looped = sequence?.find((f) => f.id === this.id);
612
+
613
+ sequence.push({ id: this.id, type: this.type, count: looped ? looped.count + 1 : count });
455
614
 
456
- const broker = this.broker;
457
615
  this.broker.publish('api', 'activity.shake.start', message.content, { persistent: false, type: 'shake' });
458
616
 
459
- if (this[kFlags].isEnd) {
460
- return broker.publish('event', 'activity.shake.end', message.content, { persistent: false, type: 'shake' });
617
+ const flags = this[K_FLAGS];
618
+ if (flags.isThrowing && flags.linkNames?.length) {
619
+ for (const target of this.context.getActivitiesByEventDefinitionBehaviour(flags.linkBehaviour, flags.linkNames)) {
620
+ if (target.id === this.id || !target.isCatching) continue;
621
+ const linkedContent = cloneContent(message.content, { sourceId: this.id, targetId: target.id, isLinked: true });
622
+ linkedContent.sequence = linkedContent.sequence.concat({ id: target.id, type: target.type });
623
+ target.broker.publish('event', 'activity.shake.linked', linkedContent, { persistent: false, type: 'shake' });
624
+ for (const flow of target.outbound) flow.shake({ content: cloneContent(linkedContent) });
625
+ }
626
+ }
627
+
628
+ if (this[K_FLAGS].isEnd) {
629
+ return this.broker.publish('event', 'activity.shake.end', cloneContent(message.content), { persistent: false, type: 'shake' });
630
+ }
631
+
632
+ const targets = new Map();
633
+
634
+ for (const outboundFlow of this[K_FLOWS].outboundSequenceFlows) {
635
+ const prevTarget = targets.get(outboundFlow.targetId);
636
+ if (!prevTarget) {
637
+ targets.set(outboundFlow.targetId, outboundFlow);
638
+ }
461
639
  }
462
640
 
463
- for (const flow of this[kFlows].outboundSequenceFlows) flow.shake(message);
641
+ for (const t of targets.values()) t.shake(message);
464
642
  };
465
643
 
644
+ /** @internal */
466
645
  Activity.prototype._consumeInbound = function consumeInbound() {
467
- if (!this[kActivated]) return;
646
+ if (!this[K_ACTIVATED]) return;
468
647
 
469
- if (this.status) return;
648
+ if (this.status || !this._getInboundTriggers().length) return;
470
649
 
471
650
  const inboundQ = this.broker.getQueue('inbound-q');
472
- const onInbound = this[kMessageHandlers].onInbound;
651
+ const onInbound = this[K_MESSAGE_HANDLERS].onInbound;
473
652
 
474
- if (this[kFlags].isParallelJoin) {
475
- return inboundQ.consume(onInbound, { consumerTag: '_run-on-inbound', prefetch: 1000 });
476
- }
477
-
478
- return inboundQ.consume(onInbound, { consumerTag: '_run-on-inbound' });
653
+ return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' });
479
654
  };
480
655
 
656
+ /** @internal */
481
657
  Activity.prototype._onInbound = function onInbound(routingKey, message) {
482
658
  message.ack();
483
659
  const broker = this.broker;
@@ -487,6 +663,12 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) {
487
663
  const inbound = [cloneContent(content)];
488
664
 
489
665
  switch (routingKey) {
666
+ case 'activity.relink':
667
+ if (content.executionId) this[K_EXEC].set('initExecutionId', content.executionId);
668
+ return this.run({
669
+ message: content.message,
670
+ inbound,
671
+ });
490
672
  case 'association.take':
491
673
  case 'flow.take':
492
674
  case 'activity.restart':
@@ -495,64 +677,13 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) {
495
677
  message: content.message,
496
678
  inbound,
497
679
  });
498
- case 'flow.discard':
499
680
  case 'activity.discard': {
500
- let discardSequence;
501
- if (content.discardSequence) discardSequence = content.discardSequence.slice();
502
- return this._runDiscard({ inbound, discardSequence });
503
- }
504
- }
505
- };
506
-
507
- Activity.prototype._onJoinInbound = function onJoinInbound(routingKey, message) {
508
- const { content } = message;
509
- const { inboundJoinFlows, inboundSourceIds } = this[kFlows];
510
- let alreadyTouched = false;
511
-
512
- const touched = new Set();
513
-
514
- let taken;
515
- for (const msg of inboundJoinFlows) {
516
- const sourceId = msg.content.sourceId;
517
- touched.add(sourceId);
518
- if (sourceId === content.sourceId) {
519
- alreadyTouched = true;
520
- }
521
- }
522
-
523
- inboundJoinFlows.add(message);
524
-
525
- if (alreadyTouched) return;
526
-
527
- const remaining = inboundSourceIds.size - touched.size - 1;
528
- if (remaining) {
529
- return this.logger.debug(`<${this.id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`);
530
- }
531
-
532
- const inbound = [];
533
- for (const im of inboundJoinFlows) {
534
- if (im.fields.routingKey === 'flow.take') taken = true;
535
- im.ack();
536
- inbound.push(cloneContent(im.content));
537
- }
538
-
539
- const discardSequence = new Set();
540
- if (!taken) {
541
- for (const im of inboundJoinFlows) {
542
- if (!im.content.discardSequence) continue;
543
- for (const sourceId of im.content.discardSequence) {
544
- discardSequence.add(sourceId);
545
- }
681
+ return this._runDiscard({ inbound });
546
682
  }
547
683
  }
548
-
549
- inboundJoinFlows.clear();
550
- this.broker.cancel('_run-on-inbound');
551
-
552
- if (!taken) return this._runDiscard({ inbound, discardSequence: [...discardSequence] });
553
- return this.run({ inbound });
554
684
  };
555
685
 
686
+ /** @internal */
556
687
  Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message) {
557
688
  const { fields, content, properties } = message;
558
689
  const inboundQ = this.broker.getQueue('inbound-q');
@@ -560,36 +691,54 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message
560
691
  switch (routingKey) {
561
692
  case 'activity.enter':
562
693
  case 'activity.discard': {
563
- if (content.id === this[kFlags].attachedTo) {
694
+ if (content.id === this[K_FLAGS].attachedTo) {
564
695
  inboundQ.queueMessage(fields, cloneContent(content), properties);
565
696
  }
566
697
  break;
567
698
  }
568
- case 'flow.shake': {
569
- return this._shakeOutbound(message);
699
+ case 'flow.shake':
700
+ case 'activity.shake.start':
701
+ return this._onShakeMessage(message);
702
+ case 'activity.link': {
703
+ const linkName = content.message?.linkName;
704
+ if (!this[K_FLAGS].linkNames?.includes(linkName)) break;
705
+ const executionId = getUniqueId(this.id);
706
+ this.broker.publish(
707
+ 'event',
708
+ 'activity.enter',
709
+ cloneContent(content, { id: this.id, type: this.type, executionId, state: 'enter', message: { ...content.message } })
710
+ );
711
+ inboundQ.queueMessage(
712
+ { routingKey: 'activity.relink' },
713
+ cloneContent(content, { id: this.id, executionId, message: { ...content.message } }),
714
+ properties
715
+ );
716
+ return;
570
717
  }
571
718
  case 'association.take':
572
719
  case 'flow.take':
573
- case 'flow.discard':
574
720
  return inboundQ.queueMessage(fields, cloneContent(content), properties);
575
721
  }
576
722
  };
577
723
 
724
+ /** @internal */
578
725
  Activity.prototype._consumeRunQ = function consumeRunQ() {
579
- this[kConsumingRunQ] = true;
580
- this.broker.getQueue('run-q').assertConsumer(this[kMessageHandlers].onRunMessage, { exclusive: true, consumerTag: '_activity-run' });
726
+ this[K_CONSUMING_RUN_Q] = true;
727
+ this.broker.getQueue('run-q').assertConsumer(this[K_MESSAGE_HANDLERS].onRunMessage, { exclusive: true, consumerTag: '_activity-run' });
581
728
  };
582
729
 
730
+ /** @internal */
583
731
  Activity.prototype._pauseRunQ = function pauseRunQ() {
584
- if (!this[kConsumingRunQ]) return;
732
+ if (!this[K_CONSUMING_RUN_Q]) return;
585
733
 
586
- this[kConsumingRunQ] = false;
734
+ this[K_CONSUMING_RUN_Q] = false;
587
735
  this.broker.cancel('_activity-run');
588
736
  };
589
737
 
738
+ /** @internal */
590
739
  Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, messageProperties) {
591
740
  switch (routingKey) {
592
- case 'run.outbound.discard':
741
+ case 'run.execute.passthrough':
593
742
  case 'run.outbound.take':
594
743
  case 'run.next':
595
744
  return this._continueRunMessage(routingKey, message, messageProperties);
@@ -611,6 +760,7 @@ Activity.prototype._onRunMessage = function onRunMessage(routingKey, message, me
611
760
  });
612
761
  };
613
762
 
763
+ /** @internal */
614
764
  Activity.prototype._continueRunMessage = function continueRunMessage(routingKey, message) {
615
765
  const isRedelivered = message.fields.redelivered;
616
766
  const content = cloneContent(message.content);
@@ -618,7 +768,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
618
768
 
619
769
  const id = this.id;
620
770
  const step = this.environment.settings.step;
621
- this[kStateMessage] = message;
771
+ this[K_STATE_MESSAGE] = message;
622
772
 
623
773
  switch (routingKey) {
624
774
  case 'run.enter': {
@@ -626,7 +776,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
626
776
 
627
777
  this.status = 'entered';
628
778
  if (!isRedelivered) {
629
- this[kExec].delete('execution');
779
+ this[K_EXEC].delete('execution');
630
780
  if (this.extensions) this.extensions.activate(cloneMessage(message));
631
781
  this._publishEvent('enter', content, { correlationId });
632
782
  }
@@ -636,7 +786,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
636
786
  this.logger.debug(`<${id}> discard`, isRedelivered ? 'redelivered' : '');
637
787
 
638
788
  this.status = 'discard';
639
- this[kExec].delete('execution');
789
+ this[K_EXEC].delete('execution');
640
790
 
641
791
  if (this.extensions) this.extensions.activate(cloneMessage(message));
642
792
 
@@ -656,20 +806,20 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
656
806
  break;
657
807
  }
658
808
  case 'run.execute.passthrough': {
659
- const execution = this[kExec].get('execution');
809
+ const execution = this[K_EXEC].get('execution');
660
810
  if (!isRedelivered && execution) {
661
811
  if (execution.completed) return message.ack();
662
- this[kExecuteMessage] = message;
812
+ this[K_EXECUTE_MESSAGE] = message;
663
813
  return execution.passthrough(message);
664
814
  }
665
815
  }
666
816
  case 'run.execute': {
667
817
  this.status = 'executing';
668
- this[kExecuteMessage] = message;
818
+ this[K_EXECUTE_MESSAGE] = message;
669
819
 
670
820
  if (isRedelivered && this.extensions) this.extensions.activate(cloneMessage(message));
671
821
 
672
- const exec = this[kExec];
822
+ const exec = this[K_EXEC];
673
823
  let execution = exec.get('execution');
674
824
  if (!execution) {
675
825
  execution = new ActivityExecution(this, this.context);
@@ -678,14 +828,14 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
678
828
 
679
829
  this.broker
680
830
  .getQueue('execution-q')
681
- .assertConsumer(this[kMessageHandlers].onExecutionMessage, { exclusive: true, consumerTag: '_activity-execution' });
831
+ .assertConsumer(this[K_MESSAGE_HANDLERS].onExecutionMessage, { exclusive: true, consumerTag: '_activity-execution' });
682
832
  return execution.execute(message);
683
833
  }
684
834
  case 'run.end': {
685
835
  this.logger.debug(`<${id}> end`, isRedelivered ? 'redelivered' : '');
686
836
  if (isRedelivered) break;
687
837
 
688
- this[kCounters].taken++;
838
+ this[K_COUNTERS].taken++;
689
839
 
690
840
  this.status = 'end';
691
841
 
@@ -707,7 +857,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
707
857
  }
708
858
  case 'run.discarded': {
709
859
  this.logger.debug(`<${content.executionId} (${id})> discarded`);
710
- this[kCounters].discarded++;
860
+ this[K_COUNTERS].discarded++;
711
861
 
712
862
  this.status = 'discarded';
713
863
  content.outbound = undefined;
@@ -725,11 +875,6 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
725
875
  message.ack();
726
876
  return flow.take(content.flow);
727
877
  }
728
- case 'run.outbound.discard': {
729
- const flow = this._getOutboundSequenceFlowById(content.flow.id);
730
- message.ack();
731
- return flow.discard(content.flow);
732
- }
733
878
  case 'run.leave': {
734
879
  this.status = undefined;
735
880
 
@@ -751,8 +896,9 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
751
896
  if (!step) message.ack();
752
897
  };
753
898
 
899
+ /** @internal */
754
900
  Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey, message) {
755
- const executeMessage = this[kExecuteMessage];
901
+ const executeMessage = this[K_EXECUTE_MESSAGE];
756
902
  const content = cloneContent({
757
903
  ...executeMessage.content,
758
904
  ...message.content,
@@ -767,7 +913,7 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey,
767
913
 
768
914
  switch (routingKey) {
769
915
  case 'execution.outbound.take': {
770
- return this._doOutbound(message, false, (err, outbound) => {
916
+ return this._doOutbound(message, (err, outbound) => {
771
917
  message.ack();
772
918
  if (err) return this.emitFatal(err, content);
773
919
  broker.publish('run', 'run.execute.passthrough', cloneContent(content, { outbound }));
@@ -781,10 +927,11 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey,
781
927
  break;
782
928
  }
783
929
  case 'execution.cancel':
784
- case 'execution.discard':
930
+ case 'execution.discard': {
785
931
  this.status = 'discarded';
786
932
  broker.publish('run', 'run.discarded', content, { correlationId });
787
933
  break;
934
+ }
788
935
  default: {
789
936
  this.status = 'executed';
790
937
  broker.publish('run', 'run.end', content, { correlationId });
@@ -795,21 +942,23 @@ Activity.prototype._onExecutionMessage = function onExecutionMessage(routingKey,
795
942
  this._ackRunExecuteMessage();
796
943
  };
797
944
 
945
+ /** @internal */
798
946
  Activity.prototype._ackRunExecuteMessage = function ackRunExecuteMessage() {
799
947
  if (this.environment.settings.step) return;
800
- const executeMessage = this[kExecuteMessage];
948
+ const executeMessage = this[K_EXECUTE_MESSAGE];
801
949
  executeMessage.ack();
802
950
  };
803
951
 
952
+ /** @internal */
804
953
  Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOutbound) {
805
954
  const { content, properties } = message;
806
955
  const correlationId = properties.correlationId;
807
- if (content.ignoreOutbound) {
956
+ if (isDiscarded || content.ignoreOutbound) {
808
957
  this.broker.publish('run', 'run.leave', cloneContent(content), { correlationId });
809
958
  return onOutbound();
810
959
  }
811
960
 
812
- return this._doOutbound(cloneMessage(message), isDiscarded, (err, outbound) => {
961
+ return this._doOutbound(cloneMessage(message), (err, outbound) => {
813
962
  if (err) {
814
963
  return this._publishEvent('error', { ...content, error: err }, { correlationId });
815
964
  }
@@ -827,39 +976,34 @@ Activity.prototype._doRunLeave = function doRunLeave(message, isDiscarded, onOut
827
976
  });
828
977
  };
829
978
 
830
- Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) {
831
- const outboundSequenceFlows = this[kFlows].outboundSequenceFlows;
979
+ /** @internal */
980
+ Activity.prototype._doOutbound = function doOutbound(fromMessage, callback) {
981
+ const outboundSequenceFlows = this[K_FLOWS].outboundSequenceFlows;
832
982
  if (!outboundSequenceFlows.length) return callback(null, []);
833
983
 
834
984
  const fromContent = fromMessage.content;
835
985
 
836
- let discardSequence = fromContent.discardSequence;
837
- if (isDiscarded && !discardSequence && this[kFlags].attachedTo && fromContent.inbound?.[0]) {
838
- discardSequence = [fromContent.inbound[0].id];
839
- }
840
-
841
986
  let outboundFlows;
842
- if (isDiscarded) {
843
- outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, { action: 'discard' }));
844
- } else if (fromContent.outbound?.length) {
987
+ if (fromContent.outbound?.length) {
845
988
  outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, fromContent.outbound.filter((f) => f.id === flow.id).pop()));
846
989
  }
847
990
 
848
991
  if (outboundFlows) {
849
- this._doRunOutbound(outboundFlows, fromContent, discardSequence);
992
+ this._doRunOutbound(outboundFlows, fromContent);
850
993
  return callback(null, outboundFlows);
851
994
  }
852
995
 
853
996
  return this.evaluateOutbound(fromMessage, fromContent.outboundTakeOne, (err, evaluatedOutbound) => {
854
997
  if (err) return callback(new ActivityError(err.message, fromMessage, err));
855
- const outbound = this._doRunOutbound(evaluatedOutbound, fromContent, discardSequence);
998
+ const outbound = this._doRunOutbound(evaluatedOutbound, fromContent);
856
999
  return callback(null, outbound);
857
1000
  });
858
1001
  };
859
1002
 
860
- Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) {
1003
+ /** @internal */
1004
+ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content) {
861
1005
  if (outboundList.length === 1) {
862
- this._publishRunOutbound(outboundList[0], content, discardSequence);
1006
+ this._publishRunOutbound(outboundList[0], content);
863
1007
  } else {
864
1008
  const targets = new Map();
865
1009
 
@@ -873,15 +1017,21 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content
873
1017
  }
874
1018
 
875
1019
  for (const outboundFlow of targets.values()) {
876
- this._publishRunOutbound(outboundFlow, content, discardSequence);
1020
+ this._publishRunOutbound(outboundFlow, content);
877
1021
  }
878
1022
  }
879
1023
 
880
1024
  return outboundList;
881
1025
  };
882
1026
 
883
- Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content, discardSequence) {
1027
+ /** @internal */
1028
+ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlow, content) {
884
1029
  const { id: flowId, action, result } = outboundFlow;
1030
+
1031
+ if (action === 'discard') {
1032
+ return;
1033
+ }
1034
+
885
1035
  this.broker.publish(
886
1036
  'run',
887
1037
  'run.outbound.' + action,
@@ -890,16 +1040,16 @@ Activity.prototype._publishRunOutbound = function publishRunOutbound(outboundFlo
890
1040
  ...(result && typeof result === 'object' && result),
891
1041
  ...outboundFlow,
892
1042
  sequenceId: getUniqueId(`${flowId}_${action}`),
893
- ...(discardSequence && { discardSequence: discardSequence.slice() }),
894
1043
  },
895
1044
  })
896
1045
  );
897
1046
  };
898
1047
 
1048
+ /** @internal */
899
1049
  Activity.prototype._onResumeMessage = function onResumeMessage(message) {
900
1050
  message.ack();
901
1051
 
902
- const stateMessage = this[kStateMessage];
1052
+ const stateMessage = this[K_STATE_MESSAGE];
903
1053
  const fields = stateMessage.fields;
904
1054
  if (!fields.redelivered) return;
905
1055
 
@@ -921,6 +1071,7 @@ Activity.prototype._onResumeMessage = function onResumeMessage(message) {
921
1071
  return this.broker.publish('run', fields.routingKey, cloneContent(stateMessage.content), stateMessage.properties);
922
1072
  };
923
1073
 
1074
+ /** @internal */
924
1075
  Activity.prototype._publishEvent = function publishEvent(state, content, properties) {
925
1076
  this.broker.publish('event', `activity.${state}`, cloneContent(content, { state }), {
926
1077
  ...properties,
@@ -929,12 +1080,13 @@ Activity.prototype._publishEvent = function publishEvent(state, content, propert
929
1080
  });
930
1081
  };
931
1082
 
1083
+ /** @internal */
932
1084
  Activity.prototype._onStop = function onStop(message) {
933
- const running = this[kConsuming];
1085
+ const running = this[K_CONSUMING];
934
1086
 
935
1087
  this.stopped = true;
936
1088
 
937
- this[kConsuming] = false;
1089
+ this[K_CONSUMING] = false;
938
1090
  const broker = this.broker;
939
1091
  this._pauseRunQ();
940
1092
  broker.cancel('_activity-api');
@@ -949,18 +1101,20 @@ Activity.prototype._onStop = function onStop(message) {
949
1101
  }
950
1102
  };
951
1103
 
1104
+ /** @internal */
952
1105
  Activity.prototype._consumeApi = function consumeApi() {
953
- const executionId = this[kExec].get('executionId');
1106
+ const executionId = this[K_EXEC].get('executionId');
954
1107
  if (!executionId) return;
955
1108
  const broker = this.broker;
956
1109
  broker.cancel('_activity-api');
957
- broker.subscribeTmp('api', `activity.*.${executionId}`, this[kMessageHandlers].onApiMessage, {
1110
+ broker.subscribeTmp('api', `activity.*.${executionId}`, this[K_MESSAGE_HANDLERS].onApiMessage, {
958
1111
  noAck: true,
959
1112
  consumerTag: '_activity-api',
960
1113
  priority: 100,
961
1114
  });
962
1115
  };
963
1116
 
1117
+ /** @internal */
964
1118
  Activity.prototype._onApiMessage = function onApiMessage(routingKey, message) {
965
1119
  switch (message.properties.type) {
966
1120
  case 'discard': {
@@ -975,6 +1129,7 @@ Activity.prototype._onApiMessage = function onApiMessage(routingKey, message) {
975
1129
  }
976
1130
  };
977
1131
 
1132
+ /** @internal */
978
1133
  Activity.prototype._createMessage = function createMessage(override) {
979
1134
  const { name, status, parent } = this;
980
1135
 
@@ -987,21 +1142,23 @@ Activity.prototype._createMessage = function createMessage(override) {
987
1142
  ...(parent && { parent: cloneParent(parent) }),
988
1143
  };
989
1144
 
990
- for (const [flag, value] of Object.entries(this[kFlags])) {
1145
+ for (const [flag, value] of Object.entries(this[K_FLAGS])) {
991
1146
  if (value) result[flag] = value;
992
1147
  }
993
1148
 
994
1149
  return result;
995
1150
  };
996
1151
 
1152
+ /** @internal */
997
1153
  Activity.prototype._getOutboundSequenceFlowById = function getOutboundSequenceFlowById(flowId) {
998
- return this[kFlows].outboundSequenceFlows.find((flow) => flow.id === flowId);
1154
+ return this[K_FLOWS].outboundSequenceFlows.find((flow) => flow.id === flowId);
999
1155
  };
1000
1156
 
1157
+ /** @internal */
1001
1158
  Activity.prototype._deactivateRunConsumers = function _deactivateRunConsumers() {
1002
1159
  const broker = this.broker;
1003
1160
  broker.cancel('_activity-api');
1004
1161
  this._pauseRunQ();
1005
1162
  broker.cancel('_activity-execution');
1006
- this[kConsuming] = false;
1163
+ this[K_CONSUMING] = false;
1007
1164
  };