@aranzatech/diagrams-bpmn 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,14 +1,112 @@
1
- export { B as BPMN_ELEMENT_CATALOG, a as BPMN_RESIZABLE_ELEMENT_TYPES, g as getBpmnElementSize, b as getElementMeta, i as isBpmnElementResizable } from './catalog-CjGdTFxc.cjs';
1
+ export { B as BPMN_ELEMENT_CATALOG, a as BPMN_RESIZABLE_ELEMENT_TYPES, g as getBpmnElementSize, b as getElementMeta, i as isBpmnElementResizable } from './catalog-Ch3YT0-0.cjs';
2
2
  export { acceptsBoundaryEvents, getHandlePolicy, getOrientation, isChoreographyType, isContainerType, isConversationType, isDataType, isEventType, isGatewayType, isTaskType, supportsCollapse, supportsMarkers } from './elements/index.cjs';
3
- export { B as BpmnCategory, a as BpmnDefinitionsSet, b as BpmnEdgeData, c as BpmnEdgeType, d as BpmnElementMeta, e as BpmnElementSize, f as BpmnElementType, g as BpmnErrorDefinition, h as BpmnEscalationDefinition, i as BpmnEventDefinition, j as BpmnEventSemantics, k as BpmnHandlePolicy, l as BpmnMessageDefinition, m as BpmnNodeData, n as BpmnOrientation, o as BpmnProcessVariable, p as BpmnSignalDefinition, q as BpmnTimerDefinition, r as BpmnTimerKind, E as EventTrigger, S as SubProcessVariant, T as TaskMarker } from './types-wFn_tJLY.cjs';
3
+ export { B as BpmnCategory, a as BpmnDefinitionsSet, b as BpmnEdgeData, c as BpmnEdgeType, d as BpmnElementMeta, e as BpmnElementSize, f as BpmnElementType, g as BpmnErrorDefinition, h as BpmnEscalationDefinition, i as BpmnEventDefinition, j as BpmnEventSemantics, k as BpmnHandlePolicy, l as BpmnMessageDefinition, m as BpmnNodeData, n as BpmnOrientation, o as BpmnProcessVariable, p as BpmnSignalDefinition, q as BpmnTimerDefinition, r as BpmnTimerKind, E as EventTrigger, S as SubProcessVariant, T as TaskMarker } from './types-BTuiBv7p.cjs';
4
4
  export { AnnotationNode, BPMN_NODE_TYPES, BoundaryEventNode, CallChoreographyNode, CallConversationNode, ChoreographyTaskNode, ConversationNode, DataInputNode, DataObjectNode, DataObjectReferenceNode, DataOutputNode, DataStoreNode, DataStoreReferenceNode, EndEventNode, GatewayNode, GroupNode, IntermediateCatchEventNode, IntermediateThrowEventNode, LaneNode, PoolNode, StartEventNode, SubChoreographyNode, SubConversationNode, SubProcessNode, TaskNode } from './nodes/index.cjs';
5
5
  export { AssociationEdge, BPMN_EDGE_TYPES, ConversationLinkEdge, DataAssociationEdge, MessageFlowEdge, SequenceFlowEdge } from './edges/index.cjs';
6
6
  export { parseBpmnXml, serializeBpmnXml } from './xml/index.cjs';
7
- export { B as BpmnExportOptions, a as BpmnImportResult, b as BpmnProcessModel, c as BpmnRFEdge, d as BpmnRFNode } from './types-BjVERSZn.cjs';
8
- export { SimDiagram, SimEdge, SimLogEntry, SimLogType, SimNode, SimStatus, SimToken, SimVariables, SimulationState, createSimulation, fire, getFireable, isCompleted, setVariable, tick } from './simulation/index.cjs';
7
+ export { B as BpmnExportOptions, a as BpmnImportResult, b as BpmnProcessModel, c as BpmnRFEdge, d as BpmnRFNode } from './types-C7tONwP5.cjs';
8
+ import { SimDiagram } from './simulation/index.cjs';
9
+ export { SimEdge, SimLogEntry, SimLogType, SimNode, SimStatus, SimToken, SimVariables, SimulationState, createSimulation, fire, getFireable, isCompleted, setVariable, tick } from './simulation/index.cjs';
9
10
  export { BPMN_EDGE_CONNECTION_RULES, BPMN_MODELING_RULES, BPMN_POOL_LANE_LAYOUT, BPMN_ROUTABLE_EDGE_TYPES, BPMN_SELECTION_STYLE, BpmnClipboardState, BpmnConnectionRule, BpmnDiagramDocument, BpmnDiagramSnapshot, BpmnDiagramState, BpmnEventBus, ConnectBpmnOptions, CreateBpmnNodeOptions, FindBpmnContainerAtOptions, GroupAsBpmnSubProcessOptions, MoveBpmnLaneOptions, PasteBpmnOptions, ReorderBpmnLaneOptions, ReparentBpmnNodeAtPositionOptions, ReparentBpmnNodeOptions, ReplaceBpmnNodeOptions, ResizeBpmnNodeByHandleOptions, ResizeBpmnNodeOptions, RouteBpmnEdgeOptions, attachBoundaryEventCommand, bpmnConnectionValidators, canContainBpmnElement, computeBpmnSmartGuides, connectBpmnCommand, copyBpmnElements, createBpmnDiagramDocument, createBpmnEventBus, createBpmnLayoutCache, createBpmnNode, createBpmnNodeCommand, deleteBpmnElementsCommand, deserializeBpmnDiagram, deserializeBpmnDiagramSnapshot, findBpmnContainerAt, getBpmnDragHandleSelector, getBpmnEdgeLabelLayout, getBpmnLaneIndexAtPosition, getBpmnNodeAbsolutePosition, getBpmnNodeCenter, getBpmnNodeSize, getBpmnNodeZIndex, getBpmnPoolLanes, getBpmnTabOrder, groupAsBpmnSubProcessCommand, inferBpmnEdgeType, isBpmnDroppableInContainer, isBpmnEdgeRoutingEditable, isBpmnProcessNode, layoutBpmnPoolLaneNodes, layoutBpmnPoolLanes, moveBpmnLaneCommand, parseBpmnDiagramDocument, pasteBpmnElementsCommand, persistBpmnHistory, reorderBpmnLane, reorderBpmnLaneAfterDrop, reorderBpmnLaneCommand, reparentBpmnNodeAtPosition, reparentBpmnNodeCommand, replaceBpmnNodeCommand, resizeBpmnNodeByHandleCommand, resizeBpmnNodeCommand, restoreBpmnHistory, routeBpmnEdgeCommand, runBpmnCommand, runBpmnCommands, selectBpmnElementsCommand, serializeBpmnDiagram, toBpmnRelativePosition, validateBpmnConnectionForEdgeType, withBpmnLayoutCache, withBpmnNodeZIndexes } from './modeling/index.cjs';
10
11
  export { BpmnValidationIssue, BpmnValidationOptions, BpmnValidationResult, BpmnValidationSeverity } from './validation/index.cjs';
11
12
  import 'react/jsx-runtime';
12
13
  import '@xyflow/react';
13
14
  import '@aranzatech/diagrams-core';
14
15
  import '@aranzatech/diagrams-core/serialization';
16
+
17
+ /**
18
+ * Branch weights for one gateway.
19
+ * Maps each outgoing sequence-flow edge ID to a non-negative weight.
20
+ * Weights are normalised internally so they need not sum to any specific value.
21
+ * An edge absent from the map inherits weight 1.
22
+ */
23
+ type GatewayWeights = Record<string, number>;
24
+ interface BatchSimConfig {
25
+ /**
26
+ * Number of process instances to simulate.
27
+ * @default 100
28
+ */
29
+ instances?: number;
30
+ /**
31
+ * Gateway branch weights. Keys are gateway node IDs; values map
32
+ * each outgoing edge ID to its relative weight.
33
+ * Applies to ExclusiveGateway and InclusiveGateway nodes.
34
+ * Gateways absent from this map fall back to condition evaluation
35
+ * or first-edge behaviour.
36
+ */
37
+ gatewayWeights?: Record<string, GatewayWeights>;
38
+ /**
39
+ * Simulated activity duration per node in milliseconds.
40
+ * Used to compute the `totalDurationMs` load indicator:
41
+ * totalDurationMs = visits × nodeDurations[nodeId]
42
+ * Nodes absent from this map contribute 0 ms.
43
+ */
44
+ nodeDurations?: Record<string, number>;
45
+ /**
46
+ * Safety limit: maximum tick iterations per instance.
47
+ * Prevents infinite-loop diagrams from blocking indefinitely.
48
+ * @default 500
49
+ */
50
+ maxSteps?: number;
51
+ }
52
+ interface NodeSimStats {
53
+ /**
54
+ * Number of instances in which at least one token passed through
55
+ * this node. Value in [0, config.instances].
56
+ */
57
+ visits: number;
58
+ /**
59
+ * visits × nodeDurations[nodeId].
60
+ * Higher values indicate heavier aggregate load on this activity.
61
+ */
62
+ totalDurationMs: number;
63
+ /**
64
+ * Highest number of concurrent tokens at this node observed within
65
+ * any single instance. Values > 1 occur inside parallel branches.
66
+ */
67
+ peakConcurrency: number;
68
+ }
69
+ interface BatchSimResult {
70
+ /** Per-node aggregated statistics, keyed by node ID. */
71
+ nodeStats: Record<string, NodeSimStats>;
72
+ /** Instances that reached the EndEvent(s) successfully. */
73
+ completed: number;
74
+ /** Instances that stalled with tokens still present (deadlock). */
75
+ deadlocked: number;
76
+ /** Total instances attempted — equals `config.instances`. */
77
+ total: number;
78
+ /**
79
+ * Mean number of simulation steps across completed instances.
80
+ * Proxy for relative cycle time (higher = longer path).
81
+ * 0 when no instance completed.
82
+ */
83
+ avgSteps: number;
84
+ }
85
+ /**
86
+ * Run `config.instances` process instances through the diagram and
87
+ * aggregate per-node statistics for bottleneck analysis.
88
+ *
89
+ * Tasks are completed instantly (no wait time); gateway choices follow
90
+ * either the weights in `config.gatewayWeights` or the existing
91
+ * condition/default/first-edge logic when no weights are specified.
92
+ *
93
+ * @param diagram - The BPMN graph to simulate.
94
+ * @param config - Simulation parameters.
95
+ * @returns Aggregated {@link BatchSimResult}.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const result = runBatchSimulation(diagram, {
100
+ * instances: 200,
101
+ * gatewayWeights: {
102
+ * "gw_approve": { "edge_approved": 70, "edge_rejected": 30 },
103
+ * },
104
+ * nodeDurations: { "task_review": 3600_000 }, // 1 hour
105
+ * });
106
+ * const topBottleneck = Object.entries(result.nodeStats)
107
+ * .sort((a, b) => b[1].totalDurationMs - a[1].totalDurationMs)[0];
108
+ * ```
109
+ */
110
+ declare function runBatchSimulation(diagram: SimDiagram, config?: BatchSimConfig): BatchSimResult;
111
+
112
+ export { type BatchSimConfig, type BatchSimResult, type GatewayWeights, type NodeSimStats, SimDiagram, runBatchSimulation };
package/dist/index.d.ts CHANGED
@@ -1,14 +1,112 @@
1
- export { B as BPMN_ELEMENT_CATALOG, a as BPMN_RESIZABLE_ELEMENT_TYPES, g as getBpmnElementSize, b as getElementMeta, i as isBpmnElementResizable } from './catalog-DW0Hknp2.js';
1
+ export { B as BPMN_ELEMENT_CATALOG, a as BPMN_RESIZABLE_ELEMENT_TYPES, g as getBpmnElementSize, b as getElementMeta, i as isBpmnElementResizable } from './catalog-BOwJOaXV.js';
2
2
  export { acceptsBoundaryEvents, getHandlePolicy, getOrientation, isChoreographyType, isContainerType, isConversationType, isDataType, isEventType, isGatewayType, isTaskType, supportsCollapse, supportsMarkers } from './elements/index.js';
3
- export { B as BpmnCategory, a as BpmnDefinitionsSet, b as BpmnEdgeData, c as BpmnEdgeType, d as BpmnElementMeta, e as BpmnElementSize, f as BpmnElementType, g as BpmnErrorDefinition, h as BpmnEscalationDefinition, i as BpmnEventDefinition, j as BpmnEventSemantics, k as BpmnHandlePolicy, l as BpmnMessageDefinition, m as BpmnNodeData, n as BpmnOrientation, o as BpmnProcessVariable, p as BpmnSignalDefinition, q as BpmnTimerDefinition, r as BpmnTimerKind, E as EventTrigger, S as SubProcessVariant, T as TaskMarker } from './types-wFn_tJLY.js';
3
+ export { B as BpmnCategory, a as BpmnDefinitionsSet, b as BpmnEdgeData, c as BpmnEdgeType, d as BpmnElementMeta, e as BpmnElementSize, f as BpmnElementType, g as BpmnErrorDefinition, h as BpmnEscalationDefinition, i as BpmnEventDefinition, j as BpmnEventSemantics, k as BpmnHandlePolicy, l as BpmnMessageDefinition, m as BpmnNodeData, n as BpmnOrientation, o as BpmnProcessVariable, p as BpmnSignalDefinition, q as BpmnTimerDefinition, r as BpmnTimerKind, E as EventTrigger, S as SubProcessVariant, T as TaskMarker } from './types-BTuiBv7p.js';
4
4
  export { AnnotationNode, BPMN_NODE_TYPES, BoundaryEventNode, CallChoreographyNode, CallConversationNode, ChoreographyTaskNode, ConversationNode, DataInputNode, DataObjectNode, DataObjectReferenceNode, DataOutputNode, DataStoreNode, DataStoreReferenceNode, EndEventNode, GatewayNode, GroupNode, IntermediateCatchEventNode, IntermediateThrowEventNode, LaneNode, PoolNode, StartEventNode, SubChoreographyNode, SubConversationNode, SubProcessNode, TaskNode } from './nodes/index.js';
5
5
  export { AssociationEdge, BPMN_EDGE_TYPES, ConversationLinkEdge, DataAssociationEdge, MessageFlowEdge, SequenceFlowEdge } from './edges/index.js';
6
6
  export { parseBpmnXml, serializeBpmnXml } from './xml/index.js';
7
- export { B as BpmnExportOptions, a as BpmnImportResult, b as BpmnProcessModel, c as BpmnRFEdge, d as BpmnRFNode } from './types-CBgWMl9p.js';
8
- export { SimDiagram, SimEdge, SimLogEntry, SimLogType, SimNode, SimStatus, SimToken, SimVariables, SimulationState, createSimulation, fire, getFireable, isCompleted, setVariable, tick } from './simulation/index.js';
7
+ export { B as BpmnExportOptions, a as BpmnImportResult, b as BpmnProcessModel, c as BpmnRFEdge, d as BpmnRFNode } from './types-DSDMCAre.js';
8
+ import { SimDiagram } from './simulation/index.js';
9
+ export { SimEdge, SimLogEntry, SimLogType, SimNode, SimStatus, SimToken, SimVariables, SimulationState, createSimulation, fire, getFireable, isCompleted, setVariable, tick } from './simulation/index.js';
9
10
  export { BPMN_EDGE_CONNECTION_RULES, BPMN_MODELING_RULES, BPMN_POOL_LANE_LAYOUT, BPMN_ROUTABLE_EDGE_TYPES, BPMN_SELECTION_STYLE, BpmnClipboardState, BpmnConnectionRule, BpmnDiagramDocument, BpmnDiagramSnapshot, BpmnDiagramState, BpmnEventBus, ConnectBpmnOptions, CreateBpmnNodeOptions, FindBpmnContainerAtOptions, GroupAsBpmnSubProcessOptions, MoveBpmnLaneOptions, PasteBpmnOptions, ReorderBpmnLaneOptions, ReparentBpmnNodeAtPositionOptions, ReparentBpmnNodeOptions, ReplaceBpmnNodeOptions, ResizeBpmnNodeByHandleOptions, ResizeBpmnNodeOptions, RouteBpmnEdgeOptions, attachBoundaryEventCommand, bpmnConnectionValidators, canContainBpmnElement, computeBpmnSmartGuides, connectBpmnCommand, copyBpmnElements, createBpmnDiagramDocument, createBpmnEventBus, createBpmnLayoutCache, createBpmnNode, createBpmnNodeCommand, deleteBpmnElementsCommand, deserializeBpmnDiagram, deserializeBpmnDiagramSnapshot, findBpmnContainerAt, getBpmnDragHandleSelector, getBpmnEdgeLabelLayout, getBpmnLaneIndexAtPosition, getBpmnNodeAbsolutePosition, getBpmnNodeCenter, getBpmnNodeSize, getBpmnNodeZIndex, getBpmnPoolLanes, getBpmnTabOrder, groupAsBpmnSubProcessCommand, inferBpmnEdgeType, isBpmnDroppableInContainer, isBpmnEdgeRoutingEditable, isBpmnProcessNode, layoutBpmnPoolLaneNodes, layoutBpmnPoolLanes, moveBpmnLaneCommand, parseBpmnDiagramDocument, pasteBpmnElementsCommand, persistBpmnHistory, reorderBpmnLane, reorderBpmnLaneAfterDrop, reorderBpmnLaneCommand, reparentBpmnNodeAtPosition, reparentBpmnNodeCommand, replaceBpmnNodeCommand, resizeBpmnNodeByHandleCommand, resizeBpmnNodeCommand, restoreBpmnHistory, routeBpmnEdgeCommand, runBpmnCommand, runBpmnCommands, selectBpmnElementsCommand, serializeBpmnDiagram, toBpmnRelativePosition, validateBpmnConnectionForEdgeType, withBpmnLayoutCache, withBpmnNodeZIndexes } from './modeling/index.js';
10
11
  export { BpmnValidationIssue, BpmnValidationOptions, BpmnValidationResult, BpmnValidationSeverity } from './validation/index.js';
11
12
  import 'react/jsx-runtime';
12
13
  import '@xyflow/react';
13
14
  import '@aranzatech/diagrams-core';
14
15
  import '@aranzatech/diagrams-core/serialization';
16
+
17
+ /**
18
+ * Branch weights for one gateway.
19
+ * Maps each outgoing sequence-flow edge ID to a non-negative weight.
20
+ * Weights are normalised internally so they need not sum to any specific value.
21
+ * An edge absent from the map inherits weight 1.
22
+ */
23
+ type GatewayWeights = Record<string, number>;
24
+ interface BatchSimConfig {
25
+ /**
26
+ * Number of process instances to simulate.
27
+ * @default 100
28
+ */
29
+ instances?: number;
30
+ /**
31
+ * Gateway branch weights. Keys are gateway node IDs; values map
32
+ * each outgoing edge ID to its relative weight.
33
+ * Applies to ExclusiveGateway and InclusiveGateway nodes.
34
+ * Gateways absent from this map fall back to condition evaluation
35
+ * or first-edge behaviour.
36
+ */
37
+ gatewayWeights?: Record<string, GatewayWeights>;
38
+ /**
39
+ * Simulated activity duration per node in milliseconds.
40
+ * Used to compute the `totalDurationMs` load indicator:
41
+ * totalDurationMs = visits × nodeDurations[nodeId]
42
+ * Nodes absent from this map contribute 0 ms.
43
+ */
44
+ nodeDurations?: Record<string, number>;
45
+ /**
46
+ * Safety limit: maximum tick iterations per instance.
47
+ * Prevents infinite-loop diagrams from blocking indefinitely.
48
+ * @default 500
49
+ */
50
+ maxSteps?: number;
51
+ }
52
+ interface NodeSimStats {
53
+ /**
54
+ * Number of instances in which at least one token passed through
55
+ * this node. Value in [0, config.instances].
56
+ */
57
+ visits: number;
58
+ /**
59
+ * visits × nodeDurations[nodeId].
60
+ * Higher values indicate heavier aggregate load on this activity.
61
+ */
62
+ totalDurationMs: number;
63
+ /**
64
+ * Highest number of concurrent tokens at this node observed within
65
+ * any single instance. Values > 1 occur inside parallel branches.
66
+ */
67
+ peakConcurrency: number;
68
+ }
69
+ interface BatchSimResult {
70
+ /** Per-node aggregated statistics, keyed by node ID. */
71
+ nodeStats: Record<string, NodeSimStats>;
72
+ /** Instances that reached the EndEvent(s) successfully. */
73
+ completed: number;
74
+ /** Instances that stalled with tokens still present (deadlock). */
75
+ deadlocked: number;
76
+ /** Total instances attempted — equals `config.instances`. */
77
+ total: number;
78
+ /**
79
+ * Mean number of simulation steps across completed instances.
80
+ * Proxy for relative cycle time (higher = longer path).
81
+ * 0 when no instance completed.
82
+ */
83
+ avgSteps: number;
84
+ }
85
+ /**
86
+ * Run `config.instances` process instances through the diagram and
87
+ * aggregate per-node statistics for bottleneck analysis.
88
+ *
89
+ * Tasks are completed instantly (no wait time); gateway choices follow
90
+ * either the weights in `config.gatewayWeights` or the existing
91
+ * condition/default/first-edge logic when no weights are specified.
92
+ *
93
+ * @param diagram - The BPMN graph to simulate.
94
+ * @param config - Simulation parameters.
95
+ * @returns Aggregated {@link BatchSimResult}.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const result = runBatchSimulation(diagram, {
100
+ * instances: 200,
101
+ * gatewayWeights: {
102
+ * "gw_approve": { "edge_approved": 70, "edge_rejected": 30 },
103
+ * },
104
+ * nodeDurations: { "task_review": 3600_000 }, // 1 hour
105
+ * });
106
+ * const topBottleneck = Object.entries(result.nodeStats)
107
+ * .sort((a, b) => b[1].totalDurationMs - a[1].totalDurationMs)[0];
108
+ * ```
109
+ */
110
+ declare function runBatchSimulation(diagram: SimDiagram, config?: BatchSimConfig): BatchSimResult;
111
+
112
+ export { type BatchSimConfig, type BatchSimResult, type GatewayWeights, type NodeSimStats, SimDiagram, runBatchSimulation };
package/dist/index.js CHANGED
@@ -2,10 +2,137 @@ import './chunk-OZKTOILD.js';
2
2
  export { AnnotationNode, BPMN_NODE_TYPES, BoundaryEventNode, CallChoreographyNode, CallConversationNode, ChoreographyTaskNode, ConversationNode, DataInputNode, DataObjectNode, DataObjectReferenceNode, DataOutputNode, DataStoreNode, DataStoreReferenceNode, EndEventNode, GatewayNode, GroupNode, IntermediateCatchEventNode, IntermediateThrowEventNode, LaneNode, PoolNode, StartEventNode, SubChoreographyNode, SubConversationNode, SubProcessNode, TaskNode } from './chunk-IMW6RG6F.js';
3
3
  export { AssociationEdge, BPMN_EDGE_TYPES, ConversationLinkEdge, DataAssociationEdge, MessageFlowEdge, SequenceFlowEdge } from './chunk-O3NWJ5H7.js';
4
4
  import './chunk-PDTXM32P.js';
5
- export { parseBpmnXml, serializeBpmnXml } from './chunk-KW2QVBOB.js';
5
+ export { parseBpmnXml, serializeBpmnXml } from './chunk-HLCUGTEK.js';
6
+ import { createSimulation, tick, getFireable, fire } from './chunk-M46UDUN3.js';
6
7
  export { createSimulation, fire, getFireable, isCompleted, setVariable, tick } from './chunk-M46UDUN3.js';
7
8
  export { BPMN_EDGE_CONNECTION_RULES, BPMN_MODELING_RULES, BPMN_POOL_LANE_LAYOUT, BPMN_ROUTABLE_EDGE_TYPES, BPMN_SELECTION_STYLE, attachBoundaryEventCommand, bpmnConnectionValidators, canContainBpmnElement, computeBpmnSmartGuides, connectBpmnCommand, copyBpmnElements, createBpmnDiagramDocument, createBpmnEventBus, createBpmnLayoutCache, createBpmnNode, createBpmnNodeCommand, deleteBpmnElementsCommand, deserializeBpmnDiagram, deserializeBpmnDiagramSnapshot, findBpmnContainerAt, getBpmnDragHandleSelector, getBpmnEdgeLabelLayout, getBpmnLaneIndexAtPosition, getBpmnNodeAbsolutePosition, getBpmnNodeCenter, getBpmnNodeSize, getBpmnNodeZIndex, getBpmnPoolLanes, getBpmnTabOrder, groupAsBpmnSubProcessCommand, inferBpmnEdgeType, isBpmnDroppableInContainer, isBpmnEdgeRoutingEditable, isBpmnProcessNode, layoutBpmnPoolLaneNodes, layoutBpmnPoolLanes, moveBpmnLaneCommand, parseBpmnDiagramDocument, pasteBpmnElementsCommand, persistBpmnHistory, reorderBpmnLane, reorderBpmnLaneAfterDrop, reorderBpmnLaneCommand, reparentBpmnNodeAtPosition, reparentBpmnNodeCommand, replaceBpmnNodeCommand, resizeBpmnNodeByHandleCommand, resizeBpmnNodeCommand, restoreBpmnHistory, routeBpmnEdgeCommand, runBpmnCommand, runBpmnCommands, selectBpmnElementsCommand, serializeBpmnDiagram, toBpmnRelativePosition, validateBpmnConnectionForEdgeType, withBpmnLayoutCache, withBpmnNodeZIndexes } from './chunk-UAWLUDKC.js';
8
9
  export { acceptsBoundaryEvents, getHandlePolicy, getOrientation, isChoreographyType, isContainerType, isConversationType, isDataType, isEventType, isGatewayType, isTaskType, supportsCollapse, supportsMarkers } from './chunk-RLAJNRF2.js';
9
10
  export { BPMN_ELEMENT_CATALOG, BPMN_RESIZABLE_ELEMENT_TYPES, getBpmnElementSize, getElementMeta, isBpmnElementResizable } from './chunk-L5Z22RLX.js';
11
+
12
+ // src/simulation/batch.ts
13
+ function weightedChoice(edgeIds, weights) {
14
+ if (edgeIds.length === 0) return "";
15
+ const w = edgeIds.map((id) => Math.max(0, weights[id] ?? 1));
16
+ const total = w.reduce((a, b) => a + b, 0);
17
+ if (total === 0) return edgeIds[0];
18
+ let r = Math.random() * total;
19
+ for (let i = 0; i < edgeIds.length; i++) {
20
+ r -= w[i];
21
+ if (r <= 0) return edgeIds[i];
22
+ }
23
+ return edgeIds[edgeIds.length - 1];
24
+ }
25
+ function buildBatchDiagram(diagram, gatewayWeights, gwVarMap) {
26
+ const patchedEdges = diagram.edges.map((edge) => {
27
+ const gwId = edge.source;
28
+ if (!(gwId in gatewayWeights) || edge.type !== "sequenceFlow") return edge;
29
+ const varName = gwVarMap[gwId];
30
+ const outEdges = diagram.edges.filter(
31
+ (e) => e.source === gwId && e.type === "sequenceFlow"
32
+ );
33
+ const idx = outEdges.findIndex((e) => e.id === edge.id);
34
+ if (idx === -1) return edge;
35
+ return {
36
+ ...edge,
37
+ conditionExpression: `\${${varName} == ${idx}}`,
38
+ isDefault: false
39
+ };
40
+ });
41
+ return { nodes: diagram.nodes, edges: patchedEdges };
42
+ }
43
+ function runOneInstance(diagram, initialVars, maxSteps) {
44
+ let state = createSimulation(diagram, initialVars);
45
+ state = tick(diagram, state);
46
+ const visitedNodes = /* @__PURE__ */ new Set();
47
+ const peakPerNode = {};
48
+ function snapshot() {
49
+ const counts = {};
50
+ for (const token of state.tokens) {
51
+ visitedNodes.add(token.elementId);
52
+ counts[token.elementId] = (counts[token.elementId] ?? 0) + 1;
53
+ }
54
+ for (const [nodeId, c] of Object.entries(counts)) {
55
+ if (c > (peakPerNode[nodeId] ?? 0)) peakPerNode[nodeId] = c;
56
+ }
57
+ }
58
+ snapshot();
59
+ let steps = 0;
60
+ while (state.status === "running" && steps < maxSteps) {
61
+ const fireable = getFireable(diagram, state);
62
+ if (fireable.length === 0) break;
63
+ for (const id of fireable) {
64
+ if (state.status !== "running") break;
65
+ state = fire(diagram, state, id);
66
+ snapshot();
67
+ }
68
+ steps++;
69
+ }
70
+ for (const entry of state.log) {
71
+ visitedNodes.add(entry.elementId);
72
+ }
73
+ return {
74
+ visitedNodes,
75
+ peakPerNode,
76
+ steps: state.step,
77
+ completed: state.status === "completed"
78
+ };
79
+ }
80
+ function runBatchSimulation(diagram, config = {}) {
81
+ const n = Math.max(1, config.instances ?? 100);
82
+ const maxSteps = Math.max(1, config.maxSteps ?? 500);
83
+ const gwWeights = config.gatewayWeights ?? {};
84
+ const nodeDurations = config.nodeDurations ?? {};
85
+ const gwVarMap = {};
86
+ Object.keys(gwWeights).forEach((gwId, i) => {
87
+ gwVarMap[gwId] = `__g${i}`;
88
+ });
89
+ const batchDiagram = Object.keys(gwWeights).length > 0 ? buildBatchDiagram(diagram, gwWeights, gwVarMap) : diagram;
90
+ const nodeStats = {};
91
+ function node(id) {
92
+ if (!nodeStats[id]) {
93
+ nodeStats[id] = { visits: 0, totalDurationMs: 0, peakConcurrency: 0 };
94
+ }
95
+ return nodeStats[id];
96
+ }
97
+ let completed = 0;
98
+ let deadlocked = 0;
99
+ let totalSteps = 0;
100
+ for (let i = 0; i < n; i++) {
101
+ const instanceVars = {};
102
+ for (const [gwId, varName] of Object.entries(gwVarMap)) {
103
+ const outEdges = diagram.edges.filter(
104
+ (e) => e.source === gwId && e.type === "sequenceFlow"
105
+ );
106
+ const edgeIds = outEdges.map((e) => e.id);
107
+ const chosen = weightedChoice(edgeIds, gwWeights[gwId]);
108
+ instanceVars[varName] = outEdges.findIndex((e) => e.id === chosen);
109
+ }
110
+ const result = runOneInstance(batchDiagram, instanceVars, maxSteps);
111
+ if (result.completed) {
112
+ completed++;
113
+ totalSteps += result.steps;
114
+ } else {
115
+ deadlocked++;
116
+ }
117
+ for (const nodeId of result.visitedNodes) {
118
+ const s = node(nodeId);
119
+ s.visits++;
120
+ s.totalDurationMs += nodeDurations[nodeId] ?? 0;
121
+ }
122
+ for (const [nodeId, peak] of Object.entries(result.peakPerNode)) {
123
+ const s = node(nodeId);
124
+ if (peak > s.peakConcurrency) s.peakConcurrency = peak;
125
+ }
126
+ }
127
+ return {
128
+ nodeStats,
129
+ completed,
130
+ deadlocked,
131
+ total: n,
132
+ avgSteps: completed > 0 ? Math.round(totalSteps / completed) : 0
133
+ };
134
+ }
135
+
136
+ export { runBatchSimulation };
10
137
  //# sourceMappingURL=index.js.map
11
138
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
1
+ {"version":3,"sources":["../src/simulation/batch.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\n createSimulation,\n tick,\n fire,\n getFireable,\n} from \"./index\";\nimport type { SimDiagram, SimEdge } from \"./index\";\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/**\n * Branch weights for one gateway.\n * Maps each outgoing sequence-flow edge ID to a non-negative weight.\n * Weights are normalised internally so they need not sum to any specific value.\n * An edge absent from the map inherits weight 1.\n */\nexport type GatewayWeights = Record<string, number>;\n\nexport interface BatchSimConfig {\n /**\n * Number of process instances to simulate.\n * @default 100\n */\n instances?: number;\n\n /**\n * Gateway branch weights. Keys are gateway node IDs; values map\n * each outgoing edge ID to its relative weight.\n * Applies to ExclusiveGateway and InclusiveGateway nodes.\n * Gateways absent from this map fall back to condition evaluation\n * or first-edge behaviour.\n */\n gatewayWeights?: Record<string, GatewayWeights>;\n\n /**\n * Simulated activity duration per node in milliseconds.\n * Used to compute the `totalDurationMs` load indicator:\n * totalDurationMs = visits × nodeDurations[nodeId]\n * Nodes absent from this map contribute 0 ms.\n */\n nodeDurations?: Record<string, number>;\n\n /**\n * Safety limit: maximum tick iterations per instance.\n * Prevents infinite-loop diagrams from blocking indefinitely.\n * @default 500\n */\n maxSteps?: number;\n}\n\nexport interface NodeSimStats {\n /**\n * Number of instances in which at least one token passed through\n * this node. Value in [0, config.instances].\n */\n visits: number;\n\n /**\n * visits × nodeDurations[nodeId].\n * Higher values indicate heavier aggregate load on this activity.\n */\n totalDurationMs: number;\n\n /**\n * Highest number of concurrent tokens at this node observed within\n * any single instance. Values > 1 occur inside parallel branches.\n */\n peakConcurrency: number;\n}\n\nexport interface BatchSimResult {\n /** Per-node aggregated statistics, keyed by node ID. */\n nodeStats: Record<string, NodeSimStats>;\n\n /** Instances that reached the EndEvent(s) successfully. */\n completed: number;\n\n /** Instances that stalled with tokens still present (deadlock). */\n deadlocked: number;\n\n /** Total instances attempted — equals `config.instances`. */\n total: number;\n\n /**\n * Mean number of simulation steps across completed instances.\n * Proxy for relative cycle time (higher = longer path).\n * 0 when no instance completed.\n */\n avgSteps: number;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/** Weighted random selection from a list of edge IDs. */\nfunction weightedChoice(edgeIds: string[], weights: GatewayWeights): string {\n if (edgeIds.length === 0) return \"\";\n const w = edgeIds.map((id) => Math.max(0, weights[id] ?? 1));\n const total = w.reduce((a, b) => a + b, 0);\n if (total === 0) return edgeIds[0];\n\n let r = Math.random() * total;\n for (let i = 0; i < edgeIds.length; i++) {\n r -= w[i];\n if (r <= 0) return edgeIds[i];\n }\n return edgeIds[edgeIds.length - 1];\n}\n\n/**\n * Builds a modified diagram where each weighted gateway's outgoing\n * sequence edges carry a synthetic condition expression keyed to a\n * deterministic per-instance variable `__g{i}`.\n *\n * This lets the existing ExclusiveGateway evaluator (condition-based)\n * implement probabilistic branching without touching the engine core.\n */\nfunction buildBatchDiagram(\n diagram: SimDiagram,\n gatewayWeights: Record<string, GatewayWeights>,\n gwVarMap: Record<string, string>,\n): SimDiagram {\n const patchedEdges: SimEdge[] = diagram.edges.map((edge) => {\n const gwId = edge.source;\n if (!(gwId in gatewayWeights) || edge.type !== \"sequenceFlow\") return edge;\n\n const varName = gwVarMap[gwId];\n const outEdges = diagram.edges.filter(\n (e) => e.source === gwId && e.type === \"sequenceFlow\",\n );\n const idx = outEdges.findIndex((e) => e.id === edge.id);\n if (idx === -1) return edge;\n\n return {\n ...edge,\n conditionExpression: `\\${${varName} == ${idx}}`,\n isDefault: false,\n };\n });\n\n return { nodes: diagram.nodes, edges: patchedEdges };\n}\n\ninterface InstanceResult {\n /** All node IDs touched by any token during this instance. */\n visitedNodes: Set<string>;\n /** Peak concurrent-token count per node observed during this instance. */\n peakPerNode: Record<string, number>;\n /** Final simulation step count. */\n steps: number;\n completed: boolean;\n}\n\n/**\n * Runs a single process instance to completion (or until the safety\n * limit is reached). Manual elements (Tasks, CatchEvents) are fired\n * immediately — simulating instant activity completion — so the\n * run is fully automated.\n */\nfunction runOneInstance(\n diagram: SimDiagram,\n initialVars: Record<string, string | number | boolean>,\n maxSteps: number,\n): InstanceResult {\n let state = createSimulation(diagram, initialVars);\n state = tick(diagram, state);\n\n const visitedNodes = new Set<string>();\n const peakPerNode: Record<string, number> = {};\n\n function snapshot() {\n // Track which nodes are occupied and peak concurrency.\n const counts: Record<string, number> = {};\n for (const token of state.tokens) {\n visitedNodes.add(token.elementId);\n counts[token.elementId] = (counts[token.elementId] ?? 0) + 1;\n }\n for (const [nodeId, c] of Object.entries(counts)) {\n if (c > (peakPerNode[nodeId] ?? 0)) peakPerNode[nodeId] = c;\n }\n }\n\n snapshot();\n\n let steps = 0;\n while (state.status === \"running\" && steps < maxSteps) {\n const fireable = getFireable(diagram, state);\n if (fireable.length === 0) break;\n\n for (const id of fireable) {\n if (state.status !== \"running\") break;\n state = fire(diagram, state, id);\n snapshot();\n }\n steps++;\n }\n\n // Capture all nodes mentioned in the log (covers automatics that\n // never appear as token positions but do appear in log entries).\n for (const entry of state.log) {\n visitedNodes.add(entry.elementId);\n }\n\n return {\n visitedNodes,\n peakPerNode,\n steps: state.step,\n completed: state.status === \"completed\",\n };\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Run `config.instances` process instances through the diagram and\n * aggregate per-node statistics for bottleneck analysis.\n *\n * Tasks are completed instantly (no wait time); gateway choices follow\n * either the weights in `config.gatewayWeights` or the existing\n * condition/default/first-edge logic when no weights are specified.\n *\n * @param diagram - The BPMN graph to simulate.\n * @param config - Simulation parameters.\n * @returns Aggregated {@link BatchSimResult}.\n *\n * @example\n * ```ts\n * const result = runBatchSimulation(diagram, {\n * instances: 200,\n * gatewayWeights: {\n * \"gw_approve\": { \"edge_approved\": 70, \"edge_rejected\": 30 },\n * },\n * nodeDurations: { \"task_review\": 3600_000 }, // 1 hour\n * });\n * const topBottleneck = Object.entries(result.nodeStats)\n * .sort((a, b) => b[1].totalDurationMs - a[1].totalDurationMs)[0];\n * ```\n */\nexport function runBatchSimulation(\n diagram: SimDiagram,\n config: BatchSimConfig = {},\n): BatchSimResult {\n const n = Math.max(1, config.instances ?? 100);\n const maxSteps = Math.max(1, config.maxSteps ?? 500);\n const gwWeights = config.gatewayWeights ?? {};\n const nodeDurations = config.nodeDurations ?? {};\n\n // Map each weighted gateway to a synthetic variable name (__g0, __g1, …)\n const gwVarMap: Record<string, string> = {};\n Object.keys(gwWeights).forEach((gwId, i) => {\n gwVarMap[gwId] = `__g${i}`;\n });\n\n const batchDiagram =\n Object.keys(gwWeights).length > 0\n ? buildBatchDiagram(diagram, gwWeights, gwVarMap)\n : diagram;\n\n const nodeStats: Record<string, NodeSimStats> = {};\n\n function node(id: string): NodeSimStats {\n if (!nodeStats[id]) {\n nodeStats[id] = { visits: 0, totalDurationMs: 0, peakConcurrency: 0 };\n }\n return nodeStats[id];\n }\n\n let completed = 0;\n let deadlocked = 0;\n let totalSteps = 0;\n\n for (let i = 0; i < n; i++) {\n // Resolve branch choices for this instance based on configured weights.\n const instanceVars: Record<string, string | number | boolean> = {};\n for (const [gwId, varName] of Object.entries(gwVarMap)) {\n const outEdges = diagram.edges.filter(\n (e) => e.source === gwId && e.type === \"sequenceFlow\",\n );\n const edgeIds = outEdges.map((e) => e.id);\n const chosen = weightedChoice(edgeIds, gwWeights[gwId]);\n instanceVars[varName] = outEdges.findIndex((e) => e.id === chosen);\n }\n\n const result = runOneInstance(batchDiagram, instanceVars, maxSteps);\n\n if (result.completed) {\n completed++;\n totalSteps += result.steps;\n } else {\n deadlocked++;\n }\n\n // Accumulate per-node stats.\n for (const nodeId of result.visitedNodes) {\n const s = node(nodeId);\n s.visits++;\n s.totalDurationMs += nodeDurations[nodeId] ?? 0;\n }\n\n for (const [nodeId, peak] of Object.entries(result.peakPerNode)) {\n const s = node(nodeId);\n if (peak > s.peakConcurrency) s.peakConcurrency = peak;\n }\n }\n\n return {\n nodeStats,\n completed,\n deadlocked,\n total: n,\n avgSteps: completed > 0 ? Math.round(totalSteps / completed) : 0,\n };\n}\n"]}
@@ -1,12 +1,12 @@
1
1
  import { LayoutResult, LayoutOptions } from '@aranzatech/diagrams-core/types';
2
2
  export { applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
3
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-BjVERSZn.cjs';
3
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-C7tONwP5.cjs';
4
4
  import { BpmnDiagramState } from '../modeling/index.cjs';
5
5
  import '@xyflow/react';
6
- import '../types-wFn_tJLY.cjs';
6
+ import '../types-BTuiBv7p.cjs';
7
7
  import '@aranzatech/diagrams-core';
8
8
  import '@aranzatech/diagrams-core/serialization';
9
- import '../catalog-CjGdTFxc.cjs';
9
+ import '../catalog-Ch3YT0-0.cjs';
10
10
 
11
11
  /**
12
12
  * Dagre layout pre-configured for BPMN diagrams.
@@ -1,12 +1,12 @@
1
1
  import { LayoutResult, LayoutOptions } from '@aranzatech/diagrams-core/types';
2
2
  export { applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
3
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-CBgWMl9p.js';
3
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-DSDMCAre.js';
4
4
  import { BpmnDiagramState } from '../modeling/index.js';
5
5
  import '@xyflow/react';
6
- import '../types-wFn_tJLY.js';
6
+ import '../types-BTuiBv7p.js';
7
7
  import '@aranzatech/diagrams-core';
8
8
  import '@aranzatech/diagrams-core/serialization';
9
- import '../catalog-DW0Hknp2.js';
9
+ import '../catalog-BOwJOaXV.js';
10
10
 
11
11
  /**
12
12
  * Dagre layout pre-configured for BPMN diagrams.
@@ -1,8 +1,8 @@
1
1
  import { ModelingRules, ClipboardState, DiagramSnapshot, DiagramState, DiagramEventBus, ResizeHandlePosition, DiagramCommand, ConnectionValidator, SmartGuideResult, SelectionState, LayoutCacheOptions, LayoutCache, EdgeLabelOffsetOptions, EdgeLabelLayout, CommandStackState, Viewport, LayoutFn } from '@aranzatech/diagrams-core';
2
2
  import { DiagramDocument, CreateDiagramDocumentOptions } from '@aranzatech/diagrams-core/serialization';
3
- import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-wFn_tJLY.cjs';
4
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-BjVERSZn.cjs';
5
- export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-CjGdTFxc.cjs';
3
+ import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-BTuiBv7p.cjs';
4
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-C7tONwP5.cjs';
5
+ export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-Ch3YT0-0.cjs';
6
6
  import '@xyflow/react';
7
7
 
8
8
  type BpmnDiagramState = DiagramState<BpmnRFNode, BpmnRFEdge>;
@@ -1,8 +1,8 @@
1
1
  import { ModelingRules, ClipboardState, DiagramSnapshot, DiagramState, DiagramEventBus, ResizeHandlePosition, DiagramCommand, ConnectionValidator, SmartGuideResult, SelectionState, LayoutCacheOptions, LayoutCache, EdgeLabelOffsetOptions, EdgeLabelLayout, CommandStackState, Viewport, LayoutFn } from '@aranzatech/diagrams-core';
2
2
  import { DiagramDocument, CreateDiagramDocumentOptions } from '@aranzatech/diagrams-core/serialization';
3
- import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-wFn_tJLY.js';
4
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-CBgWMl9p.js';
5
- export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-DW0Hknp2.js';
3
+ import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-BTuiBv7p.js';
4
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-DSDMCAre.js';
5
+ export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-BOwJOaXV.js';
6
6
  import '@xyflow/react';
7
7
 
8
8
  type BpmnDiagramState = DiagramState<BpmnRFNode, BpmnRFEdge>;
@@ -168,6 +168,10 @@ interface BpmnNodeData extends Record<string, unknown> {
168
168
  decisionRef?: string;
169
169
  /** UserTask: form key resolved to a FormDefinition by name at runtime. */
170
170
  formKey?: string;
171
+ /** UserTask: comma-separated Flowable user ids that can claim this task. */
172
+ candidateUsers?: string;
173
+ /** UserTask: comma-separated Flowable group ids that can claim this task. */
174
+ candidateGroups?: string;
171
175
  /** AdHocSubProcess: FEEL expression that determines when the sub-process completes. */
172
176
  completionCondition?: string;
173
177
  }
@@ -168,6 +168,10 @@ interface BpmnNodeData extends Record<string, unknown> {
168
168
  decisionRef?: string;
169
169
  /** UserTask: form key resolved to a FormDefinition by name at runtime. */
170
170
  formKey?: string;
171
+ /** UserTask: comma-separated Flowable user ids that can claim this task. */
172
+ candidateUsers?: string;
173
+ /** UserTask: comma-separated Flowable group ids that can claim this task. */
174
+ candidateGroups?: string;
171
175
  /** AdHocSubProcess: FEEL expression that determines when the sub-process completes. */
172
176
  completionCondition?: string;
173
177
  }
@@ -1,5 +1,5 @@
1
1
  import { Node, Edge } from '@xyflow/react';
2
- import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-wFn_tJLY.cjs';
2
+ import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-BTuiBv7p.cjs';
3
3
 
4
4
  type BpmnRFNode = Node<BpmnNodeData>;
5
5
  type BpmnRFEdge = Edge<BpmnEdgeData>;
@@ -1,5 +1,5 @@
1
1
  import { Node, Edge } from '@xyflow/react';
2
- import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-wFn_tJLY.js';
2
+ import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-BTuiBv7p.js';
3
3
 
4
4
  type BpmnRFNode = Node<BpmnNodeData>;
5
5
  type BpmnRFEdge = Edge<BpmnEdgeData>;
@@ -1,6 +1,6 @@
1
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-BjVERSZn.cjs';
1
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-C7tONwP5.cjs';
2
2
  import '@xyflow/react';
3
- import '../types-wFn_tJLY.cjs';
3
+ import '../types-BTuiBv7p.cjs';
4
4
 
5
5
  type BpmnValidationSeverity = "error" | "warning" | "info";
6
6
  interface BpmnValidationIssue {
@@ -1,6 +1,6 @@
1
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-CBgWMl9p.js';
1
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-DSDMCAre.js';
2
2
  import '@xyflow/react';
3
- import '../types-wFn_tJLY.js';
3
+ import '../types-BTuiBv7p.js';
4
4
 
5
5
  type BpmnValidationSeverity = "error" | "warning" | "info";
6
6
  interface BpmnValidationIssue {
@@ -23,7 +23,10 @@ var ARANZA_DESCRIPTOR = {
23
23
  // BusinessRuleTask: reference to a DMN decision table id
24
24
  { name: "decisionRef", isAttr: true, type: "String" },
25
25
  // UserTask: form key resolved to a FormDefinition name at runtime
26
- { name: "formKey", isAttr: true, type: "String" }
26
+ { name: "formKey", isAttr: true, type: "String" },
27
+ // UserTask: Flowable task assignment — comma-separated ids
28
+ { name: "candidateUsers", isAttr: true, type: "String" },
29
+ { name: "candidateGroups", isAttr: true, type: "String" }
27
30
  ]
28
31
  }
29
32
  ],
@@ -897,6 +900,10 @@ function extractAranzaExtensions(el) {
897
900
  if (fde) result.flowableDelegateExpression = fde;
898
901
  const fk = asString(elAttrs["flowable:formKey"]);
899
902
  if (fk) result.formKey = fk;
903
+ const cu = asString(elAttrs["flowable:candidateUsers"]);
904
+ if (cu) result.candidateUsers = cu;
905
+ const cg = asString(elAttrs["flowable:candidateGroups"]);
906
+ if (cg) result.candidateGroups = cg;
900
907
  }
901
908
  const ext = el.extensionElements;
902
909
  if (!ext) return result;
@@ -922,6 +929,10 @@ function extractAranzaExtensions(el) {
922
929
  if (decisionRef) result.decisionRef = decisionRef;
923
930
  const formKey = asString(taskConfig.formKey);
924
931
  if (formKey) result.formKey = formKey;
932
+ const candidateUsers = asString(taskConfig.candidateUsers);
933
+ if (candidateUsers) result.candidateUsers = candidateUsers;
934
+ const candidateGroups = asString(taskConfig.candidateGroups);
935
+ if (candidateGroups) result.candidateGroups = candidateGroups;
925
936
  return result;
926
937
  }
927
938
  function extractCompletionCondition(el) {
@@ -1291,7 +1302,9 @@ function buildAranzaExtensionElements(moddle, node) {
1291
1302
  const flowableDelegateExpression = typeof node.data.flowableDelegateExpression === "string" ? node.data.flowableDelegateExpression : void 0;
1292
1303
  const decisionRef = typeof node.data.decisionRef === "string" ? node.data.decisionRef : void 0;
1293
1304
  const formKey = typeof node.data.formKey === "string" ? node.data.formKey : void 0;
1294
- if (!priority && !owner && !sla && !connector && !action && !flowableType && !flowableDelegateExpression && !decisionRef && !formKey) {
1305
+ const candidateUsers = typeof node.data.candidateUsers === "string" ? node.data.candidateUsers : void 0;
1306
+ const candidateGroups = typeof node.data.candidateGroups === "string" ? node.data.candidateGroups : void 0;
1307
+ if (!priority && !owner && !sla && !connector && !action && !flowableType && !flowableDelegateExpression && !decisionRef && !formKey && !candidateUsers && !candidateGroups) {
1295
1308
  return null;
1296
1309
  }
1297
1310
  const configAttrs = {};
@@ -1304,6 +1317,8 @@ function buildAranzaExtensionElements(moddle, node) {
1304
1317
  if (flowableDelegateExpression) configAttrs.flowableDelegateExpression = flowableDelegateExpression;
1305
1318
  if (decisionRef) configAttrs.decisionRef = decisionRef;
1306
1319
  if (formKey) configAttrs.formKey = formKey;
1320
+ if (candidateUsers) configAttrs.candidateUsers = candidateUsers;
1321
+ if (candidateGroups) configAttrs.candidateGroups = candidateGroups;
1307
1322
  const taskConfig = moddle.create("aranza:TaskConfig", configAttrs);
1308
1323
  return moddle.create("bpmn:ExtensionElements", { values: [taskConfig] });
1309
1324
  }
@@ -1486,8 +1501,14 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
1486
1501
  if (script) attrs.script = script;
1487
1502
  }
1488
1503
  if (elementType === "UserTask") {
1504
+ const flowableAttrs = {};
1489
1505
  const fk = typeof node.data.formKey === "string" ? node.data.formKey : void 0;
1490
- if (fk) attrs.$attrs = { "flowable:formKey": fk };
1506
+ const cu = typeof node.data.candidateUsers === "string" ? node.data.candidateUsers : void 0;
1507
+ const cg = typeof node.data.candidateGroups === "string" ? node.data.candidateGroups : void 0;
1508
+ if (fk) flowableAttrs["flowable:formKey"] = fk;
1509
+ if (cu) flowableAttrs["flowable:candidateUsers"] = cu;
1510
+ if (cg) flowableAttrs["flowable:candidateGroups"] = cg;
1511
+ if (Object.keys(flowableAttrs).length > 0) attrs.$attrs = flowableAttrs;
1491
1512
  }
1492
1513
  if (elementType === "ServiceTask") {
1493
1514
  const flowableAttrs = {};