bpmn-elements 17.3.0 → 18.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +434 -233
  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 +27 -0
  20. package/dist/definition/Definition.js +187 -64
  21. package/dist/definition/DefinitionExecution.js +198 -84
  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 +1 -1
  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 +176 -77
  62. package/dist/process/ProcessExecution.js +397 -178
  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 +372 -218
  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 +21 -0
  95. package/src/definition/Definition.js +165 -63
  96. package/src/definition/DefinitionExecution.js +164 -85
  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 +1 -1
  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 +157 -74
  137. package/src/process/ProcessExecution.js +363 -176
  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 +2619 -84
  154. package/types/interfaces.d.ts +638 -0
  155. package/types/types.d.ts +0 -765
@@ -2,24 +2,25 @@ import { ProcessApi } from '../Api.js';
2
2
  import { cloneContent, cloneMessage, pushParent } from '../messageHelper.js';
3
3
  import { getUniqueId } from '../shared.js';
4
4
  import { ActivityTracker } from '../Tracker.js';
5
-
6
- export default ProcessExecution;
7
-
8
- const kActivated = Symbol.for('activated');
9
- const kActivityQ = Symbol.for('activityQ');
10
- const kCompleted = Symbol.for('completed');
11
- const kElements = Symbol.for('elements');
12
- const kExecuteMessage = Symbol.for('executeMessage');
13
- const kMessageHandlers = Symbol.for('messageHandlers');
14
- const kParent = Symbol.for('parent');
15
- const kStatus = Symbol.for('status');
16
- const kStopped = Symbol.for('stopped');
17
- const kTracker = Symbol.for('activity tracker');
18
-
19
- function ProcessExecution(parentActivity, context) {
5
+ import { K_ACTIVATED, K_COMPLETED, K_EXECUTE_MESSAGE, K_MESSAGE_HANDLERS, K_STATUS, K_STOPPED, STATE_VERSION } from '../constants.js';
6
+
7
+ const K_ACTIVITY_Q = Symbol.for('activityQ');
8
+ const K_ELEMENTS = Symbol.for('elements');
9
+ const K_PARENT = Symbol.for('parent');
10
+ const K_TRACKER = Symbol.for('activity tracker');
11
+ const K_PEERS_DISCOVERED = Symbol.for('peers discovered');
12
+ const K_RECOVERED_VERSION = Symbol.for('recovered version');
13
+
14
+ /**
15
+ * Drives the execution of a single process or sub-process: activates children, routes activity
16
+ * events, and rolls completion up to the owning Process or sub-process Activity.
17
+ * @param {import('#types').Process | import('#types').Activity} parentActivity
18
+ * @param {import('#types').ContextInstance} context
19
+ */
20
+ export function ProcessExecution(parentActivity, context) {
20
21
  const { id, type, broker, isSubProcess, isTransaction } = parentActivity;
21
22
 
22
- this[kParent] = parentActivity;
23
+ this[K_PARENT] = parentActivity;
23
24
  this.id = id;
24
25
  this.type = type;
25
26
  this.isSubProcess = isSubProcess;
@@ -28,29 +29,30 @@ function ProcessExecution(parentActivity, context) {
28
29
  this.environment = context.environment;
29
30
  this.context = context;
30
31
 
31
- this[kElements] = {
32
+ this[K_ELEMENTS] = {
32
33
  postponed: new Set(),
33
34
  children: context.getActivities(id),
34
35
  associations: context.getAssociations(id),
35
36
  flows: context.getSequenceFlows(id),
36
37
  outboundMessageFlows: context.getMessageFlows(id),
37
38
  startActivities: new Set(),
39
+ startEventCount: 0,
38
40
  triggeredByEvent: new Set(),
39
41
  detachedActivities: new Set(),
40
- startSequences: {},
42
+ convergingGateways: new Set(),
41
43
  };
42
44
 
43
45
  const exchangeName = (this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution');
44
46
  broker.assertExchange(exchangeName, 'topic', { autoDelete: false, durable: true });
45
47
 
46
- this[kCompleted] = false;
47
- this[kStopped] = false;
48
- this[kActivated] = false;
49
- this[kStatus] = 'init';
50
- this[kTracker] = new ActivityTracker(id);
48
+ this[K_COMPLETED] = false;
49
+ this[K_STOPPED] = false;
50
+ this[K_ACTIVATED] = false;
51
+ this[K_STATUS] = 'init';
52
+ this[K_TRACKER] = new ActivityTracker(id);
51
53
  this.executionId = undefined;
52
54
 
53
- this[kMessageHandlers] = {
55
+ this[K_MESSAGE_HANDLERS] = {
54
56
  onActivityEvent: this._onActivityEvent.bind(this),
55
57
  onApiMessage: this._onApiMessage.bind(this),
56
58
  onChildMessage: this._onChildMessage.bind(this),
@@ -61,51 +63,56 @@ function ProcessExecution(parentActivity, context) {
61
63
  Object.defineProperties(ProcessExecution.prototype, {
62
64
  stopped: {
63
65
  get() {
64
- return this[kStopped];
66
+ return this[K_STOPPED];
65
67
  },
66
68
  },
67
69
  completed: {
68
70
  get() {
69
- return this[kCompleted];
71
+ return this[K_COMPLETED];
70
72
  },
71
73
  },
72
74
  status: {
73
75
  get() {
74
- return this[kStatus];
76
+ return this[K_STATUS];
75
77
  },
76
78
  },
77
79
  postponedCount: {
78
80
  get() {
79
- return this[kElements].postponed.size;
81
+ return this[K_ELEMENTS].postponed.size;
80
82
  },
81
83
  },
82
84
  isRunning: {
83
85
  get() {
84
- return this[kActivated];
86
+ return this[K_ACTIVATED];
85
87
  },
86
88
  },
87
89
  activityStatus: {
88
90
  get() {
89
- return this[kTracker].activityStatus;
91
+ return this[K_TRACKER].activityStatus;
90
92
  },
91
93
  },
92
94
  });
93
95
 
96
+ /**
97
+ * Activate children and start the process execution. Resumes if the message is redelivered.
98
+ * @param {import('#types').ElementBrokerMessage} executeMessage
99
+ * @throws {Error} when message or executionId is missing
100
+ */
94
101
  ProcessExecution.prototype.execute = function execute(executeMessage) {
95
102
  if (!executeMessage) throw new Error('Process execution requires message');
96
103
  if (!executeMessage.content || !executeMessage.content.executionId) throw new Error('Process execution requires execution id');
97
104
 
98
105
  const executionId = (this.executionId = executeMessage.content.executionId);
99
106
 
100
- this[kExecuteMessage] = cloneMessage(executeMessage, {
107
+ this[K_EXECUTE_MESSAGE] = cloneMessage(executeMessage, {
101
108
  executionId,
102
109
  state: 'start',
103
110
  });
104
111
 
105
- this[kStopped] = false;
112
+ this[K_STOPPED] = false;
106
113
 
107
114
  this.environment.assignVariables(executeMessage);
108
- this[kActivityQ] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false });
115
+ this[K_ACTIVITY_Q] = this.broker.assertQueue(`execute-${executionId}-q`, { durable: true, autoDelete: false });
109
116
 
110
117
  if (executeMessage.fields.redelivered) {
111
118
  return this.resume();
@@ -117,33 +124,33 @@ ProcessExecution.prototype.execute = function execute(executeMessage) {
117
124
  return true;
118
125
  };
119
126
 
127
+ /**
128
+ * Resume after recover, resuming any postponed children.
129
+ */
120
130
  ProcessExecution.prototype.resume = function resume() {
121
131
  this._debug(`resume process execution at ${this.status}`);
122
132
 
123
- if (this[kCompleted]) return this._complete('completed');
133
+ if (this[K_COMPLETED]) return this._complete('completed');
124
134
 
125
135
  this._activate();
126
136
 
127
- const { startActivities, detachedActivities, postponed } = this[kElements];
128
-
129
- if (startActivities.size > 1) {
130
- for (const a of startActivities) a.shake();
131
- }
137
+ const { postponed, detachedActivities } = this[K_ELEMENTS];
138
+ this._shakeOnStart();
132
139
 
133
140
  postponed.clear();
134
141
  detachedActivities.clear();
135
142
 
136
- this[kActivityQ].consume(this[kMessageHandlers].onChildMessage, {
143
+ this[K_ACTIVITY_Q].consume(this[K_MESSAGE_HANDLERS].onChildMessage, {
137
144
  prefetch: 1000,
138
145
  consumerTag: `_process-activity-${this.executionId}`,
139
146
  });
140
147
 
141
- if (this[kCompleted]) return;
148
+ if (this[K_COMPLETED]) return;
142
149
 
143
150
  const status = this.status;
144
151
  if (status === 'init') return this._start();
145
152
 
146
- const tracker = this[kTracker];
153
+ const tracker = this[K_TRACKER];
147
154
  for (const msg of new Set(postponed)) {
148
155
  const activity = this.getActivityById(msg.content.id);
149
156
  if (!activity) continue;
@@ -158,13 +165,21 @@ ProcessExecution.prototype.resume = function resume() {
158
165
  activity.resume();
159
166
  }
160
167
 
161
- if (this[kCompleted]) return;
168
+ if (this[K_COMPLETED]) return;
169
+
170
+ this._reconcileStartEvents();
171
+
172
+ if (this[K_COMPLETED]) return;
162
173
 
163
174
  if (!postponed.size && status === 'executing') return this._complete('completed');
164
175
  };
165
176
 
177
+ /**
178
+ * Snapshot execution state including children, flows, message flows, and associations.
179
+ * @returns {import('#types').ProcessExecutionState}
180
+ */
166
181
  ProcessExecution.prototype.getState = function getState() {
167
- const { children, flows, outboundMessageFlows, associations } = this[kElements];
182
+ const { children, flows, outboundMessageFlows, associations } = this[K_ELEMENTS];
168
183
 
169
184
  const flowStates = flows.reduce((result, flow) => {
170
185
  const elmState = flow.getState();
@@ -174,8 +189,8 @@ ProcessExecution.prototype.getState = function getState() {
174
189
 
175
190
  return {
176
191
  executionId: this.executionId,
177
- stopped: this[kStopped],
178
- completed: this[kCompleted],
192
+ stopped: this[K_STOPPED],
193
+ completed: this[K_COMPLETED],
179
194
  status: this.status,
180
195
  children: children.reduce((result, activity) => {
181
196
  if (activity.placeholder) return result;
@@ -191,13 +206,20 @@ ProcessExecution.prototype.getState = function getState() {
191
206
  };
192
207
  };
193
208
 
194
- ProcessExecution.prototype.recover = function recover(state) {
209
+ /**
210
+ * Restore execution state captured by getState.
211
+ * @param {import('#types').ProcessExecutionState} [state]
212
+ * @param {number} [recoveredVersion] State version
213
+ * @returns {this}
214
+ */
215
+ ProcessExecution.prototype.recover = function recover(state, recoveredVersion) {
195
216
  if (!state) return this;
196
217
  this.executionId = state.executionId;
218
+ this[K_RECOVERED_VERSION] = recoveredVersion;
197
219
 
198
- this[kStopped] = state.stopped;
199
- this[kCompleted] = state.completed;
200
- this[kStatus] = state.status;
220
+ this[K_STOPPED] = state.stopped;
221
+ this[K_COMPLETED] = state.completed;
222
+ this[K_STATUS] = state.status;
201
223
 
202
224
  this._debug(`recover process execution at ${this.status}`);
203
225
 
@@ -237,53 +259,29 @@ ProcessExecution.prototype.recover = function recover(state) {
237
259
  return this;
238
260
  };
239
261
 
262
+ /**
263
+ * Walk activity graph from the given start id, or every start activity when omitted.
264
+ * @param {string} [fromId]
265
+ * @returns {import('#types').ShakeResult}
266
+ */
240
267
  ProcessExecution.prototype.shake = function shake(fromId) {
241
- let executing = true;
242
- const id = this.id;
243
- if (!this.isRunning) {
244
- executing = false;
245
- this.executionId = getUniqueId(id);
246
- this._activate();
247
- }
248
- const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[kElements].startActivities;
249
-
250
- const result = {};
251
- this.broker.subscribeTmp(
252
- 'event',
253
- '*.shake.*',
254
- (routingKey, { content }) => {
255
- let isLooped = false;
256
- switch (routingKey) {
257
- case 'flow.shake.loop':
258
- isLooped = true;
259
- case 'activity.shake.end': {
260
- const { id: shakeId, parent: shakeParent } = content;
261
- if (shakeParent.id !== id) return;
262
-
263
- result[shakeId] = result[shakeId] || [];
264
- result[shakeId].push({ ...content, isLooped });
265
- break;
266
- }
267
- }
268
- },
269
- { noAck: true, consumerTag: `_shaker-${this.executionId}` }
270
- );
271
-
272
- for (const a of toShake) a.shake();
273
-
274
- if (!executing) this._deactivate();
275
- this.broker.cancel(`_shaker-${this.executionId}`);
276
-
277
- return result;
268
+ return Object.fromEntries(this._shakeElements(fromId).sequences);
278
269
  };
279
270
 
271
+ /**
272
+ * Stop the running process execution via the api.
273
+ */
280
274
  ProcessExecution.prototype.stop = function stop() {
281
275
  this.getApi().stop();
282
276
  };
283
277
 
278
+ /**
279
+ * List currently postponed children as Api wrappers.
280
+ * @param {import('#types').filterPostponed} [filterFn]
281
+ */
284
282
  ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) {
285
283
  const result = [];
286
- for (const msg of this[kElements].postponed) {
284
+ for (const msg of this[K_ELEMENTS].postponed) {
287
285
  const api = this._getChildApi(msg);
288
286
  if (!api) continue;
289
287
  if (filterFn && !filterFn(api)) continue;
@@ -292,9 +290,12 @@ ProcessExecution.prototype.getPostponed = function getPostponed(filterFn) {
292
290
  return result;
293
291
  };
294
292
 
293
+ /**
294
+ * Queue a discard message that propagates to all running children.
295
+ */
295
296
  ProcessExecution.prototype.discard = function discard() {
296
- this[kStatus] = 'discard';
297
- return this[kActivityQ].queueMessage(
297
+ this[K_STATUS] = 'discard';
298
+ this[K_ACTIVITY_Q].queueMessage(
298
299
  { routingKey: 'execution.discard' },
299
300
  {
300
301
  id: this.id,
@@ -305,8 +306,11 @@ ProcessExecution.prototype.discard = function discard() {
305
306
  );
306
307
  };
307
308
 
309
+ /**
310
+ * Queue a cancel message that propagates to all running children.
311
+ */
308
312
  ProcessExecution.prototype.cancel = function discard() {
309
- return this[kActivityQ].queueMessage(
313
+ this[K_ACTIVITY_Q].queueMessage(
310
314
  { routingKey: 'execution.cancel' },
311
315
  {
312
316
  id: this.id,
@@ -317,24 +321,45 @@ ProcessExecution.prototype.cancel = function discard() {
317
321
  );
318
322
  };
319
323
 
324
+ /**
325
+ * Get child activities in the process scope.
326
+ * @returns {import('#types').Activity[]}
327
+ */
320
328
  ProcessExecution.prototype.getActivities = function getActivities() {
321
- return this[kElements].children.slice();
329
+ return this[K_ELEMENTS].children.slice();
322
330
  };
323
331
 
332
+ /**
333
+ * @param {string} activityId
334
+ * @returns {import('#types').Activity}
335
+ */
324
336
  ProcessExecution.prototype.getActivityById = function getActivityById(activityId) {
325
- return this[kElements].children.find((child) => child.id === activityId);
337
+ return this[K_ELEMENTS].children.find((child) => child.id === activityId);
326
338
  };
327
339
 
340
+ /**
341
+ * Get sequence flows in the process scope.
342
+ * @returns {import('#types').SequenceFlow}
343
+ */
328
344
  ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() {
329
- return this[kElements].flows.slice();
345
+ return this[K_ELEMENTS].flows.slice();
330
346
  };
331
347
 
348
+ /**
349
+ * Get associations in the process scope.
350
+ * @returns {import('../flows/Association.js').Association}
351
+ */
332
352
  ProcessExecution.prototype.getAssociations = function getAssociations() {
333
- return this[kElements].associations.slice();
353
+ return this[K_ELEMENTS].associations.slice();
334
354
  };
335
355
 
356
+ /**
357
+ * Resolve a process or child Api for the given message.
358
+ * @param {import('#types').ElementBrokerMessage} [message]
359
+ * @returns {import('#types').IApi<import('#types').Process>}
360
+ */
336
361
  ProcessExecution.prototype.getApi = function getApi(message) {
337
- if (!message) return ProcessApi(this.broker, this[kExecuteMessage]);
362
+ if (!message) return ProcessApi(this.broker, this[K_EXECUTE_MESSAGE]);
338
363
 
339
364
  const content = message.content;
340
365
 
@@ -343,7 +368,7 @@ ProcessExecution.prototype.getApi = function getApi(message) {
343
368
  }
344
369
 
345
370
  const api = ProcessApi(this.broker, message);
346
- const postponed = this[kElements].postponed;
371
+ const postponed = this[K_ELEMENTS].postponed;
347
372
  const self = this;
348
373
 
349
374
  api.getExecuting = function getExecuting() {
@@ -358,36 +383,42 @@ ProcessExecution.prototype.getApi = function getApi(message) {
358
383
  return api;
359
384
  };
360
385
 
386
+ /** @internal */
361
387
  ProcessExecution.prototype._start = function start() {
362
- if (!this[kElements].children.length) {
388
+ if (!this[K_ELEMENTS].children.length) {
363
389
  return this._complete('completed');
364
390
  }
365
391
 
366
- this[kStatus] = 'start';
392
+ this[K_STATUS] = 'start';
367
393
 
368
- const executeContent = { ...this[kExecuteMessage].content, state: this.status };
394
+ const executeContent = { ...this[K_EXECUTE_MESSAGE].content, state: this.status };
369
395
 
370
396
  this.broker.publish(this._exchangeName, 'execute.start', cloneContent(executeContent));
371
397
 
372
- const { startActivities, postponed, detachedActivities } = this[kElements];
373
- if (startActivities.size > 1) {
374
- for (const a of startActivities) a.shake();
375
- }
398
+ const { startActivities, postponed, detachedActivities } = this[K_ELEMENTS];
399
+ this._shakeOnStart();
376
400
 
377
401
  for (const a of startActivities) a.init();
378
- this[kStatus] = 'executing';
402
+ this[K_STATUS] = 'executing';
379
403
  for (const a of startActivities) a.run();
380
404
 
405
+ if (!startActivities.size) {
406
+ for (const a of this[K_ELEMENTS].triggeredByEvent) {
407
+ if (a.isCatching && !a.isRunning) a.run();
408
+ }
409
+ }
410
+
381
411
  postponed.clear();
382
412
  detachedActivities.clear();
383
- this[kActivityQ].assertConsumer(this[kMessageHandlers].onChildMessage, {
413
+ this[K_ACTIVITY_Q].assertConsumer(this[K_MESSAGE_HANDLERS].onChildMessage, {
384
414
  prefetch: 1000,
385
415
  consumerTag: `_process-activity-${this.executionId}`,
386
416
  });
387
417
  };
388
418
 
419
+ /** @internal */
389
420
  ProcessExecution.prototype._activate = function activate() {
390
- const { onApiMessage, onMessageFlowEvent, onActivityEvent } = this[kMessageHandlers];
421
+ const { onApiMessage, onMessageFlowEvent, onActivityEvent } = this[K_MESSAGE_HANDLERS];
391
422
 
392
423
  if (!this.isSubProcess) {
393
424
  this.broker.consume('api-q', onApiMessage, {
@@ -403,7 +434,7 @@ ProcessExecution.prototype._activate = function activate() {
403
434
  });
404
435
  }
405
436
 
406
- const { outboundMessageFlows, flows, associations, startActivities, triggeredByEvent, children } = this[kElements];
437
+ const { outboundMessageFlows, flows, associations, startActivities, triggeredByEvent, convergingGateways, children } = this[K_ELEMENTS];
407
438
 
408
439
  for (const flow of outboundMessageFlows) {
409
440
  flow.activate();
@@ -433,6 +464,7 @@ ProcessExecution.prototype._activate = function activate() {
433
464
  startActivities.clear();
434
465
  triggeredByEvent.clear();
435
466
 
467
+ let startEventCount = 0;
436
468
  for (const activity of children) {
437
469
  if (activity.placeholder) continue;
438
470
  activity.activate(this);
@@ -441,20 +473,26 @@ ProcessExecution.prototype._activate = function activate() {
441
473
  consumerTag: '_process-activity-consumer',
442
474
  priority: 200,
443
475
  });
444
- if (activity.isStart) startActivities.add(activity);
445
- if (activity.triggeredByEvent) triggeredByEvent.add(activity);
476
+ if (activity.isStart) {
477
+ startActivities.add(activity);
478
+ if (activity.isStartEvent) startEventCount++;
479
+ }
480
+ if (activity.triggeredByEvent || activity.isCatching) triggeredByEvent.add(activity);
481
+ if (activity.isParallelGateway) convergingGateways.add(activity);
446
482
  }
447
483
 
448
- this[kActivated] = true;
484
+ this[K_ELEMENTS].startEventCount = startEventCount;
485
+ this[K_ACTIVATED] = true;
449
486
  };
450
487
 
488
+ /** @internal */
451
489
  ProcessExecution.prototype._deactivate = function deactivate() {
452
490
  const broker = this.broker;
453
491
  const executionId = this.executionId;
454
492
  broker.cancel(`_process-api-consumer-${executionId}`);
455
493
  broker.cancel(`_process-activity-${executionId}`);
456
494
 
457
- const { children, flows, associations, outboundMessageFlows } = this[kElements];
495
+ const { children, flows, associations, outboundMessageFlows } = this[K_ELEMENTS];
458
496
 
459
497
  for (const activity of children) {
460
498
  if (activity.placeholder) continue;
@@ -475,9 +513,108 @@ ProcessExecution.prototype._deactivate = function deactivate() {
475
513
  flow.broker.cancel('_process-message-consumer');
476
514
  }
477
515
 
478
- this[kActivated] = false;
516
+ this[K_ACTIVATED] = false;
517
+ };
518
+
519
+ /**
520
+ * Discover converging parallel gateway peers for the peer monitor, reusing already discovered ones.
521
+ * @internal
522
+ */
523
+ ProcessExecution.prototype._shakeOnStart = function shakeOnStart() {
524
+ const convergingGateways = this[K_ELEMENTS].convergingGateways;
525
+ if (!convergingGateways.size) return;
526
+
527
+ if (this._peersDiscovered()) {
528
+ this._debug(`reuse discovered parallel gateway peers (${convergingGateways.size})`);
529
+ return;
530
+ }
531
+
532
+ this._shakeElements();
533
+ this._debug(`forced shake to discover converging gateway peers (${convergingGateways.size})`);
534
+ };
535
+
536
+ /**
537
+ * Whether every converging parallel gateway has discovered its peers in this runtime instance.
538
+ * Peers are a runtime cache and absent after recover, so a changed source is reshaken.
539
+ * @internal
540
+ */
541
+ ProcessExecution.prototype._peersDiscovered = function peersDiscovered() {
542
+ const convergingGateways = this[K_ELEMENTS].convergingGateways;
543
+ for (const gateway of convergingGateways) {
544
+ if (!gateway[K_PEERS_DISCOVERED]) return false;
545
+ }
546
+ return true;
547
+ };
548
+
549
+ /** @internal */
550
+ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) {
551
+ let executing = true;
552
+ const id = this.id;
553
+ if (!this.isRunning) {
554
+ executing = false;
555
+ this.executionId = getUniqueId(id);
556
+ this._activate();
557
+ }
558
+ const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[K_ELEMENTS].startActivities;
559
+
560
+ const result = {
561
+ sequences: new Map(),
562
+ };
563
+
564
+ const convergingGateways = new Map();
565
+ const consumerTag = `_shaker-${this.executionId}`;
566
+
567
+ this.broker.subscribeTmp(
568
+ 'event',
569
+ '*.shake.*',
570
+ (routingKey, { content }) => {
571
+ if (content.parent.id !== this.id) return;
572
+
573
+ switch (routingKey) {
574
+ case 'activity.shake.join': {
575
+ const join = convergingGateways.get(content.join);
576
+ if (!join) {
577
+ convergingGateways.set(content.join, content);
578
+ } else {
579
+ join.sequence = join.sequence.concat(content.sequence);
580
+ }
581
+ break;
582
+ }
583
+ case 'flow.shake.loop':
584
+ case 'activity.shake.linked':
585
+ case 'activity.shake.end': {
586
+ const { id: shakeId, parent: shakeParent } = content;
587
+ if (shakeParent.id !== id) return;
588
+
589
+ let seqnce;
590
+ if (!(seqnce = result.sequences.get(shakeId))) {
591
+ seqnce = [];
592
+ result.sequences.set(shakeId, seqnce);
593
+ }
594
+ seqnce.push({ ...content, isLooped: routingKey === 'flow.shake.loop' });
595
+
596
+ break;
597
+ }
598
+ }
599
+ },
600
+ { noAck: true, consumerTag }
601
+ );
602
+
603
+ for (const a of toShake) a.shake();
604
+
605
+ for (const [aid, c] of convergingGateways.entries()) {
606
+ this._debug(`manual shake of converging gateway <${aid}>`);
607
+ this.getActivityById(aid).broker.publish('api', 'activity.shake.continue', c, { type: 'shake' });
608
+ }
609
+
610
+ if (!executing) this._deactivate();
611
+
612
+ this.broker.cancel(consumerTag);
613
+
614
+ return result;
479
615
  };
480
616
 
617
+ /** @internal */
481
618
  ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message) {
482
619
  const eventType = message.properties.type;
483
620
  let delegate = true;
@@ -489,8 +626,8 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message)
489
626
  this._debug(`delegate ${eventType} anonymous event`);
490
627
  }
491
628
 
492
- for (const activity of this[kElements].triggeredByEvent) {
493
- if (activity.getStartActivities({ referenceId: content.message?.id, referenceType: eventType }).length) {
629
+ for (const activity of this[K_ELEMENTS].triggeredByEvent) {
630
+ if (activity.isSubProcess && activity.getStartActivities({ referenceId: content.message?.id, referenceType: eventType }).length) {
494
631
  delegate = false;
495
632
  activity.run(content.message);
496
633
  }
@@ -501,17 +638,20 @@ ProcessExecution.prototype._onDelegateEvent = function onDelegateEvent(message)
501
638
  return delegate;
502
639
  };
503
640
 
641
+ /** @internal */
504
642
  ProcessExecution.prototype._onMessageFlowEvent = function onMessageFlowEvent(routingKey, message) {
505
643
  this.broker.publish('message', routingKey, cloneContent(message.content), message.properties);
506
644
  };
507
645
 
646
+ /** @internal */
508
647
  ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKey, message) {
509
- if (message.fields.redelivered && message.properties.persistent === false) return;
648
+ const { fields, content, properties } = message;
649
+
650
+ if (fields.redelivered && properties.persistent === false) return;
510
651
 
511
- const content = message.content;
512
652
  const parent = (content.parent = content.parent || {});
513
- let delegate = message.properties.delegate;
514
- const shaking = message.properties.type === 'shake';
653
+ let delegate = properties.delegate;
654
+ const shaking = properties.type === 'shake';
515
655
 
516
656
  const isDirectChild = content.parent.id === this.id;
517
657
  if (isDirectChild) {
@@ -522,14 +662,14 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe
522
662
 
523
663
  if (delegate) delegate = this._onDelegateEvent(message);
524
664
 
525
- this[kTracker].track(routingKey, message);
526
- this.broker.publish('event', routingKey, content, { ...message.properties, delegate, mandatory: false });
527
- if (shaking) return this._onShookEnd(message);
665
+ this[K_TRACKER].track(routingKey, message);
666
+ this.broker.publish('event', routingKey, content, { ...properties, delegate, mandatory: false });
667
+ if (shaking) return;
528
668
  if (!isDirectChild) return;
529
669
 
530
670
  switch (routingKey) {
531
671
  case 'process.terminate':
532
- return this[kActivityQ].queueMessage({ routingKey: 'execution.terminate' }, cloneContent(content), {
672
+ return this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.terminate' }, cloneContent(content), {
533
673
  type: 'terminate',
534
674
  persistent: true,
535
675
  });
@@ -537,9 +677,10 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe
537
677
  return;
538
678
  }
539
679
 
540
- this[kActivityQ].queueMessage(message.fields, cloneContent(content), { persistent: true, ...message.properties });
680
+ this[K_ACTIVITY_Q].queueMessage(message.fields, cloneContent(content), { persistent: true, ...message.properties });
541
681
  };
542
682
 
683
+ /** @internal */
543
684
  ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey, message) {
544
685
  if (message.fields.redelivered && message.properties.persistent === false) return message.ack();
545
686
 
@@ -557,7 +698,7 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
557
698
  return this._onDiscard(message);
558
699
  case 'execution.discard.detached': {
559
700
  message.ack();
560
- for (const detached of this[kElements].detachedActivities) {
701
+ for (const detached of this[K_ELEMENTS].detachedActivities) {
561
702
  this._getChildApi(detached).discard();
562
703
  }
563
704
  return;
@@ -567,7 +708,7 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
567
708
  return this._onCancel(message);
568
709
  case 'activity.error.caught': {
569
710
  let prevMsg;
570
- for (const msg of this[kElements].postponed) {
711
+ for (const msg of this[K_ELEMENTS].postponed) {
571
712
  if (msg.content.executionId === content.executionId) {
572
713
  prevMsg = msg;
573
714
  break;
@@ -576,7 +717,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
576
717
  if (!prevMsg) return message.ack();
577
718
  break;
578
719
  }
579
- case 'flow.looped':
580
720
  case 'activity.leave':
581
721
  return this._onChildCompleted(message);
582
722
  }
@@ -585,7 +725,7 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
585
725
 
586
726
  switch (routingKey) {
587
727
  case 'activity.detach': {
588
- this[kElements].detachedActivities.add(cloneMessage(message));
728
+ this[K_ELEMENTS].detachedActivities.add(cloneMessage(message));
589
729
  break;
590
730
  }
591
731
  case 'activity.cancel': {
@@ -604,16 +744,22 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
604
744
 
605
745
  break;
606
746
  }
747
+ case 'activity.end': {
748
+ if (!(content.isStartEvent || this.getActivityById(content.id)?.isStartEvent)) break;
749
+ if (this[K_ELEMENTS].startEventCount <= 1) break;
750
+ this._discardArmedStartEvents(content.id);
751
+ break;
752
+ }
607
753
  case 'activity.error': {
608
754
  let eventCaughtBy;
609
- for (const msg of this[kElements].postponed) {
755
+ for (const msg of this[K_ELEMENTS].postponed) {
610
756
  if (msg.fields.routingKey === 'activity.catch' && msg.content.source?.executionId === content.executionId) {
611
757
  eventCaughtBy = msg;
612
758
  break;
613
759
  }
614
760
  }
615
761
  if (eventCaughtBy) {
616
- this[kActivityQ].queueMessage({ routingKey: 'activity.error.caught' }, cloneContent(content), {
762
+ this[K_ACTIVITY_Q].queueMessage({ routingKey: 'activity.error.caught' }, cloneContent(content), {
617
763
  persistent: true,
618
764
  ...message.properties,
619
765
  });
@@ -624,14 +770,16 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
624
770
  }
625
771
  };
626
772
 
773
+ /** @internal */
627
774
  ProcessExecution.prototype._stateChangeMessage = function stateChangeMessage(message, postponeMessage) {
628
775
  const previousMsg = this._popPostponed(message.content);
629
776
  if (previousMsg) previousMsg.ack();
630
- if (postponeMessage) this[kElements].postponed.add(message);
777
+ if (postponeMessage) this[K_ELEMENTS].postponed.add(message);
631
778
  };
632
779
 
780
+ /** @internal */
633
781
  ProcessExecution.prototype._popPostponed = function popPostponed(byContent) {
634
- const { postponed, detachedActivities } = this[kElements];
782
+ const { postponed, detachedActivities } = this[K_ELEMENTS];
635
783
 
636
784
  let postponedMsg;
637
785
  if (byContent.sequenceId) {
@@ -663,13 +811,20 @@ ProcessExecution.prototype._popPostponed = function popPostponed(byContent) {
663
811
  return postponedMsg;
664
812
  };
665
813
 
814
+ /** @internal */
666
815
  ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message) {
667
816
  this._stateChangeMessage(message, false);
668
817
  if (message.fields.redelivered) return message.ack();
669
818
 
670
- const { id, type, isEnd } = message.content;
819
+ const { id, type, isParallelGateway } = message.content;
820
+
821
+ if (isParallelGateway) {
822
+ for (const inb of message.content.inbound) {
823
+ this._popPostponed(inb)?.ack();
824
+ }
825
+ }
671
826
 
672
- const { postponed, detachedActivities, startActivities } = this[kElements];
827
+ const { postponed, detachedActivities } = this[K_ELEMENTS];
673
828
  const postponedCount = postponed.size;
674
829
 
675
830
  if (!postponedCount) {
@@ -679,10 +834,10 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message
679
834
  }
680
835
 
681
836
  message.ack();
682
- this._debug(`left <${id}> (${type}), pending activities ${postponedCount}`);
837
+ this._debug(`left <${id}> (${type}), pending activities ${postponedCount} ${[...postponed].map((m) => m.content.id)}`);
683
838
 
684
839
  if (postponedCount && postponedCount === detachedActivities.size) {
685
- return this[kActivityQ].queueMessage(
840
+ return this[K_ACTIVITY_Q].queueMessage(
686
841
  { routingKey: 'execution.discard.detached' },
687
842
  {
688
843
  id: this.id,
@@ -692,21 +847,9 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message
692
847
  { type: 'cancel' }
693
848
  );
694
849
  }
695
-
696
- if (isEnd && startActivities.size) {
697
- const startSequences = this[kElements].startSequences;
698
- for (const msg of postponed) {
699
- const postponedId = msg.content.id;
700
- const startSequence = startSequences[postponedId];
701
- if (startSequence) {
702
- if (startSequence.content.sequence.some(({ id: sid }) => sid === id)) {
703
- this._getChildApi(msg).discard();
704
- }
705
- }
706
- }
707
- }
708
850
  };
709
851
 
852
+ /** @internal */
710
853
  ProcessExecution.prototype._stopExecution = function stopExecution(message) {
711
854
  const postponedCount = this.postponedCount;
712
855
  this._debug(`stop process execution (stop child executions ${postponedCount})`);
@@ -714,21 +857,22 @@ ProcessExecution.prototype._stopExecution = function stopExecution(message) {
714
857
  for (const api of this.getPostponed()) api.stop();
715
858
  }
716
859
  this._deactivate();
717
- this[kStopped] = true;
860
+ this[K_STOPPED] = true;
718
861
  return this.broker.publish(
719
862
  this._exchangeName,
720
863
  `execution.stopped.${this.executionId}`,
721
864
  {
722
- ...this[kExecuteMessage].content,
865
+ ...this[K_EXECUTE_MESSAGE].content,
723
866
  ...(message && message.content),
724
867
  },
725
868
  { type: 'stopped', persistent: false }
726
869
  );
727
870
  };
728
871
 
872
+ /** @internal */
729
873
  ProcessExecution.prototype._onDiscard = function onDiscard() {
730
874
  this._deactivate();
731
- const postponed = this[kElements].postponed;
875
+ const postponed = this[K_ELEMENTS].postponed;
732
876
  const running = new Set(postponed);
733
877
  postponed.clear();
734
878
 
@@ -742,23 +886,24 @@ ProcessExecution.prototype._onDiscard = function onDiscard() {
742
886
  for (const msg of running) this._getChildApi(msg).discard();
743
887
  }
744
888
 
745
- this[kActivityQ].purge();
889
+ this[K_ACTIVITY_Q].purge();
746
890
  return this._complete('discard');
747
891
  };
748
892
 
893
+ /** @internal */
749
894
  ProcessExecution.prototype._onCancel = function onCancel() {
750
- const postponed = this[kElements].postponed;
895
+ const postponed = this[K_ELEMENTS].postponed;
751
896
  const running = new Set(postponed);
752
897
 
753
898
  const isTransaction = this.isTransaction;
754
899
 
755
900
  if (isTransaction) {
756
901
  this._debug(`cancel transaction execution (cancel child executions ${running.size})`);
757
- this[kStatus] = 'cancel';
902
+ this[K_STATUS] = 'cancel';
758
903
  this.broker.publish(
759
904
  'event',
760
905
  'transaction.cancel',
761
- cloneMessage(this[kExecuteMessage], {
906
+ cloneMessage(this[K_EXECUTE_MESSAGE], {
762
907
  state: 'cancel',
763
908
  })
764
909
  );
@@ -778,6 +923,7 @@ ProcessExecution.prototype._onCancel = function onCancel() {
778
923
  }
779
924
  };
780
925
 
926
+ /** @internal */
781
927
  ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, message) {
782
928
  if (message.properties.delegate) {
783
929
  return this._delegateApiMessage(routingKey, message);
@@ -797,11 +943,12 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes
797
943
  case 'discard':
798
944
  return this.discard(message);
799
945
  case 'stop':
800
- this[kActivityQ].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false });
946
+ this[K_ACTIVITY_Q].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false });
801
947
  break;
802
948
  }
803
949
  };
804
950
 
951
+ /** @internal */
805
952
  ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(routingKey, message, continueOnConsumed) {
806
953
  const correlationId = message.properties.correlationId || getUniqueId(this.executionId);
807
954
  this._debug(`delegate api ${routingKey} message to children, with correlationId <${correlationId}>`);
@@ -820,8 +967,9 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou
820
967
  { consumerTag: `_ct-delegate-${correlationId}`, noAck: true }
821
968
  );
822
969
 
823
- for (const child of this[kElements].children) {
970
+ for (const child of this[K_ELEMENTS].children) {
824
971
  if (child.placeholder) continue;
972
+
825
973
  child.broker.publish('api', routingKey, cloneContent(message.content), message.properties);
826
974
  if (consumed && !continueOnConsumed) break;
827
975
  }
@@ -829,9 +977,10 @@ ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(rou
829
977
  return broker.cancel(`_ct-delegate-${correlationId}`);
830
978
  };
831
979
 
980
+ /** @internal */
832
981
  ProcessExecution.prototype._complete = function complete(completionType, content) {
833
982
  this._deactivate();
834
- this[kCompleted] = true;
983
+ this[K_COMPLETED] = true;
835
984
 
836
985
  const status = this.status;
837
986
  switch (this.status) {
@@ -844,16 +993,16 @@ ProcessExecution.prototype._complete = function complete(completionType, content
844
993
  break;
845
994
  default:
846
995
  this._debug(`process execution ${completionType}`);
847
- this[kStatus] = completionType;
996
+ this[K_STATUS] = completionType;
848
997
  }
849
998
 
850
999
  const broker = this.broker;
851
- this[kActivityQ].delete();
1000
+ this[K_ACTIVITY_Q].delete();
852
1001
 
853
- return broker.publish(
1002
+ broker.publish(
854
1003
  this._exchangeName,
855
1004
  `execution.${completionType}.${this.executionId}`,
856
- cloneContent(this[kExecuteMessage].content, {
1005
+ cloneContent(this[K_EXECUTE_MESSAGE].content, {
857
1006
  output: { ...this.environment.output },
858
1007
  ...content,
859
1008
  state: completionType,
@@ -862,11 +1011,12 @@ ProcessExecution.prototype._complete = function complete(completionType, content
862
1011
  );
863
1012
  };
864
1013
 
1014
+ /** @internal */
865
1015
  ProcessExecution.prototype._terminate = function terminate(message) {
866
- this[kStatus] = 'terminated';
1016
+ this[K_STATUS] = 'terminated';
867
1017
  this._debug('terminating process execution');
868
1018
 
869
- const postponed = this[kElements].postponed;
1019
+ const postponed = this[K_ELEMENTS].postponed;
870
1020
  const running = new Set(postponed);
871
1021
  postponed.clear();
872
1022
 
@@ -881,25 +1031,67 @@ ProcessExecution.prototype._terminate = function terminate(message) {
881
1031
  msg.ack();
882
1032
  }
883
1033
 
884
- this[kActivityQ].purge();
1034
+ this[K_ACTIVITY_Q].purge();
885
1035
  };
886
1036
 
1037
+ /** @internal */
887
1038
  ProcessExecution.prototype._getFlowById = function getFlowById(flowId) {
888
- return this[kElements].flows.find((f) => f.id === flowId);
1039
+ return this[K_ELEMENTS].flows.find((f) => f.id === flowId);
889
1040
  };
890
1041
 
1042
+ /** @internal */
891
1043
  ProcessExecution.prototype._getAssociationById = function getAssociationById(associationId) {
892
- return this[kElements].associations.find((a) => a.id === associationId);
1044
+ return this[K_ELEMENTS].associations.find((a) => a.id === associationId);
893
1045
  };
894
1046
 
1047
+ /** @internal */
895
1048
  ProcessExecution.prototype._getMessageFlowById = function getMessageFlowById(flowId) {
896
- return this[kElements].outboundMessageFlows.find((f) => f.id === flowId);
1049
+ return this[K_ELEMENTS].outboundMessageFlows.find((f) => f.id === flowId);
897
1050
  };
898
1051
 
1052
+ /** @internal */
899
1053
  ProcessExecution.prototype._getChildById = function getChildById(childId) {
900
1054
  return this.getActivityById(childId) || this._getFlowById(childId);
901
1055
  };
902
1056
 
1057
+ /**
1058
+ * Discard the other armed start events once one mutually exclusive entry point wins.
1059
+ * Resolves the start-event flag from the live activity so recovered pre-flag state is handled.
1060
+ * @internal
1061
+ */
1062
+ ProcessExecution.prototype._discardArmedStartEvents = function discardArmedStartEvents(winnerId) {
1063
+ const elements = this[K_ELEMENTS];
1064
+ const startPeers = [];
1065
+ for (const msg of elements.postponed) {
1066
+ const peerId = msg.content.id;
1067
+ if (peerId === winnerId) continue;
1068
+ if (this.getActivityById(peerId)?.isStartEvent) startPeers.push(msg);
1069
+ }
1070
+ if (!startPeers.length) return;
1071
+ elements.startEventCount = 0;
1072
+ for (const msg of startPeers) this._getChildApi(msg).discard();
1073
+ };
1074
+
1075
+ /**
1076
+ * On resume of a state from an older major, discard start events left armed when another entry
1077
+ * point already won before recovery. The winning start event's `activity.end` cannot replay, so
1078
+ * the live discard trigger never fires.
1079
+ * @internal
1080
+ */
1081
+ ProcessExecution.prototype._reconcileStartEvents = function reconcileStartEvents() {
1082
+ const elements = this[K_ELEMENTS];
1083
+ if (elements.startEventCount <= 1) return;
1084
+ if (!(this[K_RECOVERED_VERSION] < STATE_VERSION)) return;
1085
+
1086
+ for (const child of elements.children) {
1087
+ if (child.isStartEvent && child.counters.taken) {
1088
+ this._discardArmedStartEvents();
1089
+ return;
1090
+ }
1091
+ }
1092
+ };
1093
+
1094
+ /** @internal */
903
1095
  ProcessExecution.prototype._getChildApi = function getChildApi(message) {
904
1096
  const content = message.content;
905
1097
 
@@ -919,12 +1111,7 @@ ProcessExecution.prototype._getChildApi = function getChildApi(message) {
919
1111
  }
920
1112
  };
921
1113
 
922
- ProcessExecution.prototype._onShookEnd = function onShookEnd(message) {
923
- const routingKey = message.fields.routingKey;
924
- if (routingKey !== 'activity.shake.end') return;
925
- this[kElements].startSequences[message.content.id] = cloneMessage(message);
926
- };
927
-
1114
+ /** @internal */
928
1115
  ProcessExecution.prototype._debug = function debugMessage(logMessage) {
929
- this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`);
1116
+ this[K_PARENT].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`);
930
1117
  };