@0dep/bpmn-extensions 0.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.
@@ -0,0 +1,40 @@
1
+ import { ServiceError } from '../Errors.js';
2
+ import { resolveValue } from '../feel.js';
3
+
4
+ /**
5
+ * `zeebe:taskDefinition`.
6
+ *
7
+ * A job worker subscribed to the task `type` executes the activity. Here the
8
+ * `type` is mapped to an environment service of the same name: the job worker is a service
9
+ * function `(executionMessage, callback) => void` registered under the job type.
10
+ *
11
+ * The service receives the task headers and resolved io input on the execution message
12
+ * content, and its result (the second callback argument) becomes the job variables that
13
+ * output mapping operates on.
14
+ *
15
+ * Bind the task type to use as the activity `Service`:
16
+ * activity.behaviour.Service = JobService.bind(JobService, taskType);
17
+ */
18
+ export function JobService(taskType, activity) {
19
+ if (!(this instanceof JobService)) return new JobService(taskType, activity);
20
+ this.type = `${activity.type}:taskDefinition`;
21
+ this.taskType = taskType;
22
+ this.activity = activity;
23
+ }
24
+
25
+ JobService.prototype.execute = function execute(executionMessage, callback) {
26
+ const activity = this.activity;
27
+ const environment = activity.environment;
28
+
29
+ let jobType;
30
+ try {
31
+ jobType = resolveValue(this.taskType, environment.variables);
32
+ } catch (err) {
33
+ return callback(err);
34
+ }
35
+
36
+ const serviceFn = environment.services[jobType];
37
+ if (typeof serviceFn !== 'function') return callback(new ServiceError(jobType));
38
+
39
+ return serviceFn.call(activity, executionMessage, (err, result) => callback(err, result));
40
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `zeebe:taskHeaders`.
3
+ *
4
+ * Static key/value metadata passed to the job worker. Resolved to a plain object and made
5
+ * available on the element content as `headers`.
6
+ */
7
+ export class TaskHeaders {
8
+ constructor(taskHeaders) {
9
+ this.values = taskHeaders.values || [];
10
+ }
11
+ resolve() {
12
+ const result = {};
13
+ for (const { key, value } of this.values) {
14
+ if (key === undefined) continue;
15
+ result[key] = value;
16
+ }
17
+ return result;
18
+ }
19
+ }
@@ -0,0 +1,67 @@
1
+ import { resolveValue } from '../feel.js';
2
+
3
+ /**
4
+ * Format an activity on enter from its behaviour and extensions: documentation and,
5
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
6
+ */
7
+ export class FormatActivity {
8
+ constructor(activity, assignmentDefinition) {
9
+ this.activity = activity;
10
+ this.assignmentDefinition = assignmentDefinition;
11
+ }
12
+ resolve(elementApi) {
13
+ const scope = elementApi.environment.variables;
14
+ const result = {};
15
+
16
+ const documentation = this.activity.behaviour.documentation;
17
+ if (documentation && !elementApi.content.description) {
18
+ const text = documentation[0]?.text;
19
+ if (text) result.description = resolveValue(text, scope);
20
+ }
21
+
22
+ const assignment = this.assignmentDefinition;
23
+ if (assignment) {
24
+ const { assignee, candidateUsers, candidateGroups } = assignment;
25
+ if (assignee) result.assignee = resolveValue(assignee, scope);
26
+ const users = resolveList(candidateUsers, scope);
27
+ if (users) result.candidateUsers = users;
28
+ const groups = resolveList(candidateGroups, scope);
29
+ if (groups) result.candidateGroups = groups;
30
+ }
31
+
32
+ return result;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Format a process on enter: documentation.
38
+ */
39
+ export class FormatProcess {
40
+ constructor(bp) {
41
+ this.process = bp;
42
+ }
43
+ resolve(elementApi) {
44
+ const result = {};
45
+ const documentation = this.process.behaviour.documentation;
46
+ if (documentation && !elementApi.content.description) {
47
+ const text = documentation[0]?.text;
48
+ if (text) result.description = resolveValue(text, elementApi.environment.variables);
49
+ }
50
+ return result;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Resolve a candidate users/groups value to a string array. A FEEL expression may yield an
56
+ * array directly, otherwise a comma-separated string is split.
57
+ */
58
+ function resolveList(value, scope) {
59
+ if (!value) return undefined;
60
+ const resolved = resolveValue(value, scope);
61
+ if (Array.isArray(resolved)) return resolved.filter((v) => v !== null && v !== undefined);
62
+ if (typeof resolved !== 'string') return undefined;
63
+ return resolved
64
+ .split(',')
65
+ .map((v) => v.trim())
66
+ .filter(Boolean);
67
+ }
package/src/feel.js ADDED
@@ -0,0 +1,60 @@
1
+ import { evaluate, unaryTest } from 'feelin';
2
+
3
+ /**
4
+ * A value is a FEEL expression when it is a string prefixed with `=`.
5
+ * Anything else is a static literal.
6
+ */
7
+ const FEEL_PREFIX = /^\s*=/;
8
+
9
+ /**
10
+ * Is the value a FEEL expression, i.e. a string starting with `=`?
11
+ * @param {unknown} value
12
+ * @returns {boolean}
13
+ */
14
+ export function isFeelExpression(value) {
15
+ return typeof value === 'string' && FEEL_PREFIX.test(value);
16
+ }
17
+
18
+ /**
19
+ * Strip the leading `=` from a FEEL expression.
20
+ * @param {string} expression
21
+ * @returns {string}
22
+ */
23
+ export function stripFeel(expression) {
24
+ return expression.replace(FEEL_PREFIX, '');
25
+ }
26
+
27
+ /**
28
+ * Evaluate a FEEL expression against a context (the variables in scope).
29
+ * @param {string} expression FEEL expression, with or without the leading `=`
30
+ * @param {Record<string, any>} [context] Variables in scope
31
+ * @returns {any}
32
+ */
33
+ export function evaluateFeel(expression, context) {
34
+ const { value } = evaluate(stripFeel(expression), context || {});
35
+ return value;
36
+ }
37
+
38
+ /**
39
+ * Evaluate a FEEL unary test, e.g. `> 100` or `1, 2, 3`, against an input value.
40
+ * @param {string} expression FEEL unary test
41
+ * @param {any} input The value being tested, available as `?` in the test
42
+ * @param {Record<string, any>} [context] Additional variables in scope
43
+ * @returns {boolean}
44
+ */
45
+ export function evaluateFeelUnaryTest(expression, input, context) {
46
+ const { value } = unaryTest(stripFeel(expression), { ...(context || {}), '?': input });
47
+ return value;
48
+ }
49
+
50
+ /**
51
+ * Resolve a value: evaluate it as FEEL when it starts with `=`, otherwise
52
+ * return the static literal untouched.
53
+ * @param {any} value
54
+ * @param {Record<string, any>} [context] Variables in scope for FEEL evaluation
55
+ * @returns {any}
56
+ */
57
+ export function resolveValue(value, context) {
58
+ if (isFeelExpression(value)) return evaluateFeel(value, context);
59
+ return value;
60
+ }
@@ -0,0 +1,70 @@
1
+ import { FormatActivity, FormatProcess } from './extensions/formatters.js';
2
+ import { IoMapping } from './extensions/IoMapping.js';
3
+ import { TaskHeaders } from './extensions/TaskHeaders.js';
4
+ import { Properties } from './extensions/Properties.js';
5
+ import { ExecutionListeners } from './extensions/ExecutionListeners.js';
6
+ import { Form } from './extensions/Form.js';
7
+ import { LoopCharacteristics } from './extensions/LoopCharacteristics.js';
8
+ import { JobService } from './extensions/TaskDefinition.js';
9
+
10
+ /**
11
+ * Inspect an element's extension elements and assemble the extension handlers it needs.
12
+ * @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
13
+ * @returns {{
14
+ * format: FormatActivity | FormatProcess,
15
+ * io?: IoMapping,
16
+ * headers?: TaskHeaders,
17
+ * properties?: Properties,
18
+ * listeners?: ExecutionListeners,
19
+ * form?: Form,
20
+ * loop?: LoopCharacteristics,
21
+ * Service?: Function,
22
+ * }}
23
+ */
24
+ export function getExtensions(element) {
25
+ const result = {};
26
+ const isProcess = element.type === 'bpmn:Process';
27
+
28
+ let assignmentDefinition;
29
+ const values = element.behaviour.extensionElements?.values;
30
+ if (values) {
31
+ for (const ext of values) {
32
+ switch (ext.$type) {
33
+ case 'zeebe:IoMapping':
34
+ result.io = new IoMapping(element, ext);
35
+ break;
36
+ case 'zeebe:TaskHeaders':
37
+ if (ext.values?.length) result.headers = new TaskHeaders(ext);
38
+ break;
39
+ case 'zeebe:Properties':
40
+ if (ext.properties?.length) result.properties = new Properties(ext);
41
+ break;
42
+ case 'zeebe:AssignmentDefinition':
43
+ assignmentDefinition = ext;
44
+ break;
45
+ case 'zeebe:ExecutionListeners':
46
+ if (ext.listeners?.length) result.listeners = new ExecutionListeners(element, ext);
47
+ break;
48
+ case 'zeebe:TaskDefinition':
49
+ result.Service = JobService.bind(JobService, ext.type);
50
+ break;
51
+ case 'zeebe:Script':
52
+ result.script = ext;
53
+ break;
54
+ case 'zeebe:FormDefinition':
55
+ result.form = new Form(ext);
56
+ break;
57
+ }
58
+ }
59
+ }
60
+
61
+ // Output side of a multi-instance `zeebe:loopCharacteristics` (the input side is lifted by extendFn).
62
+ const loopExtension = element.behaviour.loopCharacteristics?.behaviour?.extensionElements?.values?.find(
63
+ (v) => v.$type === 'zeebe:LoopCharacteristics'
64
+ );
65
+ if (loopExtension?.outputCollection) result.loop = new LoopCharacteristics(loopExtension);
66
+
67
+ result.format = isProcess ? new FormatProcess(element) : new FormatActivity(element, assignmentDefinition);
68
+
69
+ return result;
70
+ }
package/src/index.js ADDED
@@ -0,0 +1,64 @@
1
+ import { ElementExtensions } from './ElementExtensions.js';
2
+ import { ProcessExtensions } from './ProcessExtensions.js';
3
+ import { SubProcessExtensions } from './SubProcessExtensions.js';
4
+
5
+ export { ElementExtensions, ProcessExtensions, SubProcessExtensions };
6
+ export { FeelExpressions } from './Expressions.js';
7
+ export { FeelScripts } from './extensions/FeelScripts.js';
8
+ export { isFeelExpression, stripFeel, evaluateFeel, evaluateFeelUnaryTest, resolveValue } from './feel.js';
9
+ export { JobService } from './extensions/TaskDefinition.js';
10
+ export { ServiceError, FormatError } from './Errors.js';
11
+
12
+ /**
13
+ * A flow extension activated by bpmn-elements around an element's run.
14
+ * @typedef {object} FlowExtension
15
+ * @property {(message: any) => void} activate
16
+ * @property {(message?: any) => void} deactivate
17
+ */
18
+
19
+ /**
20
+ * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
21
+ * @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
22
+ * @param {import('bpmn-elements').ContextInstance} context
23
+ * @returns {FlowExtension}
24
+ */
25
+ export function extensions(element, context) {
26
+ switch (element.type) {
27
+ case 'bpmn:Process':
28
+ return new ProcessExtensions(element, context);
29
+ case 'bpmn:SubProcess':
30
+ case 'bpmn:AdHocSubProcess':
31
+ case 'bpmn:Transaction':
32
+ return new SubProcessExtensions(element, context);
33
+ default:
34
+ return new ElementExtensions(element, context);
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Behaviour extend function for moddle-context-serializer.
40
+ *
41
+ * Lifts extension data onto the places bpmn-elements expects to find it on the element
42
+ * behaviour: the call activity's called process id (`zeebe:calledElement`) and the multi-instance
43
+ * input collection/element (`zeebe:loopCharacteristics`).
44
+ * @param {any} behaviour
45
+ */
46
+ export function extendFn(behaviour) {
47
+ const values = behaviour.extensionElements?.values;
48
+ if (Array.isArray(values)) {
49
+ for (const ext of values) {
50
+ if (ext.$type === 'zeebe:CalledElement' && ext.processId) {
51
+ behaviour.calledElement = ext.processId;
52
+ }
53
+ }
54
+ }
55
+
56
+ // Map zeebe:loopCharacteristics (nested in the multi-instance loop) onto the bpmn-elements
57
+ // multi-instance behaviour: `inputCollection` -> `collection`, `inputElement` -> `elementVariable`.
58
+ const loop = behaviour.loopCharacteristics?.behaviour;
59
+ const loopExtension = loop?.extensionElements?.values?.find((v) => v.$type === 'zeebe:LoopCharacteristics');
60
+ if (loopExtension) {
61
+ if (loopExtension.inputCollection) loop.collection = loopExtension.inputCollection;
62
+ if (loopExtension.inputElement) loop.elementVariable = loopExtension.inputElement;
63
+ }
64
+ }
@@ -0,0 +1,326 @@
1
+ declare module '@0dep/bpmn-extensions' {
2
+ /**
3
+ * A flow extension activated by bpmn-elements around an element's run.
4
+ * */
5
+ /**
6
+ * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
7
+ * */
8
+ export function extensions(element: import("bpmn-elements").Activity | import("bpmn-elements").Process, context: import("bpmn-elements").ContextInstance): FlowExtension;
9
+ /**
10
+ * Behaviour extend function for moddle-context-serializer.
11
+ *
12
+ * Lifts extension data onto the places bpmn-elements expects to find it on the element
13
+ * behaviour: the call activity's called process id (`zeebe:calledElement`) and the multi-instance
14
+ * input collection/element (`zeebe:loopCharacteristics`).
15
+ * */
16
+ export function extendFn(behaviour: any): void;
17
+ /**
18
+ * A flow extension activated by bpmn-elements around an element's run.
19
+ */
20
+ export type FlowExtension = {
21
+ activate: (message: any) => void;
22
+ deactivate: (message?: any) => void;
23
+ };
24
+ /**
25
+ * FEEL-aware expressions implementation for bpmn-elements.
26
+ *
27
+ * Plug it into the engine via the environment `expressions` option so that the whole
28
+ * definition resolves FEEL expressions (`= ...`) instead of the default
29
+ * `${...}` template expressions.
30
+ *
31
+ * */
32
+ export function FeelExpressions(): import("bpmn-elements").IExpressions;
33
+ /**
34
+ * A bpmn-elements `scripts` implementation for script tasks.
35
+ *
36
+ * A script task carries a `zeebe:script` extension with a FEEL `expression` (and a
37
+ * `resultVariable`). There is no embedded script body and no `scriptFormat` attribute, so this
38
+ * registry ignores the script format and reads the expression straight off the element.
39
+ *
40
+ * Install it on the environment via the `scripts` option, alongside `FeelExpressions()`.
41
+ *
42
+ * */
43
+ export function FeelScripts(): import("bpmn-elements").IScripts;
44
+ /**
45
+ * `zeebe:taskDefinition`.
46
+ *
47
+ * A job worker subscribed to the task `type` executes the activity. Here the
48
+ * `type` is mapped to an environment service of the same name: the job worker is a service
49
+ * function `(executionMessage, callback) => void` registered under the job type.
50
+ *
51
+ * The service receives the task headers and resolved io input on the execution message
52
+ * content, and its result (the second callback argument) becomes the job variables that
53
+ * output mapping operates on.
54
+ *
55
+ * Bind the task type to use as the activity `Service`:
56
+ * activity.behaviour.Service = JobService.bind(JobService, taskType);
57
+ */
58
+ export function JobService(taskType: any, activity: any): JobService;
59
+ export class JobService {
60
+ /**
61
+ * `zeebe:taskDefinition`.
62
+ *
63
+ * A job worker subscribed to the task `type` executes the activity. Here the
64
+ * `type` is mapped to an environment service of the same name: the job worker is a service
65
+ * function `(executionMessage, callback) => void` registered under the job type.
66
+ *
67
+ * The service receives the task headers and resolved io input on the execution message
68
+ * content, and its result (the second callback argument) becomes the job variables that
69
+ * output mapping operates on.
70
+ *
71
+ * Bind the task type to use as the activity `Service`:
72
+ * activity.behaviour.Service = JobService.bind(JobService, taskType);
73
+ */
74
+ constructor(taskType: any, activity: any);
75
+ type: string | undefined;
76
+ taskType: any;
77
+ activity: any;
78
+ execute(executionMessage: any, callback: any): any;
79
+ }
80
+ /**
81
+ * Activity-level extensions.
82
+ *
83
+ * Formatting and io/listener side effects are injected through the activity's `format-run-q`
84
+ * queue so the activity waits for them (including async execution listeners) before
85
+ * proceeding — the same mechanism bpmn-elements uses for extension formatting.
86
+ */
87
+ export class ElementExtensions {
88
+ constructor(activity: any);
89
+ activity: any;
90
+ formatQ: any;
91
+ extensions: {
92
+ format: FormatActivity | FormatProcess;
93
+ io?: IoMapping;
94
+ headers?: TaskHeaders;
95
+ properties?: Properties;
96
+ listeners?: ExecutionListeners;
97
+ form?: Form;
98
+ loop?: LoopCharacteristics;
99
+ Service?: Function;
100
+ };
101
+ activate(message: any): void;
102
+ deactivate(): void;
103
+ /** @internal Shared with SubProcessExtensions. */
104
+ _onEnter(elementApi: any): Promise<void>;
105
+ /** @internal Shared with SubProcessExtensions. */
106
+ _onExecuted(elementApi: any): Promise<void>;
107
+ /** @internal Shared with SubProcessExtensions. */
108
+ _onListener(eventType: any, elementApi: any): Promise<void>;
109
+ #private;
110
+ }
111
+ /**
112
+ * Process-level extensions. Formats the process on enter (documentation) and assigns
113
+ * the result to the process variables.
114
+ */
115
+ export class ProcessExtensions {
116
+ constructor(bp: any);
117
+ process: any;
118
+ extensions: {
119
+ format: FormatActivity | FormatProcess;
120
+ io?: IoMapping;
121
+ headers?: TaskHeaders;
122
+ properties?: Properties;
123
+ listeners?: ExecutionListeners;
124
+ form?: Form;
125
+ loop?: LoopCharacteristics;
126
+ Service?: Function;
127
+ };
128
+ activate(): void;
129
+ deactivate(): void;
130
+ #private;
131
+ }
132
+ /**
133
+ * Sub-process extensions.
134
+ *
135
+ * A sub-process shares its broker with the child activities it contains, so their
136
+ * `activity.*` events bubble through it. Subscribing with `activity.on(...)` (as a leaf
137
+ * element does) would therefore fire the extension handlers for every child and spam the
138
+ * sub-process format queue, stalling it. Instead, subscribe on the broker and filter to the
139
+ * sub-process's own id.
140
+ */
141
+ export class SubProcessExtensions extends ElementExtensions {
142
+ #private;
143
+ }
144
+ /**
145
+ * Is the value a FEEL expression, i.e. a string starting with `=`?
146
+ * */
147
+ export function isFeelExpression(value: unknown): boolean;
148
+ /**
149
+ * Strip the leading `=` from a FEEL expression.
150
+ * */
151
+ export function stripFeel(expression: string): string;
152
+ /**
153
+ * Evaluate a FEEL expression against a context (the variables in scope).
154
+ * @param expression FEEL expression, with or without the leading `=`
155
+ * @param context Variables in scope
156
+ * */
157
+ export function evaluateFeel(expression: string, context?: Record<string, any>): any;
158
+ /**
159
+ * Evaluate a FEEL unary test, e.g. `> 100` or `1, 2, 3`, against an input value.
160
+ * @param expression FEEL unary test
161
+ * @param input The value being tested, available as `?` in the test
162
+ * @param context Additional variables in scope
163
+ * */
164
+ export function evaluateFeelUnaryTest(expression: string, input: any, context?: Record<string, any>): boolean;
165
+ /**
166
+ * Resolve a value: evaluate it as FEEL when it starts with `=`, otherwise
167
+ * return the static literal untouched.
168
+ * @param context Variables in scope for FEEL evaluation
169
+ * */
170
+ export function resolveValue(value: any, context?: Record<string, any>): any;
171
+ export class ServiceError extends Error {
172
+ constructor(jobType: any);
173
+ code: string;
174
+ output: {
175
+ statusCode: number;
176
+ };
177
+ }
178
+ export class FormatError extends Error {
179
+ constructor(elementId: any, err: any);
180
+ code: string;
181
+ output: {
182
+ statusCode: number;
183
+ };
184
+ }
185
+ /**
186
+ * Format an activity on enter from its behaviour and extensions: documentation and,
187
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
188
+ */
189
+ class FormatActivity {
190
+ constructor(activity: any, assignmentDefinition: any);
191
+ activity: any;
192
+ assignmentDefinition: any;
193
+ resolve(elementApi: any): {
194
+ description: any;
195
+ assignee: any;
196
+ candidateUsers: any[];
197
+ candidateGroups: any[];
198
+ };
199
+ }
200
+ /**
201
+ * Format a process on enter: documentation.
202
+ */
203
+ class FormatProcess {
204
+ constructor(bp: any);
205
+ process: any;
206
+ resolve(elementApi: any): {
207
+ description: any;
208
+ };
209
+ }
210
+ /**
211
+ * `zeebe:ioMapping`.
212
+ *
213
+ * Input parameters are evaluated in the parent (process) scope when the element is entered,
214
+ * producing the local variables the job runs with. Output parameters are evaluated in the
215
+ * job-result scope when the element completes, merging the result back into the process
216
+ * variables.
217
+ *
218
+ * Each parameter has a `source` (a FEEL expression or static value) and a `target`
219
+ * (a, possibly dotted, variable name).
220
+ */
221
+ class IoMapping {
222
+ constructor(activity: any, ioMapping: any);
223
+ activity: any;
224
+ inputParameters: any;
225
+ outputParameters: any;
226
+ get hasInput(): boolean;
227
+ get hasOutput(): boolean;
228
+ /**
229
+ * Resolve input parameters against the current process variables.
230
+ * */
231
+ getInput(elementApi: import("bpmn-elements").IApi<any>): {};
232
+ /**
233
+ * Resolve output parameters against the job result overlaid on the process variables.
234
+ * @param jobResult Variables produced by the job
235
+ */
236
+ getOutput(elementApi: import("bpmn-elements").IApi<any>, jobResult?: Record<string, any>): {};
237
+ }
238
+ /**
239
+ * `zeebe:taskHeaders`.
240
+ *
241
+ * Static key/value metadata passed to the job worker. Resolved to a plain object and made
242
+ * available on the element content as `headers`.
243
+ */
244
+ class TaskHeaders {
245
+ constructor(taskHeaders: any);
246
+ values: any;
247
+ resolve(): {};
248
+ }
249
+ /**
250
+ * `zeebe:properties`.
251
+ *
252
+ * Named properties whose values may be FEEL expressions. Resolved to a plain object and made
253
+ * available on the element content as `properties`.
254
+ */
255
+ class Properties {
256
+ constructor(properties: any);
257
+ properties: any;
258
+ resolve(elementApi: any): {};
259
+ }
260
+ /**
261
+ * `zeebe:executionListeners`.
262
+ *
263
+ * Each listener invokes a job worker (an environment service named by the listener `type`)
264
+ * either before the element runs (`eventType: "start"`) or after it completes
265
+ * (`eventType: "end"`). A listener is called as `(elementApi, { retries, headers }, callback)` and
266
+ * may either call the callback or return a promise — either way the element blocks until it
267
+ * settles. `retries` and `headers` are only present when the listener declares them (no defaults
268
+ * are invented).
269
+ */
270
+ class ExecutionListeners {
271
+ constructor(activity: any, executionListeners: any);
272
+ activity: any;
273
+ listeners: any;
274
+ get onStart(): any;
275
+ get onEnd(): any;
276
+ /**
277
+ * Execute all listeners registered for an event type, in order.
278
+ * */
279
+ execute(eventType: "start" | "end", elementApi: import("bpmn-elements").IApi<any>): Promise<void>;
280
+ }
281
+ /**
282
+ * `zeebe:formDefinition`.
283
+ *
284
+ * User tasks (and form-bearing start events) reference their form here: a linked
285
+ * form (`formId`), a deprecated form key (`formKey`), or an external form
286
+ * (`externalReference`, which may be a FEEL expression). Resolved to a plain object and made
287
+ * available on the element content as `form` so a task list can render it.
288
+ */
289
+ class Form {
290
+ constructor(formDefinition: any);
291
+ formDefinition: any;
292
+ resolve(elementApi: any): {
293
+ versionTag?: any;
294
+ bindingType?: any;
295
+ externalReference?: any;
296
+ formKey?: any;
297
+ formId?: any;
298
+ };
299
+ }
300
+ /**
301
+ * Output side of `zeebe:loopCharacteristics`.
302
+ *
303
+ * A multi-instance is aggregated into an `outputCollection` array: for each instance the
304
+ * `outputElement` FEEL expression is evaluated in that instance's result scope and collected, in
305
+ * input order, into the named collection variable.
306
+ *
307
+ * bpmn-elements collects instance outputs into an index-keyed object on the activity content
308
+ * (`{ 0: <out>, 1: <out>, ... }`, where a call activity instance wraps its result as
309
+ * `{ executionId, output }`). This reduces that to the output-collection array.
310
+ */
311
+ class LoopCharacteristics {
312
+ constructor(loopCharacteristics: any);
313
+ outputCollection: any;
314
+ outputElement: any;
315
+ get hasOutputCollection(): boolean;
316
+ /**
317
+ * @param indexedOutput bpmn-elements index-keyed instance outputs
318
+ * @param baseScope process variables in scope for `outputElement`
319
+ * */
320
+ aggregate(indexedOutput: Record<string, any> | undefined, baseScope: Record<string, any>): any[];
321
+ }
322
+
323
+ export {};
324
+ }
325
+
326
+ //# sourceMappingURL=index.d.ts.map