@bpmnkit/proxy 0.0.8

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/bridge.js ADDED
@@ -0,0 +1,226 @@
1
+ /**
2
+ * QuickJS bridge — exposes all @bpmnkit/core operations as globalThis.Bridge.* functions.
3
+ * Bundled as an IIFE (platform=neutral) and embedded in the Rust binaries via rquickjs.
4
+ * All inputs/outputs are JSON strings or primitives.
5
+ */
6
+ import { Bpmn, compactify, expand, layoutProcess, optimize, } from "@bpmnkit/core";
7
+ // ── MCP state (persists across calls within a single QuickJS runtime) ─────────
8
+ let __state = null;
9
+ // ── Helpers (ported from mcp-server.ts) ───────────────────────────────────────
10
+ function buildDiagram(proc) {
11
+ const layout = layoutProcess(proc);
12
+ const shapes = layout.nodes.map((n) => ({
13
+ id: `${n.id}_di`,
14
+ bpmnElement: n.id,
15
+ isExpanded: n.isExpanded,
16
+ bounds: n.bounds,
17
+ label: n.labelBounds ? { bounds: n.labelBounds } : undefined,
18
+ unknownAttributes: {},
19
+ }));
20
+ const edges = layout.edges.map((e) => ({
21
+ id: `${e.id}_di`,
22
+ bpmnElement: e.id,
23
+ waypoints: e.waypoints,
24
+ unknownAttributes: {},
25
+ }));
26
+ return {
27
+ id: `BPMNDiagram_${proc.id}`,
28
+ plane: {
29
+ id: `BPMNPlane_${proc.id}`,
30
+ bpmnElement: proc.id,
31
+ shapes,
32
+ edges,
33
+ },
34
+ };
35
+ }
36
+ function recomputeIncomingOutgoing(proc) {
37
+ const elementMap = new Map();
38
+ for (const el of proc.flowElements) {
39
+ el.incoming = [];
40
+ el.outgoing = [];
41
+ elementMap.set(el.id, el);
42
+ }
43
+ for (const sf of proc.sequenceFlows) {
44
+ const src = elementMap.get(sf.sourceRef);
45
+ const tgt = elementMap.get(sf.targetRef);
46
+ if (src)
47
+ src.outgoing.push(sf.id);
48
+ if (tgt)
49
+ tgt.incoming.push(sf.id);
50
+ }
51
+ }
52
+ function findProcess(processId) {
53
+ return __state?.processes.find((p) => p.id === processId);
54
+ }
55
+ function ensureProcess(processId) {
56
+ const existing = __state?.processes.find((p) => p.id === processId);
57
+ if (existing)
58
+ return existing;
59
+ const proc = {
60
+ id: processId,
61
+ isExecutable: true,
62
+ extensionElements: [],
63
+ flowElements: [],
64
+ sequenceFlows: [],
65
+ textAnnotations: [],
66
+ associations: [],
67
+ unknownAttributes: {},
68
+ };
69
+ __state?.processes.push(proc);
70
+ return proc;
71
+ }
72
+ // ── Bridge API ─────────────────────────────────────────────────────────────────
73
+ ;
74
+ globalThis.Bridge = {
75
+ // ── HTTP server (stateless) ────────────────────────────────────────────────
76
+ /** Expand a CompactDiagram JSON string and export as BPMN XML. */
77
+ expandAndExport(compactJson) {
78
+ return Bpmn.export(expand(JSON.parse(compactJson)));
79
+ },
80
+ /** Run optimize() on expanded compact, return findings as JSON string. */
81
+ optimizeFindings(compactJson) {
82
+ const report = optimize(expand(JSON.parse(compactJson)));
83
+ return JSON.stringify(report.findings.map((f) => ({
84
+ category: f.category,
85
+ severity: f.severity,
86
+ message: f.message,
87
+ suggestion: f.suggestion,
88
+ elementIds: f.elementIds,
89
+ })));
90
+ },
91
+ // ── MCP server (stateful — __state persists in QuickJS runtime) ───────────
92
+ /** Initialize MCP state from optional BPMN XML (or create empty diagram). */
93
+ mcpInit(xml) {
94
+ __state = Bpmn.parse(xml ?? Bpmn.makeEmpty("Process_1", "New Process"));
95
+ },
96
+ /** Return current diagram as CompactDiagram JSON string. */
97
+ mcpGetDiagram() {
98
+ if (!__state)
99
+ throw new Error("mcpInit not called");
100
+ return JSON.stringify(compactify(__state), null, 2);
101
+ },
102
+ /** Export current state as BPMN XML (rebuilds diagrams before export). */
103
+ mcpExportXml() {
104
+ if (!__state)
105
+ throw new Error("mcpInit not called");
106
+ __state.diagrams = __state.processes.map(buildDiagram);
107
+ return Bpmn.export(__state);
108
+ },
109
+ /** Add elements and flows to a process. Returns result message. */
110
+ mcpAddElements(processId, elementsJson, flowsJson) {
111
+ const proc = ensureProcess(processId);
112
+ const elements = JSON.parse(elementsJson);
113
+ const flows = JSON.parse(flowsJson);
114
+ const miniCompact = {
115
+ id: "__temp__",
116
+ processes: [{ id: proc.id, elements, flows }],
117
+ };
118
+ const tempDefs = expand(miniCompact);
119
+ const tempProc = tempDefs.processes[0];
120
+ if (!tempProc)
121
+ return "Failed to expand elements.";
122
+ let addedEls = 0;
123
+ let addedFlows = 0;
124
+ for (const el of tempProc.flowElements) {
125
+ if (!proc.flowElements.some((e) => e.id === el.id)) {
126
+ proc.flowElements.push(el);
127
+ addedEls++;
128
+ }
129
+ }
130
+ for (const sf of tempProc.sequenceFlows) {
131
+ if (!proc.sequenceFlows.some((f) => f.id === sf.id)) {
132
+ proc.sequenceFlows.push(sf);
133
+ addedFlows++;
134
+ }
135
+ }
136
+ recomputeIncomingOutgoing(proc);
137
+ return `Added ${addedEls} element(s) and ${addedFlows} flow(s) to ${processId}.`;
138
+ },
139
+ /** Remove elements and flows from a process. Returns result message. */
140
+ mcpRemoveElements(processId, elementIdsJson, flowIdsJson) {
141
+ const proc = findProcess(processId);
142
+ if (!proc)
143
+ return `Process ${processId} not found.`;
144
+ const dropEls = new Set(JSON.parse(elementIdsJson));
145
+ const dropFlows = new Set(JSON.parse(flowIdsJson));
146
+ const removedEls = proc.flowElements.filter((e) => dropEls.has(e.id)).length;
147
+ proc.flowElements = proc.flowElements.filter((e) => !dropEls.has(e.id));
148
+ const removedFlows = proc.sequenceFlows.filter((f) => dropFlows.has(f.id) || dropEls.has(f.sourceRef) || dropEls.has(f.targetRef)).length;
149
+ proc.sequenceFlows = proc.sequenceFlows.filter((f) => !dropFlows.has(f.id) && !dropEls.has(f.sourceRef) && !dropEls.has(f.targetRef));
150
+ recomputeIncomingOutgoing(proc);
151
+ return `Removed ${removedEls} element(s) and ${removedFlows} flow(s).`;
152
+ },
153
+ /** Update element name. Returns result message. */
154
+ mcpUpdateElement(processId, elementId, changesJson) {
155
+ const proc = findProcess(processId);
156
+ if (!proc)
157
+ return `Process ${processId} not found.`;
158
+ const el = proc.flowElements.find((e) => e.id === elementId);
159
+ if (!el)
160
+ return `Element ${elementId} not found in ${processId}.`;
161
+ const changes = JSON.parse(changesJson);
162
+ if (changes.name !== undefined)
163
+ el.name = changes.name;
164
+ return `Updated element ${elementId}.`;
165
+ },
166
+ /** Set or clear condition on a sequence flow. Returns result message. */
167
+ mcpSetCondition(processId, flowId, conditionJson) {
168
+ const proc = findProcess(processId);
169
+ if (!proc)
170
+ return `Process ${processId} not found.`;
171
+ const sf = proc.sequenceFlows.find((f) => f.id === flowId);
172
+ if (!sf)
173
+ return `Flow ${flowId} not found in ${processId}.`;
174
+ const condition = JSON.parse(conditionJson);
175
+ if (condition === null) {
176
+ sf.conditionExpression = undefined;
177
+ }
178
+ else {
179
+ sf.conditionExpression = { text: condition, attributes: {} };
180
+ }
181
+ return `Condition set on flow ${flowId}.`;
182
+ },
183
+ /** Replace the entire diagram from CompactDiagram JSON. */
184
+ mcpReplaceDiagram(compactJson) {
185
+ __state = expand(JSON.parse(compactJson));
186
+ return "Diagram replaced.";
187
+ },
188
+ /**
189
+ * Execute arbitrary JavaScript in this context (code mode).
190
+ * The code has access to Bridge.*, __state, Bpmn, expand, compactify, etc.
191
+ * Wrap multi-statement code with return; the last expression value is the result.
192
+ */
193
+ mcpExecuteCode(code) {
194
+ // biome-ignore lint/security/noGlobalEval: intentional — code mode runs LLM-generated JS in sandboxed QuickJS/vm context
195
+ const result = eval(`(function(){\n${code}\n})()`);
196
+ return typeof result === "string" ? result : JSON.stringify(result ?? null);
197
+ },
198
+ /** Add an HTTP connector task. Returns result message. */
199
+ mcpAddHttpCall(processId, configJson) {
200
+ const proc = ensureProcess(processId);
201
+ const args = JSON.parse(configJson);
202
+ const config = {
203
+ name: args.name,
204
+ method: args.method,
205
+ url: args.url,
206
+ };
207
+ if (args.headers)
208
+ config.headers = args.headers;
209
+ if (args.body)
210
+ config.body = args.body;
211
+ if (args.resultVariable)
212
+ config.resultVariable = args.resultVariable;
213
+ const tempDefs = Bpmn.createProcess("__temp__").restConnector(args.id, config).build();
214
+ const tempProc = tempDefs.processes[0];
215
+ const el = tempProc?.flowElements.find((e) => e.id === args.id);
216
+ if (!el)
217
+ return "Failed to create REST connector element.";
218
+ if (!proc.flowElements.some((e) => e.id === el.id)) {
219
+ el.incoming = [];
220
+ el.outgoing = [];
221
+ proc.flowElements.push(el);
222
+ }
223
+ return `Added HTTP task "${args.name}" (${args.method} ${args.url}).`;
224
+ },
225
+ };
226
+ //# sourceMappingURL=bridge.js.map