@memberjunction/core-actions 2.106.0 → 2.108.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 (95) hide show
  1. package/dist/config.d.ts +112 -0
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +34 -2
  4. package/dist/config.js.map +1 -1
  5. package/dist/custom/ai/find-best-agent.action.d.ts +53 -0
  6. package/dist/custom/ai/find-best-agent.action.d.ts.map +1 -0
  7. package/dist/custom/ai/find-best-agent.action.js +194 -0
  8. package/dist/custom/ai/find-best-agent.action.js.map +1 -0
  9. package/dist/custom/ai/summarize-content.action.d.ts +72 -0
  10. package/dist/custom/ai/summarize-content.action.d.ts.map +1 -0
  11. package/dist/custom/ai/summarize-content.action.js +296 -0
  12. package/dist/custom/ai/summarize-content.action.js.map +1 -0
  13. package/dist/custom/code-execution/execute-code.action.d.ts +61 -0
  14. package/dist/custom/code-execution/execute-code.action.d.ts.map +1 -0
  15. package/dist/custom/code-execution/execute-code.action.js +172 -0
  16. package/dist/custom/code-execution/execute-code.action.js.map +1 -0
  17. package/dist/custom/data/csv-parser.action.js +1 -1
  18. package/dist/custom/data/csv-parser.action.js.map +1 -1
  19. package/dist/custom/data/execute-research-query.action.d.ts +114 -0
  20. package/dist/custom/data/execute-research-query.action.d.ts.map +1 -0
  21. package/dist/custom/data/execute-research-query.action.js +520 -0
  22. package/dist/custom/data/execute-research-query.action.js.map +1 -0
  23. package/dist/custom/data/explore-database-schema.action.d.ts +95 -0
  24. package/dist/custom/data/explore-database-schema.action.d.ts.map +1 -0
  25. package/dist/custom/data/explore-database-schema.action.js +499 -0
  26. package/dist/custom/data/explore-database-schema.action.js.map +1 -0
  27. package/dist/custom/data/get-entity-details.action.d.ts +63 -0
  28. package/dist/custom/data/get-entity-details.action.d.ts.map +1 -0
  29. package/dist/custom/data/get-entity-details.action.js +284 -0
  30. package/dist/custom/data/get-entity-details.action.js.map +1 -0
  31. package/dist/custom/data/get-entity-list.action.d.ts +57 -0
  32. package/dist/custom/data/get-entity-list.action.d.ts.map +1 -0
  33. package/dist/custom/data/get-entity-list.action.js +177 -0
  34. package/dist/custom/data/get-entity-list.action.js.map +1 -0
  35. package/dist/custom/files/index.d.ts +2 -0
  36. package/dist/custom/files/index.d.ts.map +1 -1
  37. package/dist/custom/files/index.js +5 -1
  38. package/dist/custom/files/index.js.map +1 -1
  39. package/dist/custom/files/list-storage-providers.action.d.ts +52 -0
  40. package/dist/custom/files/list-storage-providers.action.d.ts.map +1 -0
  41. package/dist/custom/files/list-storage-providers.action.js +175 -0
  42. package/dist/custom/files/list-storage-providers.action.js.map +1 -0
  43. package/dist/custom/files/search-storage-files.action.d.ts +61 -0
  44. package/dist/custom/files/search-storage-files.action.d.ts.map +1 -0
  45. package/dist/custom/files/search-storage-files.action.js +183 -0
  46. package/dist/custom/files/search-storage-files.action.js.map +1 -0
  47. package/dist/custom/visualization/create-svg-chart.action.d.ts +97 -0
  48. package/dist/custom/visualization/create-svg-chart.action.d.ts.map +1 -0
  49. package/dist/custom/visualization/create-svg-chart.action.js +290 -0
  50. package/dist/custom/visualization/create-svg-chart.action.js.map +1 -0
  51. package/dist/custom/visualization/create-svg-diagram.action.d.ts +151 -0
  52. package/dist/custom/visualization/create-svg-diagram.action.d.ts.map +1 -0
  53. package/dist/custom/visualization/create-svg-diagram.action.js +764 -0
  54. package/dist/custom/visualization/create-svg-diagram.action.js.map +1 -0
  55. package/dist/custom/visualization/create-svg-infographic.action.d.ts +72 -0
  56. package/dist/custom/visualization/create-svg-infographic.action.d.ts.map +1 -0
  57. package/dist/custom/visualization/create-svg-infographic.action.js +343 -0
  58. package/dist/custom/visualization/create-svg-infographic.action.js.map +1 -0
  59. package/dist/custom/visualization/create-svg-network.action.d.ts +106 -0
  60. package/dist/custom/visualization/create-svg-network.action.d.ts.map +1 -0
  61. package/dist/custom/visualization/create-svg-network.action.js +651 -0
  62. package/dist/custom/visualization/create-svg-network.action.js.map +1 -0
  63. package/dist/custom/visualization/create-svg-word-cloud.action.d.ts +94 -0
  64. package/dist/custom/visualization/create-svg-word-cloud.action.d.ts.map +1 -0
  65. package/dist/custom/visualization/create-svg-word-cloud.action.js +422 -0
  66. package/dist/custom/visualization/create-svg-word-cloud.action.js.map +1 -0
  67. package/dist/custom/visualization/shared/svg-theming.d.ts +91 -0
  68. package/dist/custom/visualization/shared/svg-theming.d.ts.map +1 -0
  69. package/dist/custom/visualization/shared/svg-theming.js +235 -0
  70. package/dist/custom/visualization/shared/svg-theming.js.map +1 -0
  71. package/dist/custom/visualization/shared/svg-types.d.ts +338 -0
  72. package/dist/custom/visualization/shared/svg-types.d.ts.map +1 -0
  73. package/dist/custom/visualization/shared/svg-types.js +11 -0
  74. package/dist/custom/visualization/shared/svg-types.js.map +1 -0
  75. package/dist/custom/visualization/shared/svg-utils.d.ts +129 -0
  76. package/dist/custom/visualization/shared/svg-utils.d.ts.map +1 -0
  77. package/dist/custom/visualization/shared/svg-utils.js +287 -0
  78. package/dist/custom/visualization/shared/svg-utils.js.map +1 -0
  79. package/dist/custom/web/google-custom-search.action.d.ts +60 -0
  80. package/dist/custom/web/google-custom-search.action.d.ts.map +1 -0
  81. package/dist/custom/web/google-custom-search.action.js +378 -0
  82. package/dist/custom/web/google-custom-search.action.js.map +1 -0
  83. package/dist/custom/web/web-page-content.action.d.ts +24 -0
  84. package/dist/custom/web/web-page-content.action.d.ts.map +1 -1
  85. package/dist/custom/web/web-page-content.action.js +90 -9
  86. package/dist/custom/web/web-page-content.action.js.map +1 -1
  87. package/dist/generated/action_subclasses.d.ts +51 -3
  88. package/dist/generated/action_subclasses.d.ts.map +1 -1
  89. package/dist/generated/action_subclasses.js +174 -90
  90. package/dist/generated/action_subclasses.js.map +1 -1
  91. package/dist/index.d.ts +14 -0
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +44 -0
  94. package/dist/index.js.map +1 -1
  95. package/package.json +30 -11
@@ -0,0 +1,764 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || function (mod) {
25
+ if (mod && mod.__esModule) return mod;
26
+ var result = {};
27
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
+ __setModuleDefault(result, mod);
29
+ return result;
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.LoadCreateSVGDiagramAction = exports.CreateSVGDiagramAction = void 0;
33
+ const actions_1 = require("@memberjunction/actions");
34
+ const global_1 = require("@memberjunction/global");
35
+ const dagre = __importStar(require("@dagrejs/dagre"));
36
+ const d3Hierarchy = __importStar(require("d3-hierarchy"));
37
+ const svg_utils_1 = require("./shared/svg-utils");
38
+ const svg_theming_1 = require("./shared/svg-theming");
39
+ /**
40
+ * Action that generates SVG diagrams including flowcharts, org charts, and ER diagrams.
41
+ *
42
+ * This action provides server-side SVG generation for structured diagrams, designed for
43
+ * AI agents and workflows to create publication-quality visualizations from structured data.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // Flowchart example
48
+ * await runAction({
49
+ * ActionName: 'Create SVG Diagram',
50
+ * Params: [
51
+ * { Name: 'DiagramType', Value: 'flow' },
52
+ * { Name: 'Nodes', Value: JSON.stringify([
53
+ * { id: '1', kind: 'start', label: 'Start' },
54
+ * { id: '2', kind: 'process', label: 'Process Data' },
55
+ * { id: '3', kind: 'end', label: 'End' }
56
+ * ]) },
57
+ * { Name: 'Edges', Value: JSON.stringify([
58
+ * { from: '1', to: '2', label: 'Begin' },
59
+ * { from: '2', to: '3' }
60
+ * ]) },
61
+ * { Name: 'Direction', Value: 'TB' },
62
+ * { Name: 'Width', Value: '800' },
63
+ * { Name: 'Height', Value: '600' }
64
+ * ]
65
+ * });
66
+ *
67
+ * // Org chart example
68
+ * await runAction({
69
+ * ActionName: 'Create SVG Diagram',
70
+ * Params: [
71
+ * { Name: 'DiagramType', Value: 'org' },
72
+ * { Name: 'Nodes', Value: JSON.stringify({
73
+ * id: '1',
74
+ * label: 'CEO',
75
+ * role: 'Chief Executive Officer',
76
+ * children: [
77
+ * { id: '2', label: 'CTO', role: 'Technology' },
78
+ * { id: '3', label: 'CFO', role: 'Finance' }
79
+ * ]
80
+ * }) }
81
+ * ]
82
+ * });
83
+ * ```
84
+ */
85
+ let CreateSVGDiagramAction = class CreateSVGDiagramAction extends actions_1.BaseAction {
86
+ /**
87
+ * Generates an SVG diagram from the provided data and configuration
88
+ *
89
+ * @param params - The action parameters containing:
90
+ * - DiagramType: Type of diagram ('flow' | 'org' | 'er')
91
+ * - Nodes: JSON array or object of nodes
92
+ * - Edges: JSON array of edges (for flow and ER diagrams)
93
+ * - Direction: Layout direction ('TB' | 'LR' | 'RL' | 'BT') for flow diagrams
94
+ * - Width: Diagram width in pixels (optional, default: 800)
95
+ * - Height: Diagram height in pixels (optional, default: 600)
96
+ * - Title: Diagram title (optional)
97
+ * - Palette: Color palette ('mjDefault' | 'gray' | 'pastel' | 'highContrast')
98
+ * - Seed: Random seed for deterministic layouts (optional)
99
+ *
100
+ * @returns A promise resolving to an SVGActionResult with:
101
+ * - Success: true if diagram was generated successfully
102
+ * - ResultCode: "SUCCESS" or error code
103
+ * - Message: The SVG string or error message
104
+ * - svg: The SVG XML string
105
+ * - width: Diagram width in pixels
106
+ * - height: Diagram height in pixels
107
+ */
108
+ async InternalRunAction(params) {
109
+ try {
110
+ const diagramTypeParam = this.getParamValue(params, 'DiagramType');
111
+ if (!diagramTypeParam) {
112
+ return {
113
+ Success: false,
114
+ Message: 'DiagramType parameter is required (flow, org, or er)',
115
+ ResultCode: 'MISSING_PARAMETERS',
116
+ };
117
+ }
118
+ const diagramType = this.ensureString(diagramTypeParam, 'DiagramType').toLowerCase();
119
+ // Parse common parameters
120
+ const width = parseInt(this.ensureString(this.getParamValue(params, 'Width') || '800', 'Width'));
121
+ const height = parseInt(this.ensureString(this.getParamValue(params, 'Height') || '600', 'Height'));
122
+ const title = this.ensureString(this.getParamValue(params, 'Title') || '', 'Title');
123
+ const paletteName = this.ensureString(this.getParamValue(params, 'Palette') || 'mjDefault', 'Palette');
124
+ const seed = parseInt(this.ensureString(this.getParamValue(params, 'Seed') || '0', 'Seed'));
125
+ // Create branding configuration
126
+ const branding = {
127
+ palette: { type: 'named', name: paletteName },
128
+ };
129
+ // Create viewBox configuration
130
+ const viewBox = {
131
+ width,
132
+ height,
133
+ padding: 40,
134
+ };
135
+ // Generate diagram based on type
136
+ let svg;
137
+ switch (diagramType) {
138
+ case 'flow':
139
+ svg = await this.renderFlowDiagram(params, viewBox, branding, title, seed);
140
+ break;
141
+ case 'org':
142
+ svg = await this.renderOrgChart(params, viewBox, branding, title);
143
+ break;
144
+ case 'er':
145
+ svg = await this.renderERDiagram(params, viewBox, branding, title, seed);
146
+ break;
147
+ default:
148
+ return {
149
+ Success: false,
150
+ Message: `Unsupported diagram type: ${diagramType}. Supported types: flow, org, er`,
151
+ ResultCode: 'INVALID_DIAGRAM_TYPE',
152
+ };
153
+ }
154
+ return {
155
+ Success: true,
156
+ ResultCode: 'SUCCESS',
157
+ Message: svg,
158
+ svg,
159
+ width,
160
+ height,
161
+ };
162
+ }
163
+ catch (error) {
164
+ return {
165
+ Success: false,
166
+ Message: `Failed to generate diagram: ${error instanceof Error ? error.message : String(error)}`,
167
+ ResultCode: 'DIAGRAM_GENERATION_FAILED',
168
+ };
169
+ }
170
+ }
171
+ /**
172
+ * Renders a flowchart using dagre layout
173
+ */
174
+ async renderFlowDiagram(params, viewBox, branding, title, seed) {
175
+ // Parse nodes and edges
176
+ const nodesParam = this.getParamValue(params, 'Nodes');
177
+ const edgesParam = this.getParamValue(params, 'Edges');
178
+ if (!nodesParam) {
179
+ throw new Error('Nodes parameter is required for flow diagrams');
180
+ }
181
+ const nodes = this.parseJSON(nodesParam, 'Nodes');
182
+ const edges = edgesParam ? this.parseJSON(edgesParam, 'Edges') : [];
183
+ const directionParam = this.getParamValue(params, 'Direction');
184
+ const direction = (directionParam ? this.ensureString(directionParam, 'Direction') : 'TB');
185
+ // Create dagre graph
186
+ const g = new dagre.graphlib.Graph();
187
+ g.setGraph({
188
+ rankdir: direction,
189
+ nodesep: 50,
190
+ ranksep: 80,
191
+ marginx: 40,
192
+ marginy: 40,
193
+ });
194
+ g.setDefaultEdgeLabel(() => ({}));
195
+ // Add nodes to graph with dimensions based on kind
196
+ for (const node of nodes) {
197
+ const dims = this.getNodeDimensions(node);
198
+ g.setNode(node.id, {
199
+ ...node,
200
+ width: node.width || dims.width,
201
+ height: node.height || dims.height,
202
+ });
203
+ }
204
+ // Add edges to graph
205
+ for (const edge of edges) {
206
+ g.setEdge(edge.from, edge.to, edge);
207
+ }
208
+ // Run dagre layout
209
+ dagre.layout(g);
210
+ // Create SVG
211
+ const vb = svg_utils_1.SVGUtils.calculateViewBox(viewBox);
212
+ const doc = svg_utils_1.SVGUtils.createSVG(viewBox.width, viewBox.height, 'flow');
213
+ const svg = doc.querySelector('svg');
214
+ // Add accessibility
215
+ if (title) {
216
+ svg_utils_1.SVGUtils.addA11y(svg, {
217
+ title,
218
+ ariaRole: 'img',
219
+ });
220
+ }
221
+ // Add styles
222
+ const css = (0, svg_theming_1.generateCSS)(branding);
223
+ svg_utils_1.SVGUtils.addStyles(svg, css);
224
+ // Get palette for colors
225
+ const palette = (0, svg_theming_1.getPalette)(branding.palette);
226
+ // Render nodes
227
+ for (const nodeId of g.nodes()) {
228
+ const node = g.node(nodeId);
229
+ this.renderFlowNode(doc, svg, node, palette);
230
+ }
231
+ // Render edges
232
+ for (const edgeObj of g.edges()) {
233
+ const edge = g.edge(edgeObj);
234
+ this.renderFlowEdge(doc, svg, edge, palette);
235
+ }
236
+ // Add title if present
237
+ if (title) {
238
+ this.addTitle(doc, svg, title, vb.width, (0, svg_theming_1.getFontSpec)(branding.font));
239
+ }
240
+ // Sanitize and return
241
+ return svg_utils_1.SVGUtils.sanitizeSVG(svg.outerHTML);
242
+ }
243
+ /**
244
+ * Gets dimensions for flow node based on kind
245
+ */
246
+ getNodeDimensions(node) {
247
+ const labelWidth = svg_utils_1.SVGUtils.estimateTextWidth(node.label, 14);
248
+ switch (node.kind) {
249
+ case 'start':
250
+ case 'end':
251
+ return { width: 120, height: 60 };
252
+ case 'decision':
253
+ return { width: Math.max(160, labelWidth + 40), height: 100 };
254
+ case 'process':
255
+ case 'input':
256
+ case 'output':
257
+ case 'subprocess':
258
+ return { width: Math.max(140, labelWidth + 40), height: 70 };
259
+ default:
260
+ return { width: 140, height: 70 };
261
+ }
262
+ }
263
+ /**
264
+ * Renders a single flow node
265
+ */
266
+ renderFlowNode(doc, svg, node, palette) {
267
+ const ns = svg.namespaceURI;
268
+ const g = doc.createElementNS(ns, 'g');
269
+ g.setAttribute('id', node.id);
270
+ g.setAttribute('transform', `translate(${node.x}, ${node.y})`);
271
+ const colorIndex = this.getNodeColorIndex(node.kind);
272
+ const fillColor = palette.categorical[colorIndex % palette.categorical.length];
273
+ // Render shape based on kind
274
+ switch (node.kind) {
275
+ case 'start':
276
+ case 'end':
277
+ this.renderEllipse(doc, g, node.width, node.height, fillColor);
278
+ break;
279
+ case 'decision':
280
+ this.renderDiamond(doc, g, node.width, node.height, fillColor);
281
+ break;
282
+ case 'subprocess':
283
+ this.renderRoundedRect(doc, g, node.width, node.height, fillColor, 10);
284
+ // Add double border for subprocess
285
+ const innerRect = doc.createElementNS(ns, 'path');
286
+ innerRect.setAttribute('d', svg_utils_1.SVGUtils.roundedRectPath(-node.width / 2 + 5, -node.height / 2 + 5, node.width - 10, node.height - 10, 8));
287
+ innerRect.setAttribute('fill', 'none');
288
+ innerRect.setAttribute('stroke', palette.foreground);
289
+ innerRect.setAttribute('stroke-width', '1.5');
290
+ g.appendChild(innerRect);
291
+ break;
292
+ default:
293
+ this.renderRoundedRect(doc, g, node.width, node.height, fillColor, 5);
294
+ break;
295
+ }
296
+ // Add label
297
+ const text = doc.createElementNS(ns, 'text');
298
+ text.setAttribute('class', 'node-text');
299
+ text.setAttribute('y', '0');
300
+ text.textContent = node.label;
301
+ g.appendChild(text);
302
+ svg.appendChild(g);
303
+ }
304
+ /**
305
+ * Gets color index for node kind
306
+ */
307
+ getNodeColorIndex(kind) {
308
+ const kindMap = {
309
+ start: 0,
310
+ end: 1,
311
+ process: 2,
312
+ decision: 3,
313
+ input: 4,
314
+ output: 5,
315
+ subprocess: 6,
316
+ };
317
+ return kindMap[kind] || 2;
318
+ }
319
+ /**
320
+ * Renders an ellipse shape
321
+ */
322
+ renderEllipse(doc, g, width, height, fill) {
323
+ const ns = g.namespaceURI;
324
+ const ellipse = doc.createElementNS(ns, 'ellipse');
325
+ ellipse.setAttribute('cx', '0');
326
+ ellipse.setAttribute('cy', '0');
327
+ ellipse.setAttribute('rx', String(width / 2));
328
+ ellipse.setAttribute('ry', String(height / 2));
329
+ ellipse.setAttribute('fill', fill);
330
+ ellipse.setAttribute('stroke', '#333');
331
+ ellipse.setAttribute('stroke-width', '2');
332
+ g.appendChild(ellipse);
333
+ }
334
+ /**
335
+ * Renders a diamond shape
336
+ */
337
+ renderDiamond(doc, g, width, height, fill) {
338
+ const ns = g.namespaceURI;
339
+ const path = doc.createElementNS(ns, 'path');
340
+ const w = width / 2;
341
+ const h = height / 2;
342
+ const d = `M 0,${-h} L ${w},0 L 0,${h} L ${-w},0 Z`;
343
+ path.setAttribute('d', d);
344
+ path.setAttribute('fill', fill);
345
+ path.setAttribute('stroke', '#333');
346
+ path.setAttribute('stroke-width', '2');
347
+ g.appendChild(path);
348
+ }
349
+ /**
350
+ * Renders a rounded rectangle
351
+ */
352
+ renderRoundedRect(doc, g, width, height, fill, radius) {
353
+ const ns = g.namespaceURI;
354
+ const path = doc.createElementNS(ns, 'path');
355
+ path.setAttribute('d', svg_utils_1.SVGUtils.roundedRectPath(-width / 2, -height / 2, width, height, radius));
356
+ path.setAttribute('fill', fill);
357
+ path.setAttribute('stroke', '#333');
358
+ path.setAttribute('stroke-width', '2');
359
+ g.appendChild(path);
360
+ }
361
+ /**
362
+ * Renders a flow edge
363
+ */
364
+ renderFlowEdge(doc, svg, edge, palette) {
365
+ const ns = svg.namespaceURI;
366
+ const g = doc.createElementNS(ns, 'g');
367
+ // Create path from points
368
+ const pathData = edge.points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x},${p.y}`).join(' ');
369
+ const path = doc.createElementNS(ns, 'path');
370
+ path.setAttribute('d', pathData);
371
+ path.setAttribute('class', 'edge-line');
372
+ if (edge.dashed) {
373
+ path.setAttribute('stroke-dasharray', '5,5');
374
+ }
375
+ // Add arrow marker
376
+ const markerId = svg_utils_1.SVGUtils.addArrowMarker(svg, 'arrow-end', palette.foreground);
377
+ path.setAttribute('marker-end', markerId);
378
+ g.appendChild(path);
379
+ // Add label if present
380
+ if (edge.label) {
381
+ const midPoint = edge.points[Math.floor(edge.points.length / 2)];
382
+ const text = doc.createElementNS(ns, 'text');
383
+ text.setAttribute('x', String(midPoint.x));
384
+ text.setAttribute('y', String(midPoint.y - 5));
385
+ text.setAttribute('class', 'edge-label');
386
+ text.textContent = edge.label;
387
+ g.appendChild(text);
388
+ }
389
+ svg.appendChild(g);
390
+ }
391
+ /**
392
+ * Renders an org chart using d3-hierarchy
393
+ */
394
+ async renderOrgChart(params, viewBox, branding, title) {
395
+ // Parse org tree
396
+ const nodesParam = this.getParamValue(params, 'Nodes');
397
+ if (!nodesParam) {
398
+ throw new Error('Nodes parameter is required for org charts');
399
+ }
400
+ const rootNode = this.parseJSON(nodesParam, 'Nodes');
401
+ // Create hierarchy
402
+ const hierarchy = d3Hierarchy.hierarchy(rootNode);
403
+ // Create tree layout
404
+ const vb = svg_utils_1.SVGUtils.calculateViewBox(viewBox);
405
+ const treeLayout = d3Hierarchy.tree().size([vb.contentWidth, vb.contentHeight]);
406
+ // Calculate layout
407
+ const treeData = treeLayout(hierarchy);
408
+ // Create SVG
409
+ const doc = svg_utils_1.SVGUtils.createSVG(viewBox.width, viewBox.height, 'org');
410
+ const svg = doc.querySelector('svg');
411
+ // Add accessibility
412
+ if (title) {
413
+ svg_utils_1.SVGUtils.addA11y(svg, {
414
+ title,
415
+ ariaRole: 'img',
416
+ });
417
+ }
418
+ // Add styles
419
+ const css = (0, svg_theming_1.generateCSS)(branding);
420
+ svg_utils_1.SVGUtils.addStyles(svg, css);
421
+ // Get palette
422
+ const palette = (0, svg_theming_1.getPalette)(branding.palette);
423
+ // Create container group with offset for padding
424
+ const container = doc.createElementNS(svg.namespaceURI, 'g');
425
+ container.setAttribute('transform', `translate(${vb.x}, ${vb.y})`);
426
+ svg.appendChild(container);
427
+ // Render links first (so they appear behind nodes)
428
+ treeData.links().forEach((link) => {
429
+ this.renderOrgLink(doc, container, link, palette);
430
+ });
431
+ // Render nodes
432
+ treeData.descendants().forEach((node) => {
433
+ this.renderOrgNode(doc, container, node, palette);
434
+ });
435
+ // Add title if present
436
+ if (title) {
437
+ this.addTitle(doc, svg, title, vb.width, (0, svg_theming_1.getFontSpec)(branding.font));
438
+ }
439
+ // Sanitize and return
440
+ return svg_utils_1.SVGUtils.sanitizeSVG(svg.outerHTML);
441
+ }
442
+ /**
443
+ * Renders an org chart link
444
+ */
445
+ renderOrgLink(doc, container, link, palette) {
446
+ const ns = container.namespaceURI;
447
+ const path = doc.createElementNS(ns, 'path');
448
+ // Create elbow connector
449
+ const d = `M ${link.source.x},${link.source.y + 35}
450
+ L ${link.source.x},${(link.source.y + link.target.y) / 2}
451
+ L ${link.target.x},${(link.source.y + link.target.y) / 2}
452
+ L ${link.target.x},${link.target.y - 35}`;
453
+ path.setAttribute('d', d);
454
+ path.setAttribute('fill', 'none');
455
+ path.setAttribute('stroke', palette.foreground);
456
+ path.setAttribute('stroke-width', '2');
457
+ path.setAttribute('opacity', '0.6');
458
+ container.appendChild(path);
459
+ }
460
+ /**
461
+ * Renders an org chart node
462
+ */
463
+ renderOrgNode(doc, container, node, palette) {
464
+ const ns = container.namespaceURI;
465
+ const g = doc.createElementNS(ns, 'g');
466
+ g.setAttribute('transform', `translate(${node.x}, ${node.y})`);
467
+ const boxWidth = 180;
468
+ const boxHeight = 70;
469
+ // Determine color based on depth
470
+ const colorIndex = node.depth % palette.categorical.length;
471
+ const fillColor = palette.categorical[colorIndex];
472
+ // Render box
473
+ const rect = doc.createElementNS(ns, 'rect');
474
+ rect.setAttribute('x', String(-boxWidth / 2));
475
+ rect.setAttribute('y', String(-boxHeight / 2));
476
+ rect.setAttribute('width', String(boxWidth));
477
+ rect.setAttribute('height', String(boxHeight));
478
+ rect.setAttribute('fill', fillColor);
479
+ rect.setAttribute('stroke', '#333');
480
+ rect.setAttribute('stroke-width', '2');
481
+ rect.setAttribute('rx', '8');
482
+ if (node.data.highlight) {
483
+ rect.setAttribute('stroke', '#FFD700');
484
+ rect.setAttribute('stroke-width', '4');
485
+ }
486
+ g.appendChild(rect);
487
+ // Add avatar circle if avatarUrl present
488
+ if (node.data.avatarUrl) {
489
+ const avatar = doc.createElementNS(ns, 'circle');
490
+ avatar.setAttribute('cx', '0');
491
+ avatar.setAttribute('cy', String(-boxHeight / 2 + 20));
492
+ avatar.setAttribute('r', '15');
493
+ avatar.setAttribute('fill', '#FFF');
494
+ avatar.setAttribute('stroke', '#333');
495
+ g.appendChild(avatar);
496
+ }
497
+ // Add name
498
+ const nameText = doc.createElementNS(ns, 'text');
499
+ nameText.setAttribute('y', node.data.avatarUrl ? '5' : '-8');
500
+ nameText.setAttribute('text-anchor', 'middle');
501
+ nameText.setAttribute('font-weight', 'bold');
502
+ nameText.setAttribute('font-size', '14');
503
+ nameText.setAttribute('fill', '#FFF');
504
+ nameText.textContent = node.data.label;
505
+ g.appendChild(nameText);
506
+ // Add role if present
507
+ if (node.data.role) {
508
+ const roleText = doc.createElementNS(ns, 'text');
509
+ roleText.setAttribute('y', node.data.avatarUrl ? '20' : '8');
510
+ roleText.setAttribute('text-anchor', 'middle');
511
+ roleText.setAttribute('font-size', '12');
512
+ roleText.setAttribute('fill', '#FFF');
513
+ roleText.setAttribute('opacity', '0.9');
514
+ roleText.textContent = node.data.role;
515
+ g.appendChild(roleText);
516
+ }
517
+ container.appendChild(g);
518
+ }
519
+ /**
520
+ * Renders an ER diagram using dagre layout
521
+ */
522
+ async renderERDiagram(params, viewBox, branding, title, seed) {
523
+ // Parse tables and relations
524
+ const nodesParam = this.getParamValue(params, 'Nodes');
525
+ const edgesParam = this.getParamValue(params, 'Edges');
526
+ if (!nodesParam) {
527
+ throw new Error('Nodes parameter is required for ER diagrams');
528
+ }
529
+ const tables = this.parseJSON(nodesParam, 'Nodes');
530
+ const relations = edgesParam ? this.parseJSON(edgesParam, 'Edges') : [];
531
+ // Create dagre graph
532
+ const g = new dagre.graphlib.Graph();
533
+ g.setGraph({
534
+ rankdir: 'TB',
535
+ nodesep: 60,
536
+ ranksep: 80,
537
+ marginx: 40,
538
+ marginy: 40,
539
+ });
540
+ g.setDefaultEdgeLabel(() => ({}));
541
+ // Add tables as nodes
542
+ for (const table of tables) {
543
+ const height = 40 + table.attrs.length * 25; // Header + rows
544
+ const maxAttrWidth = Math.max(...table.attrs.map((a) => svg_utils_1.SVGUtils.estimateTextWidth(`${a.name}: ${a.type || ''}`, 12)));
545
+ const width = Math.max(200, maxAttrWidth + 80);
546
+ g.setNode(table.id, {
547
+ ...table,
548
+ width,
549
+ height,
550
+ });
551
+ }
552
+ // Add relations as edges
553
+ for (const rel of relations) {
554
+ g.setEdge(rel.from, rel.to, rel);
555
+ }
556
+ // Run dagre layout
557
+ dagre.layout(g);
558
+ // Create SVG
559
+ const vb = svg_utils_1.SVGUtils.calculateViewBox(viewBox);
560
+ const doc = svg_utils_1.SVGUtils.createSVG(viewBox.width, viewBox.height, 'er');
561
+ const svg = doc.querySelector('svg');
562
+ // Add accessibility
563
+ if (title) {
564
+ svg_utils_1.SVGUtils.addA11y(svg, {
565
+ title,
566
+ ariaRole: 'img',
567
+ });
568
+ }
569
+ // Add styles
570
+ const css = (0, svg_theming_1.generateCSS)(branding);
571
+ svg_utils_1.SVGUtils.addStyles(svg, css);
572
+ // Get palette
573
+ const palette = (0, svg_theming_1.getPalette)(branding.palette);
574
+ // Render tables
575
+ for (const tableId of g.nodes()) {
576
+ const table = g.node(tableId);
577
+ this.renderERTable(doc, svg, table, palette);
578
+ }
579
+ // Render relations
580
+ for (const edgeObj of g.edges()) {
581
+ const rel = g.edge(edgeObj);
582
+ this.renderERRelation(doc, svg, rel, palette);
583
+ }
584
+ // Add title if present
585
+ if (title) {
586
+ this.addTitle(doc, svg, title, vb.width, (0, svg_theming_1.getFontSpec)(branding.font));
587
+ }
588
+ // Sanitize and return
589
+ return svg_utils_1.SVGUtils.sanitizeSVG(svg.outerHTML);
590
+ }
591
+ /**
592
+ * Renders an ER table
593
+ */
594
+ renderERTable(doc, svg, table, palette) {
595
+ const ns = svg.namespaceURI;
596
+ const g = doc.createElementNS(ns, 'g');
597
+ g.setAttribute('id', table.id);
598
+ g.setAttribute('transform', `translate(${table.x - table.width / 2}, ${table.y - table.height / 2})`);
599
+ // Render table box
600
+ const rect = doc.createElementNS(ns, 'rect');
601
+ rect.setAttribute('x', '0');
602
+ rect.setAttribute('y', '0');
603
+ rect.setAttribute('width', String(table.width));
604
+ rect.setAttribute('height', String(table.height));
605
+ rect.setAttribute('fill', palette.background);
606
+ rect.setAttribute('stroke', palette.foreground);
607
+ rect.setAttribute('stroke-width', '2');
608
+ g.appendChild(rect);
609
+ // Render header
610
+ const headerRect = doc.createElementNS(ns, 'rect');
611
+ headerRect.setAttribute('x', '0');
612
+ headerRect.setAttribute('y', '0');
613
+ headerRect.setAttribute('width', String(table.width));
614
+ headerRect.setAttribute('height', '40');
615
+ headerRect.setAttribute('fill', palette.categorical[0]);
616
+ g.appendChild(headerRect);
617
+ // Header text
618
+ const headerText = doc.createElementNS(ns, 'text');
619
+ headerText.setAttribute('x', String(table.width / 2));
620
+ headerText.setAttribute('y', '25');
621
+ headerText.setAttribute('text-anchor', 'middle');
622
+ headerText.setAttribute('font-weight', 'bold');
623
+ headerText.setAttribute('font-size', '14');
624
+ headerText.setAttribute('fill', '#FFF');
625
+ headerText.textContent = table.name;
626
+ g.appendChild(headerText);
627
+ // Render attributes
628
+ let yOffset = 40;
629
+ for (let i = 0; i < table.attrs.length; i++) {
630
+ const attr = table.attrs[i];
631
+ // Alternating row colors
632
+ if (i % 2 === 1) {
633
+ const rowRect = doc.createElementNS(ns, 'rect');
634
+ rowRect.setAttribute('x', '0');
635
+ rowRect.setAttribute('y', String(yOffset));
636
+ rowRect.setAttribute('width', String(table.width));
637
+ rowRect.setAttribute('height', '25');
638
+ rowRect.setAttribute('fill', '#F5F5F5');
639
+ g.appendChild(rowRect);
640
+ }
641
+ // Attribute text
642
+ const attrText = doc.createElementNS(ns, 'text');
643
+ attrText.setAttribute('x', '10');
644
+ attrText.setAttribute('y', String(yOffset + 17));
645
+ attrText.setAttribute('font-size', '12');
646
+ attrText.setAttribute('fill', palette.foreground);
647
+ let label = attr.name;
648
+ if (attr.pk)
649
+ label = '🔑 ' + label;
650
+ else if (attr.fk)
651
+ label = '🔗 ' + label;
652
+ if (attr.type)
653
+ label += `: ${attr.type}`;
654
+ attrText.textContent = label;
655
+ g.appendChild(attrText);
656
+ yOffset += 25;
657
+ }
658
+ svg.appendChild(g);
659
+ }
660
+ /**
661
+ * Renders an ER relation
662
+ */
663
+ renderERRelation(doc, svg, rel, palette) {
664
+ const ns = svg.namespaceURI;
665
+ const g = doc.createElementNS(ns, 'g');
666
+ // Create path from points
667
+ const pathData = rel.points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x},${p.y}`).join(' ');
668
+ const path = doc.createElementNS(ns, 'path');
669
+ path.setAttribute('d', pathData);
670
+ path.setAttribute('class', 'edge-line');
671
+ path.setAttribute('stroke-dasharray', '5,5');
672
+ g.appendChild(path);
673
+ // Add cardinality label if present
674
+ if (rel.label) {
675
+ const midPoint = rel.points[Math.floor(rel.points.length / 2)];
676
+ const text = doc.createElementNS(ns, 'text');
677
+ text.setAttribute('x', String(midPoint.x));
678
+ text.setAttribute('y', String(midPoint.y - 5));
679
+ text.setAttribute('class', 'edge-label');
680
+ text.setAttribute('fill', palette.foreground);
681
+ text.setAttribute('font-size', '11');
682
+ text.textContent = rel.label;
683
+ g.appendChild(text);
684
+ }
685
+ svg.appendChild(g);
686
+ }
687
+ /**
688
+ * Adds a title to the SVG
689
+ */
690
+ addTitle(doc, svg, title, width, font) {
691
+ const ns = svg.namespaceURI;
692
+ const text = doc.createElementNS(ns, 'text');
693
+ text.setAttribute('x', String(width / 2));
694
+ text.setAttribute('y', '25');
695
+ text.setAttribute('text-anchor', 'middle');
696
+ text.setAttribute('font-family', font.family);
697
+ text.setAttribute('font-size', String(font.size + 4));
698
+ text.setAttribute('font-weight', 'bold');
699
+ text.textContent = title;
700
+ svg.appendChild(text);
701
+ }
702
+ /**
703
+ * Helper to safely parse JSON that might already be an object
704
+ */
705
+ parseJSON(value, paramName) {
706
+ // If it's already an object/array, return it
707
+ if (typeof value === 'object' && value !== null) {
708
+ return value;
709
+ }
710
+ // If it's a string, parse it
711
+ if (typeof value === 'string') {
712
+ try {
713
+ return JSON.parse(value);
714
+ }
715
+ catch (error) {
716
+ throw new Error(`Parameter '${paramName}' contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
717
+ }
718
+ }
719
+ // For other types, error
720
+ throw new Error(`Parameter '${paramName}' must be a JSON string or object. Received ${typeof value}.`);
721
+ }
722
+ /**
723
+ * Helper to ensure a parameter value is a string, with type conversion and validation
724
+ */
725
+ ensureString(value, paramName) {
726
+ if (value == null) {
727
+ return '';
728
+ }
729
+ if (typeof value === 'string') {
730
+ return value;
731
+ }
732
+ // Convert numbers and booleans to strings
733
+ if (typeof value === 'number' || typeof value === 'boolean') {
734
+ return String(value);
735
+ }
736
+ // For objects/arrays, reject with descriptive error
737
+ throw new Error(`Parameter '${paramName}' must be a string, number, or boolean. ` +
738
+ `Received ${typeof value}. If providing JSON data, ensure it's passed as a string.`);
739
+ }
740
+ /**
741
+ * Helper to get parameter value by name (case-insensitive)
742
+ */
743
+ getParamValue(params, paramName) {
744
+ const param = params.Params.find((p) => p.Name.trim().toLowerCase() === paramName.toLowerCase());
745
+ if (param?.Value && typeof param.Value === 'string') {
746
+ return param?.Value?.trim() || null;
747
+ }
748
+ else {
749
+ return param?.Value || null;
750
+ }
751
+ }
752
+ };
753
+ exports.CreateSVGDiagramAction = CreateSVGDiagramAction;
754
+ exports.CreateSVGDiagramAction = CreateSVGDiagramAction = __decorate([
755
+ (0, global_1.RegisterClass)(actions_1.BaseAction, '__CreateSVGDiagram')
756
+ ], CreateSVGDiagramAction);
757
+ /**
758
+ * Loader function to ensure the CreateSVGDiagramAction class is included in the bundle.
759
+ */
760
+ function LoadCreateSVGDiagramAction() {
761
+ // this function is a stub that is used to force the bundler to include the above class in the final bundle and not tree shake them out
762
+ }
763
+ exports.LoadCreateSVGDiagramAction = LoadCreateSVGDiagramAction;
764
+ //# sourceMappingURL=create-svg-diagram.action.js.map