@aranzatech/diagrams-bpmn 0.2.15 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +34 -4
  2. package/dist/{catalog-xOMF2ifW.d.cts → catalog-DAGDhO-D.d.cts} +1 -1
  3. package/dist/{catalog-CK3_4cOb.d.ts → catalog-Q1QmKLDD.d.ts} +1 -1
  4. package/dist/{chunk-YUE5EM3W.js → chunk-334WN4JZ.js} +276 -107
  5. package/dist/chunk-334WN4JZ.js.map +1 -0
  6. package/dist/chunk-77L6O76M.js +3 -0
  7. package/dist/chunk-77L6O76M.js.map +1 -0
  8. package/dist/{chunk-QSMP34CT.js → chunk-CPFUQM6H.js} +80 -44
  9. package/dist/chunk-CPFUQM6H.js.map +1 -0
  10. package/dist/{chunk-XMVV7FRZ.js → chunk-FFWJA5BV.js} +3 -3
  11. package/dist/{chunk-XMVV7FRZ.js.map → chunk-FFWJA5BV.js.map} +1 -1
  12. package/dist/{chunk-FBTGIYZS.js → chunk-JEGYVEJO.js} +80 -3
  13. package/dist/{chunk-FBTGIYZS.js.map → chunk-JEGYVEJO.js.map} +1 -1
  14. package/dist/chunk-TB6V4S5N.js +104 -0
  15. package/dist/chunk-TB6V4S5N.js.map +1 -0
  16. package/dist/{chunk-HOWK3ZOO.js → chunk-YAYZW45I.js} +379 -16
  17. package/dist/chunk-YAYZW45I.js.map +1 -0
  18. package/dist/edges/index.cjs +78 -42
  19. package/dist/edges/index.cjs.map +1 -1
  20. package/dist/edges/index.js +1 -1
  21. package/dist/elements/index.cjs +78 -0
  22. package/dist/elements/index.cjs.map +1 -1
  23. package/dist/elements/index.d.cts +24 -5
  24. package/dist/elements/index.d.ts +24 -5
  25. package/dist/elements/index.js +1 -1
  26. package/dist/elk-QT7H4252.js +6 -0
  27. package/dist/elk-QT7H4252.js.map +1 -0
  28. package/dist/extensions/index.cjs +108 -0
  29. package/dist/extensions/index.cjs.map +1 -0
  30. package/dist/extensions/index.d.cts +145 -0
  31. package/dist/extensions/index.d.ts +145 -0
  32. package/dist/extensions/index.js +4 -0
  33. package/dist/extensions/index.js.map +1 -0
  34. package/dist/index.cjs +922 -160
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +7 -5
  37. package/dist/index.d.ts +7 -5
  38. package/dist/index.js +6 -4
  39. package/dist/index.js.map +1 -1
  40. package/dist/layout/index.cjs +11 -1
  41. package/dist/layout/index.cjs.map +1 -1
  42. package/dist/layout/index.d.cts +4 -3
  43. package/dist/layout/index.d.ts +4 -3
  44. package/dist/layout/index.js +3 -3
  45. package/dist/modeling/index.cjs +387 -13
  46. package/dist/modeling/index.cjs.map +1 -1
  47. package/dist/modeling/index.d.cts +62 -4
  48. package/dist/modeling/index.d.ts +62 -4
  49. package/dist/modeling/index.js +1 -1
  50. package/dist/types-BX_o95GC.d.cts +40 -0
  51. package/dist/{types-y-ZbX-ff.d.ts → types-BYN4Zuee.d.cts} +15 -1
  52. package/dist/{types-y-ZbX-ff.d.cts → types-BYN4Zuee.d.ts} +15 -1
  53. package/dist/{types-jIDz306Y.d.cts → types-CggktCqr.d.cts} +4 -1
  54. package/dist/types-D7zel9dq.d.ts +40 -0
  55. package/dist/{types-DG5yPKld.d.ts → types-DmDODKlh.d.ts} +4 -1
  56. package/dist/validation/index.cjs +81 -125
  57. package/dist/validation/index.cjs.map +1 -1
  58. package/dist/validation/index.d.cts +22 -5
  59. package/dist/validation/index.d.ts +22 -5
  60. package/dist/validation/index.js +82 -126
  61. package/dist/validation/index.js.map +1 -1
  62. package/dist/xml/index.cjs +319 -49
  63. package/dist/xml/index.cjs.map +1 -1
  64. package/dist/xml/index.d.cts +5 -3
  65. package/dist/xml/index.d.ts +5 -3
  66. package/dist/xml/index.js +2 -1
  67. package/package.json +6 -1
  68. package/dist/chunk-HOWK3ZOO.js.map +0 -1
  69. package/dist/chunk-QSMP34CT.js.map +0 -1
  70. package/dist/chunk-YUE5EM3W.js.map +0 -1
  71. package/dist/elk-FSFIEL6O.js +0 -6
  72. package/dist/elk-FSFIEL6O.js.map +0 -1
  73. package/dist/guards-C70uIY_O.d.cts +0 -16
  74. package/dist/guards-foB6XIfZ.d.ts +0 -16
package/README.md CHANGED
@@ -2,10 +2,12 @@
2
2
 
3
3
  BPMN 2.0 building blocks for the Aranza diagram ecosystem. This package owns
4
4
  BPMN-specific visual components, element metadata, BPMN modeling helpers, XML
5
- import/export and preview token simulation.
5
+ import/export, execution-extension contracts and preview token simulation.
6
6
 
7
- It is intentionally not responsible for execution-engine communication. Flowable
8
- integration belongs in a future wrapper package or in the consuming app backend.
7
+ It is intentionally not responsible for execution-engine communication. Backend
8
+ orchestrators still own actual Flowable runtime calls, deployment and instance
9
+ management. This package only owns the BPMN-side contract used to model and
10
+ round-trip those extensions safely.
9
11
 
10
12
  ## Public Subpaths
11
13
 
@@ -27,15 +29,43 @@ import { createSimulation } from "@aranzatech/diagrams-bpmn/simulation";
27
29
  - BPMN visual node and edge renderers for ReactFlow.
28
30
  - BPMN element catalog and guards.
29
31
  - BPMN XML import/export through `bpmn-moddle`.
32
+ - BPMN extension contracts for Aranza/Flowable task and message metadata.
30
33
  - BPMN modeling commands and interaction rules on top of `diagrams-core`.
31
34
  - Client-side preview token simulation.
32
35
 
33
36
  ## Out Of Scope
34
37
 
35
- - Flowable REST/backend communication.
38
+ - Flowable REST/backend communication and engine lifecycle.
36
39
  - BPMN business validation rules. Those belong in `@aranzatech/flowslint`.
37
40
  - Full execution semantics.
38
41
 
42
+ ## Extension Contract
43
+
44
+ Engine-specific metadata that still belongs to the BPMN model lives here.
45
+
46
+ - `ARANZA_DESCRIPTOR` defines the XML extension namespace.
47
+ - `BpmnFlowableExportOptions` defines Flowable export enrichment options.
48
+ - `getBpmnTaskExecutionExtensions(...)` reads the task-side execution payload.
49
+ - `getBpmnMessageFlowExecutionExtensions(...)` reads message-flow execution metadata.
50
+
51
+ That lets `webapp` focus on UX and lets `flowslint` validate the same contract
52
+ without inventing app-local shapes again.
53
+
54
+ ## Validation Scope
55
+
56
+ `@aranzatech/diagrams-bpmn/validation` remains available only as a deprecated
57
+ compatibility layer for structural editor invariants:
58
+
59
+ - edge references must point to existing nodes
60
+ - self-loops are rejected
61
+ - boundary events must attach to valid hosts
62
+ - lanes must belong to pools
63
+ - edge endpoint families must be structurally valid
64
+
65
+ For semantic BPMN 2.0 linting such as start/end requirements, gateway rules,
66
+ reachability, naming, Aranza conventions and publish-time findings, use
67
+ `@aranzatech/flowslint`.
68
+
39
69
  ## Coverage Matrix
40
70
 
41
71
  | Area | Status | Notes |
@@ -1,4 +1,4 @@
1
- import { f as BpmnElementType, d as BpmnElementMeta, e as BpmnElementSize } from './types-y-ZbX-ff.cjs';
1
+ import { f as BpmnElementType, d as BpmnElementMeta, e as BpmnElementSize } from './types-BYN4Zuee.cjs';
2
2
 
3
3
  declare const BPMN_ELEMENT_CATALOG: Record<BpmnElementType, BpmnElementMeta>;
4
4
  declare function getElementMeta(type: BpmnElementType): BpmnElementMeta;
@@ -1,4 +1,4 @@
1
- import { f as BpmnElementType, d as BpmnElementMeta, e as BpmnElementSize } from './types-y-ZbX-ff.js';
1
+ import { f as BpmnElementType, d as BpmnElementMeta, e as BpmnElementSize } from './types-BYN4Zuee.js';
2
2
 
3
3
  declare const BPMN_ELEMENT_CATALOG: Record<BpmnElementType, BpmnElementMeta>;
4
4
  declare function getElementMeta(type: BpmnElementType): BpmnElementMeta;
@@ -1,61 +1,6 @@
1
+ import { ARANZA_DESCRIPTOR, getBpmnMessageFlowExecutionExtensions, getBpmnTaskExecutionExtensions } from './chunk-TB6V4S5N.js';
1
2
  import { BPMN_ELEMENT_CATALOG } from './chunk-L5Z22RLX.js';
2
3
 
3
- // src/xml/aranza-descriptor.ts
4
- var ARANZA_DESCRIPTOR = {
5
- name: "Aranza",
6
- uri: "http://aranzatech.io/schema/bpmn-extension/1.0",
7
- prefix: "aranza",
8
- xml: { tagAlias: "lowerCase" },
9
- types: [
10
- {
11
- name: "TaskConfig",
12
- superClass: ["Element"],
13
- properties: [
14
- { name: "priority", isAttr: true, type: "String" },
15
- { name: "owner", isAttr: true, type: "String" },
16
- { name: "sla", isAttr: true, type: "String" },
17
- // Aranza connector execution config (resolved at runtime by the Flowable delegate)
18
- { name: "connector", isAttr: true, type: "String" },
19
- { name: "action", isAttr: true, type: "String" },
20
- // Flowable implementation hints stored for round-trip fidelity
21
- { name: "flowableType", isAttr: true, type: "String" },
22
- { name: "flowableDelegateExpression", isAttr: true, type: "String" },
23
- // BusinessRuleTask: reference to a DMN decision table id
24
- { name: "decisionRef", isAttr: true, type: "String" },
25
- // UserTask: form key resolved to a FormDefinition name at runtime
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" },
30
- // UserTask: scheduling + skip expression
31
- { name: "dueDate", isAttr: true, type: "String" },
32
- { name: "skipExpression", isAttr: true, type: "String" },
33
- { name: "businessCalendarName", isAttr: true, type: "String" }
34
- ]
35
- },
36
- {
37
- // BusinessRuleTask: simplified inline decision table (JSON-serialized)
38
- name: "InlineDecision",
39
- superClass: ["Element"],
40
- properties: [
41
- { name: "hitPolicy", isAttr: true, type: "String" },
42
- { name: "tableJson", isAttr: true, type: "String" }
43
- ]
44
- },
45
- {
46
- // MessageFlow: payload schema + correlation key for executable BPMN
47
- name: "MessageFlowConfig",
48
- superClass: ["Element"],
49
- properties: [
50
- { name: "payloadSchema", isAttr: true, type: "String" },
51
- { name: "correlationKey", isAttr: true, type: "String" }
52
- ]
53
- }
54
- ],
55
- enumerations: [],
56
- associations: []
57
- };
58
-
59
4
  // src/xml/mapper.ts
60
5
  var MODDLE_TO_ELEMENT_TYPE = {
61
6
  "bpmn:StartEvent": "StartEvent",
@@ -184,6 +129,11 @@ function asElements(v) {
184
129
  function asString(v) {
185
130
  return typeof v === "string" && v.trim() ? v.trim() : void 0;
186
131
  }
132
+ function asStringRecord(value) {
133
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
134
+ const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
135
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
136
+ }
187
137
  function extractDocumentation(el) {
188
138
  const [doc] = asElements(el.documentation);
189
139
  return asString(doc?.text);
@@ -362,6 +312,35 @@ function extractAranzaExtensions(el) {
362
312
  if (owner) result.owner = owner;
363
313
  const sla = asString(taskConfig.sla);
364
314
  if (sla) result.sla = sla;
315
+ const serviceConfig = {};
316
+ const implementation = asString(taskConfig.implementation);
317
+ if (implementation === "none" || implementation === "connector" || implementation === "http" || implementation === "webService") {
318
+ serviceConfig.implementation = implementation;
319
+ }
320
+ const connectorInstanceId = asString(taskConfig.connectorInstanceId);
321
+ if (connectorInstanceId) serviceConfig.connectorInstanceId = connectorInstanceId;
322
+ const connectorId = asString(taskConfig.connectorId);
323
+ if (connectorId) serviceConfig.connectorId = connectorId;
324
+ const connectorAction = asString(taskConfig.connectorAction);
325
+ if (connectorAction) serviceConfig.connectorAction = connectorAction;
326
+ const connectorParamsJson = asString(taskConfig.connectorParamsJson);
327
+ if (connectorParamsJson) {
328
+ try {
329
+ const parsed = JSON.parse(connectorParamsJson);
330
+ const connectorParams = asStringRecord(parsed);
331
+ if (connectorParams) serviceConfig.connectorParams = connectorParams;
332
+ } catch {
333
+ }
334
+ }
335
+ const httpMethod = asString(taskConfig.httpMethod);
336
+ if (httpMethod === "GET" || httpMethod === "POST" || httpMethod === "PUT" || httpMethod === "DELETE" || httpMethod === "PATCH") {
337
+ serviceConfig.httpMethod = httpMethod;
338
+ }
339
+ const endpoint = asString(taskConfig.endpoint);
340
+ if (endpoint) serviceConfig.endpoint = endpoint;
341
+ const operationRef = asString(taskConfig.operationRef);
342
+ if (operationRef) serviceConfig.operationRef = operationRef;
343
+ if (Object.keys(serviceConfig).length > 0) result.serviceConfig = serviceConfig;
365
344
  const connector = asString(taskConfig.connector);
366
345
  if (connector) result.connector = connector;
367
346
  const action = asString(taskConfig.action);
@@ -454,6 +433,7 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
454
433
  const completionCondition = elementType === "AdHocSubProcess" ? extractCompletionCondition(el) : void 0;
455
434
  const loopChars = extractLoopCharacteristics(el);
456
435
  const dataObjectRef = elementType === "DataObjectReference" ? asString(el.dataObjectRef?.id) : void 0;
436
+ const dataStoreRef = elementType === "DataStoreReference" ? asString(el.dataStoreRef?.id) : void 0;
457
437
  const data = {
458
438
  elementType,
459
439
  ...label ? { label } : {},
@@ -475,6 +455,7 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
475
455
  ...script ? { script } : {},
476
456
  ...completionCondition ? { completionCondition } : {},
477
457
  ...dataObjectRef ? { dataObjectRef } : {},
458
+ ...dataStoreRef ? { dataStoreRef } : {},
478
459
  ...loopChars,
479
460
  ...aranzaExt
480
461
  };
@@ -631,9 +612,10 @@ async function parseBpmnXml(xml) {
631
612
  }
632
613
  }
633
614
  const defaultFlowById = /* @__PURE__ */ new Set();
615
+ const defaultFlowBySourceId = /* @__PURE__ */ new Map();
634
616
  const nodeIds = new Set(nodes.map((node) => node.id));
635
617
  for (const rootEl of asElements(rootElement.rootElements)) {
636
- collectDefaultFlows(rootEl, defaultFlowById);
618
+ collectDefaultFlows(rootEl, defaultFlowById, defaultFlowBySourceId);
637
619
  }
638
620
  const normalizedEdges = edges.map((edge) => {
639
621
  if (!defaultFlowById.has(edge.id)) return edge;
@@ -656,18 +638,36 @@ async function parseBpmnXml(xml) {
656
638
  if (importedDefinitions) importedProcess.definitions = importedDefinitions;
657
639
  return importedProcess;
658
640
  })() : importedDefinitions ? { definitions: importedDefinitions } : void 0;
641
+ const normalizedNodes = normalizeChildPositions(nodes, nodeIds).map((node) => {
642
+ const defaultFlowId = defaultFlowBySourceId.get(node.id);
643
+ if (!defaultFlowId) return node;
644
+ return {
645
+ ...node,
646
+ data: {
647
+ ...node.data,
648
+ default: defaultFlowId
649
+ }
650
+ };
651
+ });
659
652
  return {
660
- nodes: normalizeChildPositions(nodes, nodeIds),
653
+ nodes: normalizedNodes,
661
654
  edges: normalizedEdges,
662
655
  warnings,
663
656
  ...process ? { process } : {}
664
657
  };
665
658
  }
666
- function collectDefaultFlows(el, defaultFlowById) {
659
+ function collectDefaultFlows(el, defaultFlowById, defaultFlowBySourceId) {
667
660
  const defaultRef = el.default;
668
- if (defaultRef?.id) defaultFlowById.add(defaultRef.id);
669
- for (const child of asElements(el.rootElements)) collectDefaultFlows(child, defaultFlowById);
670
- for (const child of asElements(el.flowElements)) collectDefaultFlows(child, defaultFlowById);
661
+ if (defaultRef?.id) {
662
+ defaultFlowById.add(defaultRef.id);
663
+ if (el.id) defaultFlowBySourceId.set(el.id, defaultRef.id);
664
+ }
665
+ for (const child of asElements(el.rootElements)) {
666
+ collectDefaultFlows(child, defaultFlowById, defaultFlowBySourceId);
667
+ }
668
+ for (const child of asElements(el.flowElements)) {
669
+ collectDefaultFlows(child, defaultFlowById, defaultFlowBySourceId);
670
+ }
671
671
  }
672
672
  function normalizeChildPositions(nodes, nodeIds) {
673
673
  const absoluteById = new Map(nodes.map((node) => [node.id, node.position]));
@@ -728,6 +728,12 @@ function parseVariableType2(type) {
728
728
  return "xsd:string";
729
729
  }
730
730
  }
731
+ function escapeXml(text) {
732
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
733
+ }
734
+ function escapeRegex(text) {
735
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
736
+ }
731
737
  function buildGlobalDefinitions(moddle, definitionsSet) {
732
738
  if (!definitionsSet) return [];
733
739
  const rootElements = [];
@@ -753,6 +759,33 @@ function buildGlobalDefinitions(moddle, definitionsSet) {
753
759
  }
754
760
  return rootElements;
755
761
  }
762
+ function collectReferencedDataStoreIds(nodes) {
763
+ const ids = /* @__PURE__ */ new Set();
764
+ for (const node of nodes) {
765
+ if (node.data.elementType !== "DataStoreReference") continue;
766
+ const explicitRef = typeof node.data.dataStoreRef === "string" ? node.data.dataStoreRef : `DataStore_${node.id}`;
767
+ ids.add(explicitRef);
768
+ }
769
+ return ids;
770
+ }
771
+ function buildGlobalDataStores(moddle, nodes) {
772
+ const referencedIds = collectReferencedDataStoreIds(nodes);
773
+ if (referencedIds.size === 0) return [];
774
+ const byId = new Map(nodes.map((node) => [node.id, node]));
775
+ const rootElements = [];
776
+ for (const id of referencedIds) {
777
+ const existing = byId.get(id);
778
+ if (existing?.data.elementType === "DataStore") {
779
+ rootElements.push(moddle.create("bpmn:DataStore", {
780
+ id,
781
+ name: existing.data.label ?? ""
782
+ }));
783
+ continue;
784
+ }
785
+ rootElements.push(moddle.create("bpmn:DataStore", { id }));
786
+ }
787
+ return rootElements;
788
+ }
756
789
  function buildItemDefinitions(moddle, variables) {
757
790
  return (variables ?? []).map(
758
791
  (variable) => moddle.create("bpmn:ItemDefinition", {
@@ -786,38 +819,41 @@ function buildEventDefinitions(moddle, node, eventDefinition) {
786
819
  return [moddle.create(defType, attrs)];
787
820
  }
788
821
  function buildAranzaExtensionElements(moddle, node) {
789
- const { priority, owner, sla } = node.data;
790
- const connector = typeof node.data.connector === "string" ? node.data.connector : void 0;
791
- const action = typeof node.data.action === "string" ? node.data.action : void 0;
792
- const flowableType = typeof node.data.flowableType === "string" ? node.data.flowableType : void 0;
793
- const flowableDelegateExpression = typeof node.data.flowableDelegateExpression === "string" ? node.data.flowableDelegateExpression : void 0;
794
- const decisionRef = typeof node.data.decisionRef === "string" ? node.data.decisionRef : void 0;
795
- const formKey = typeof node.data.formKey === "string" ? node.data.formKey : void 0;
796
- const candidateUsers = typeof node.data.candidateUsers === "string" ? node.data.candidateUsers : void 0;
797
- const candidateGroups = typeof node.data.candidateGroups === "string" ? node.data.candidateGroups : void 0;
798
- const dueDate = typeof node.data.dueDate === "string" ? node.data.dueDate : void 0;
799
- const skipExpression = typeof node.data.skipExpression === "string" ? node.data.skipExpression : void 0;
800
- const businessCalendarName = typeof node.data.businessCalendarName === "string" ? node.data.businessCalendarName : void 0;
801
- if (!priority && !owner && !sla && !connector && !action && !flowableType && !flowableDelegateExpression && !decisionRef && !formKey && !candidateUsers && !candidateGroups && !dueDate && !skipExpression && !businessCalendarName) {
822
+ const ext = getBpmnTaskExecutionExtensions(node.data);
823
+ if (!ext) {
802
824
  return null;
803
825
  }
804
826
  const configAttrs = {};
805
- if (priority) configAttrs.priority = priority;
806
- if (owner) configAttrs.owner = owner;
807
- if (sla) configAttrs.sla = sla;
808
- if (connector) configAttrs.connector = connector;
809
- if (action) configAttrs.action = action;
810
- if (flowableType) configAttrs.flowableType = flowableType;
811
- if (flowableDelegateExpression) configAttrs.flowableDelegateExpression = flowableDelegateExpression;
812
- if (decisionRef) configAttrs.decisionRef = decisionRef;
813
- if (formKey) configAttrs.formKey = formKey;
814
- if (candidateUsers) configAttrs.candidateUsers = candidateUsers;
815
- if (candidateGroups) configAttrs.candidateGroups = candidateGroups;
816
- if (dueDate) configAttrs.dueDate = dueDate;
817
- if (skipExpression) configAttrs.skipExpression = skipExpression;
818
- if (businessCalendarName) configAttrs.businessCalendarName = businessCalendarName;
827
+ if (ext.priority) configAttrs.priority = ext.priority;
828
+ if (ext.owner) configAttrs.owner = ext.owner;
829
+ if (ext.sla) configAttrs.sla = ext.sla;
830
+ if (ext.serviceConfig?.implementation) configAttrs.implementation = ext.serviceConfig.implementation;
831
+ if (ext.serviceConfig?.connectorInstanceId) {
832
+ configAttrs.connectorInstanceId = ext.serviceConfig.connectorInstanceId;
833
+ }
834
+ if (ext.serviceConfig?.connectorId) configAttrs.connectorId = ext.serviceConfig.connectorId;
835
+ if (ext.serviceConfig?.connectorAction) {
836
+ configAttrs.connectorAction = ext.serviceConfig.connectorAction;
837
+ }
838
+ if (ext.serviceConfig?.connectorParams && Object.keys(ext.serviceConfig.connectorParams).length > 0) {
839
+ configAttrs.connectorParamsJson = JSON.stringify(ext.serviceConfig.connectorParams);
840
+ }
841
+ if (ext.serviceConfig?.httpMethod) configAttrs.httpMethod = ext.serviceConfig.httpMethod;
842
+ if (ext.serviceConfig?.endpoint) configAttrs.endpoint = ext.serviceConfig.endpoint;
843
+ if (ext.serviceConfig?.operationRef) configAttrs.operationRef = ext.serviceConfig.operationRef;
844
+ if (ext.connector) configAttrs.connector = ext.connector;
845
+ if (ext.action) configAttrs.action = ext.action;
846
+ if (ext.flowableType) configAttrs.flowableType = ext.flowableType;
847
+ if (ext.flowableDelegateExpression) configAttrs.flowableDelegateExpression = ext.flowableDelegateExpression;
848
+ if (ext.decisionRef) configAttrs.decisionRef = ext.decisionRef;
849
+ if (ext.formKey) configAttrs.formKey = ext.formKey;
850
+ if (ext.candidateUsers) configAttrs.candidateUsers = ext.candidateUsers;
851
+ if (ext.candidateGroups) configAttrs.candidateGroups = ext.candidateGroups;
852
+ if (ext.dueDate) configAttrs.dueDate = ext.dueDate;
853
+ if (ext.skipExpression) configAttrs.skipExpression = ext.skipExpression;
854
+ if (ext.businessCalendarName) configAttrs.businessCalendarName = ext.businessCalendarName;
819
855
  const values = [moddle.create("aranza:TaskConfig", configAttrs)];
820
- const inlineDecisionTable = node.data.inlineDecisionTable;
856
+ const inlineDecisionTable = ext.inlineDecisionTable;
821
857
  if (inlineDecisionTable && typeof inlineDecisionTable === "object") {
822
858
  const tbl = inlineDecisionTable;
823
859
  const { hitPolicy, ...rest } = tbl;
@@ -837,13 +873,15 @@ function buildSemanticModel(moddle, nodes, edges, opts) {
837
873
  const poolNodes = asNodes(nodes, ["Pool"]);
838
874
  const laneNodes = asNodes(nodes, ["Lane"]);
839
875
  const isCollaboration = poolNodes.length > 0;
876
+ const referencedDataStoreIds = collectReferencedDataStoreIds(nodes);
840
877
  const definitions = moddle.create("bpmn:Definitions", {
841
878
  id: defId,
842
879
  targetNamespace: "http://bpmn.io/schema/bpmn",
843
880
  ...defName ? { name: defName } : {}
844
881
  });
845
882
  const rootElements = [
846
- ...buildGlobalDefinitions(moddle, opts.process?.definitions)
883
+ ...buildGlobalDefinitions(moddle, opts.process?.definitions),
884
+ ...buildGlobalDataStores(moddle, nodes)
847
885
  ];
848
886
  const itemDefinitions = buildItemDefinitions(moddle, opts.process?.definitions?.variables);
849
887
  if (itemDefinitions.length > 0) {
@@ -854,7 +892,7 @@ function buildSemanticModel(moddle, nodes, edges, opts) {
854
892
  const processes = [];
855
893
  for (const pool of poolNodes) {
856
894
  const processId = `Process_${pool.id}`;
857
- const process = buildProcess(moddle, nodes, edges, pool.id, laneNodes, processId, opts);
895
+ const process = buildProcess(moddle, nodes, edges, pool.id, laneNodes, processId, opts, referencedDataStoreIds);
858
896
  processes.push(process);
859
897
  const participant = moddle.create("bpmn:Participant", {
860
898
  id: pool.id,
@@ -866,18 +904,17 @@ function buildSemanticModel(moddle, nodes, edges, opts) {
866
904
  const messageFlowEdges = edges.filter((e) => e.data?.edgeType === "messageFlow");
867
905
  const conversationLinkEdges = edges.filter((e) => e.data?.edgeType === "conversationLink");
868
906
  const messageFlows = messageFlowEdges.map((e) => {
869
- const ps = typeof e.data?.payloadSchema === "string" ? e.data.payloadSchema : void 0;
870
- const ck = typeof e.data?.correlationKey === "string" ? e.data.correlationKey : void 0;
907
+ const ext = e.data ? getBpmnMessageFlowExecutionExtensions(e.data) : void 0;
871
908
  const mfAttrs = {
872
909
  id: e.id,
873
910
  name: e.data?.label ?? "",
874
911
  sourceRef: { id: e.source },
875
912
  targetRef: { id: e.target }
876
913
  };
877
- if (ps || ck) {
914
+ if (ext?.payloadSchema || ext?.correlationKey) {
878
915
  const cfg = moddle.create("aranza:MessageFlowConfig", {
879
- ...ps ? { payloadSchema: ps } : {},
880
- ...ck ? { correlationKey: ck } : {}
916
+ ...ext.payloadSchema ? { payloadSchema: ext.payloadSchema } : {},
917
+ ...ext.correlationKey ? { correlationKey: ext.correlationKey } : {}
881
918
  });
882
919
  mfAttrs.extensionElements = moddle.create("bpmn:ExtensionElements", { values: [cfg] });
883
920
  }
@@ -905,14 +942,15 @@ function buildSemanticModel(moddle, nodes, edges, opts) {
905
942
  void 0,
906
943
  laneNodes,
907
944
  opts.process?.processId ?? "Process_1",
908
- opts
945
+ opts,
946
+ referencedDataStoreIds
909
947
  );
910
948
  rootElements.push(process);
911
949
  }
912
950
  definitions.rootElements = rootElements;
913
951
  return definitions;
914
952
  }
915
- function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId, opts) {
953
+ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId, opts, referencedDataStoreIds) {
916
954
  const subProcessIds = new Set(
917
955
  allNodes.filter(
918
956
  (n) => n.data.elementType === "SubProcess" || n.data.elementType === "Transaction" || n.data.elementType === "EventSubProcess" || n.data.elementType === "AdHocSubProcess"
@@ -934,7 +972,7 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId,
934
972
  }
935
973
  return false;
936
974
  };
937
- const myNodes = (poolId ? allNodes.filter((n) => belongsToPool(n)) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane")).filter((n) => !isInsideSubProcess(n));
975
+ const myNodes = (poolId ? allNodes.filter((n) => belongsToPool(n)) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane")).filter((n) => !isInsideSubProcess(n)).filter((n) => !(n.data.elementType === "DataStore" && referencedDataStoreIds.has(n.id)));
938
976
  const myLanes = laneNodes.filter((l) => poolId ? l.parentId === poolId : true);
939
977
  const presentDataObjectIds = new Set(
940
978
  myNodes.filter((n) => n.data.elementType === "DataObject").map((n) => n.id)
@@ -978,10 +1016,18 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId,
978
1016
  const elementById = new Map(
979
1017
  flowElements.filter((element) => typeof element.id === "string").map((element) => [element.id, element])
980
1018
  );
1019
+ const defaultEdgeBySource = /* @__PURE__ */ new Map();
1020
+ for (const node of myNodes) {
1021
+ const defaultFlowId = typeof node.data.default === "string" ? node.data.default : void 0;
1022
+ if (defaultFlowId) defaultEdgeBySource.set(node.id, defaultFlowId);
1023
+ }
981
1024
  for (const edge of myEdges) {
982
- if (!edge.data?.isDefault) continue;
983
- const sourceElement = elementById.get(edge.source);
984
- const edgeElement = elementById.get(edge.id);
1025
+ if (!edge.data?.isDefault || defaultEdgeBySource.has(edge.source)) continue;
1026
+ defaultEdgeBySource.set(edge.source, edge.id);
1027
+ }
1028
+ for (const [sourceId, edgeId] of defaultEdgeBySource) {
1029
+ const sourceElement = elementById.get(sourceId);
1030
+ const edgeElement = elementById.get(edgeId);
985
1031
  if (sourceElement && edgeElement) {
986
1032
  sourceElement.default = edgeElement;
987
1033
  }
@@ -1048,6 +1094,10 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
1048
1094
  const refId = typeof node.data.dataObjectRef === "string" ? node.data.dataObjectRef : `DataObject_${node.id}`;
1049
1095
  attrs.dataObjectRef = { id: refId };
1050
1096
  }
1097
+ if (elementType === "DataStoreReference") {
1098
+ const refId = typeof node.data.dataStoreRef === "string" ? node.data.dataStoreRef : `DataStore_${node.id}`;
1099
+ attrs.dataStoreRef = { id: refId };
1100
+ }
1051
1101
  if (elementType === "ScriptTask") {
1052
1102
  const scriptFormat = typeof node.data.scriptFormat === "string" ? node.data.scriptFormat : void 0;
1053
1103
  const script = typeof node.data.script === "string" ? node.data.script : void 0;
@@ -1109,7 +1159,8 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
1109
1159
  return element;
1110
1160
  }
1111
1161
  function buildNestedFlowElements(moddle, parent, allNodes, allEdges) {
1112
- const childNodes = allNodes.filter((node) => node.parentId === parent.id);
1162
+ const referencedDataStoreIds = collectReferencedDataStoreIds(allNodes);
1163
+ const childNodes = allNodes.filter((node) => node.parentId === parent.id).filter((node) => !(node.data.elementType === "DataStore" && referencedDataStoreIds.has(node.id)));
1113
1164
  const childNodeIds = new Set(childNodes.map((node) => node.id));
1114
1165
  const flowElements = [];
1115
1166
  const artifacts = [];
@@ -1263,6 +1314,124 @@ function buildAbsolutePositionMap(nodes) {
1263
1314
  for (const node of nodes) resolve(node);
1264
1315
  return absoluteById;
1265
1316
  }
1317
+ function getServiceTaskConfig(node, opts) {
1318
+ const override = opts.flowable?.serviceTaskConfigs?.[node.id];
1319
+ if (override) return override;
1320
+ const config = node.data.serviceConfig;
1321
+ return config && typeof config === "object" ? config : void 0;
1322
+ }
1323
+ function injectFlowableNamespace(xml) {
1324
+ if (xml.includes("xmlns:flowable=")) return xml;
1325
+ return xml.replace(
1326
+ "<bpmn:definitions",
1327
+ '<bpmn:definitions xmlns:flowable="http://flowable.org/bpmn"'
1328
+ );
1329
+ }
1330
+ function ensureOpeningTagAttribute(openTag, name, value) {
1331
+ if (new RegExp(`\\b${escapeRegex(name)}=`).test(openTag)) return openTag;
1332
+ return openTag.replace(/>$/, ` ${name}="${escapeXml(value)}">`);
1333
+ }
1334
+ function injectFlowableFieldsIntoElement(xml, elementTagName, nodeId, fieldsXml, flowableType) {
1335
+ const idPattern = escapeRegex(nodeId);
1336
+ const selfClosingPattern = new RegExp(
1337
+ `<bpmn:${elementTagName}\\b[^>]*?\\bid="${idPattern}"[^>]*/>`,
1338
+ "s"
1339
+ );
1340
+ const blockPattern = new RegExp(
1341
+ `<bpmn:${elementTagName}\\b[^>]*?\\bid="${idPattern}"[^>]*>[\\s\\S]*?<\\/bpmn:${elementTagName}>`,
1342
+ "s"
1343
+ );
1344
+ if (selfClosingPattern.test(xml)) {
1345
+ return xml.replace(selfClosingPattern, (match) => {
1346
+ const openTag = ensureOpeningTagAttribute(match.replace(/\/>$/, ">"), "flowable:type", flowableType);
1347
+ return `${openTag}
1348
+ <bpmn:extensionElements>
1349
+ ${fieldsXml}
1350
+ </bpmn:extensionElements>
1351
+ </bpmn:${elementTagName}>`;
1352
+ });
1353
+ }
1354
+ return xml.replace(blockPattern, (block) => {
1355
+ const openTagMatch = block.match(new RegExp(`^<bpmn:${elementTagName}\\b[^>]*>`, "s"));
1356
+ if (!openTagMatch) return block;
1357
+ const openTag = ensureOpeningTagAttribute(openTagMatch[0], "flowable:type", flowableType);
1358
+ let nextBlock = openTag + block.slice(openTagMatch[0].length);
1359
+ if (nextBlock.includes("<bpmn:extensionElements>")) {
1360
+ return nextBlock.replace(
1361
+ /<bpmn:extensionElements>([\s\S]*?)<\/bpmn:extensionElements>/,
1362
+ (_match, inner) => `<bpmn:extensionElements>${inner.trimEnd()}
1363
+ ${fieldsXml}
1364
+ </bpmn:extensionElements>`
1365
+ );
1366
+ }
1367
+ return nextBlock.replace(
1368
+ openTag,
1369
+ `${openTag}
1370
+ <bpmn:extensionElements>
1371
+ ${fieldsXml}
1372
+ </bpmn:extensionElements>`
1373
+ );
1374
+ });
1375
+ }
1376
+ function injectFlowableConnectorServiceTasks(xml, nodes, opts) {
1377
+ let result = xml;
1378
+ const backendUrlTemplate = opts.flowable?.backendUrlTemplate ?? "%%ARANZAFLOWS_BACKEND_URL%%";
1379
+ const responseVariableName = opts.flowable?.connectorResponseVariableName ?? "connectorResult";
1380
+ for (const node of nodes) {
1381
+ if (node.data.elementType !== "ServiceTask") continue;
1382
+ const cfg = getServiceTaskConfig(node, opts);
1383
+ if (cfg?.implementation !== "connector" || !cfg.connectorInstanceId || !cfg.connectorAction) {
1384
+ continue;
1385
+ }
1386
+ result = injectFlowableNamespace(result);
1387
+ const bodyObj = {
1388
+ action: cfg.connectorAction,
1389
+ params: cfg.connectorParams ?? {}
1390
+ };
1391
+ const url = `${backendUrlTemplate}/api/v1/integrations/${encodeURIComponent(cfg.connectorInstanceId)}/execute-internal`;
1392
+ const fieldsXml = [
1393
+ ' <flowable:field name="requestMethod"><flowable:string>POST</flowable:string></flowable:field>',
1394
+ ` <flowable:field name="requestUrl"><flowable:string>${escapeXml(url)}</flowable:string></flowable:field>`,
1395
+ ' <flowable:field name="requestHeaders"><flowable:string>Content-Type: application/json</flowable:string></flowable:field>',
1396
+ ` <flowable:field name="requestBody"><flowable:expression>${escapeXml(JSON.stringify(bodyObj))}</flowable:expression></flowable:field>`,
1397
+ ` <flowable:field name="responseVariableName"><flowable:string>${escapeXml(responseVariableName)}</flowable:string></flowable:field>`,
1398
+ ' <flowable:field name="saveResponseParameters"><flowable:string>false</flowable:string></flowable:field>'
1399
+ ].join("\n");
1400
+ result = injectFlowableFieldsIntoElement(result, "serviceTask", node.id, fieldsXml, "http");
1401
+ }
1402
+ return result;
1403
+ }
1404
+ function injectFlowableDecisionTasks(xml, nodes, opts) {
1405
+ let result = xml;
1406
+ const variables = opts.process?.definitions?.variables ?? [];
1407
+ const backendUrlTemplate = opts.flowable?.backendUrlTemplate ?? "%%ARANZAFLOWS_BACKEND_URL%%";
1408
+ const responseVariableName = opts.flowable?.decisionResponseVariableName ?? "decisionResult";
1409
+ for (const node of nodes) {
1410
+ if (node.data.elementType !== "BusinessRuleTask") continue;
1411
+ const decisionRef = typeof node.data.decisionRef === "string" ? node.data.decisionRef : void 0;
1412
+ if (!decisionRef) continue;
1413
+ result = injectFlowableNamespace(result);
1414
+ const url = `${backendUrlTemplate}/api/v1/decisions/${encodeURIComponent(decisionRef)}/evaluate-internal`;
1415
+ const bodyField = variables.length > 0 ? `<flowable:expression>${escapeXml(
1416
+ `{${variables.map((variable) => `"${variable.name}": \${${variable.name}}`).join(", ")}}`
1417
+ )}</flowable:expression>` : "<flowable:string>{}</flowable:string>";
1418
+ const fieldsXml = [
1419
+ ' <flowable:field name="requestMethod"><flowable:string>POST</flowable:string></flowable:field>',
1420
+ ` <flowable:field name="requestUrl"><flowable:string>${escapeXml(url)}</flowable:string></flowable:field>`,
1421
+ ' <flowable:field name="requestHeaders"><flowable:string>Content-Type: application/json</flowable:string></flowable:field>',
1422
+ ` <flowable:field name="requestBody">${bodyField}</flowable:field>`,
1423
+ ` <flowable:field name="responseVariableName"><flowable:string>${escapeXml(responseVariableName)}</flowable:string></flowable:field>`,
1424
+ ' <flowable:field name="saveResponseParameters"><flowable:string>false</flowable:string></flowable:field>'
1425
+ ].join("\n");
1426
+ result = injectFlowableFieldsIntoElement(result, "businessRuleTask", node.id, fieldsXml, "http");
1427
+ }
1428
+ return result;
1429
+ }
1430
+ function applyFlowableExportEnrichment(xml, nodes, opts) {
1431
+ if (!opts.flowable?.enabled) return xml;
1432
+ const withServiceTasks = injectFlowableConnectorServiceTasks(xml, nodes, opts);
1433
+ return injectFlowableDecisionTasks(withServiceTasks, nodes, opts);
1434
+ }
1266
1435
  async function serializeBpmnXml(nodes, edges, opts = {}) {
1267
1436
  const { BpmnModdle } = await import('bpmn-moddle');
1268
1437
  const moddle = new BpmnModdle({ aranza: ARANZA_DESCRIPTOR });
@@ -1271,9 +1440,9 @@ async function serializeBpmnXml(nodes, edges, opts = {}) {
1271
1440
  const { xml } = await moddle.toXML(definitions, {
1272
1441
  format: opts.format ?? true
1273
1442
  });
1274
- return xml;
1443
+ return applyFlowableExportEnrichment(xml, nodes, opts);
1275
1444
  }
1276
1445
 
1277
1446
  export { parseBpmnXml, serializeBpmnXml };
1278
- //# sourceMappingURL=chunk-YUE5EM3W.js.map
1279
- //# sourceMappingURL=chunk-YUE5EM3W.js.map
1447
+ //# sourceMappingURL=chunk-334WN4JZ.js.map
1448
+ //# sourceMappingURL=chunk-334WN4JZ.js.map