@eventcatalog/core 3.17.5 → 3.18.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 (43) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-MJVOXKKM.js → chunk-3XKMODP4.js} +1 -1
  6. package/dist/{chunk-VWSQYMKF.js → chunk-52VBVLRT.js} +1 -1
  7. package/dist/{chunk-LLGEQ4MZ.js → chunk-7CZBLKHQ.js} +1 -1
  8. package/dist/{chunk-O6SVMZR3.js → chunk-GSHSX7NU.js} +1 -1
  9. package/dist/{chunk-6LCHHROP.js → chunk-OQ6UFIEN.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/src/components/EnvironmentDropdown.tsx +1 -1
  19. package/eventcatalog/src/components/Header.astro +5 -5
  20. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +10 -6
  21. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraphPortal.tsx +1 -1
  22. package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +10 -10
  23. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +15 -13
  24. package/eventcatalog/src/components/Search/Search.astro +2 -2
  25. package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +1 -1
  26. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +5 -6
  27. package/eventcatalog/src/content.config.ts +18 -3
  28. package/eventcatalog/src/enterprise/mcp/mcp-server.ts +11 -17
  29. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +2 -26
  30. package/eventcatalog/src/pages/_index.astro +138 -113
  31. package/eventcatalog/src/pages/index.astro +17 -5
  32. package/eventcatalog/src/styles/theme.css +7 -2
  33. package/eventcatalog/src/styles/themes/forest.css +7 -7
  34. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +5 -1
  35. package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +3 -1
  36. package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +8 -2
  37. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +1 -1
  38. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +2 -2
  39. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +13 -4
  40. package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +4 -1
  41. package/eventcatalog/src/utils/node-graphs/utils/utils.ts +80 -17
  42. package/eventcatalog/tailwind.config.mjs +11 -2
  43. package/package.json +4 -4
@@ -55,7 +55,7 @@ export const getNodesAndEdgesForDomainContextMap = async ({ defaultFlow = null }
55
55
  const servicesCount = domainServices.length;
56
56
  const SERVICES_PER_ROW = 1;
57
57
  const SERVICE_WIDTH = 330;
58
- const SERVICE_HEIGHT = 100;
58
+ const SERVICE_HEIGHT = 120;
59
59
  const PADDING = 40;
60
60
  const TITLE_HEIGHT = 20;
61
61
 
@@ -1,6 +1,6 @@
1
1
  import { getCollection, type CollectionEntry } from 'astro:content';
2
2
  import dagre from 'dagre';
3
- import { createDagreGraph, calculatedNodes } from '@utils/node-graphs/utils/utils';
3
+ import { createDagreGraph, calculatedNodes, DEFAULT_NODE_WIDTH, DEFAULT_NODE_HEIGHT } from '@utils/node-graphs/utils/utils';
4
4
  import { MarkerType } from '@xyflow/react';
5
5
  import type { Node as NodeType } from '@xyflow/react';
6
6
  import { createVersionedMap, findInMap } from '@utils/collections/util';
@@ -153,7 +153,7 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
153
153
  });
154
154
 
155
155
  nodes.forEach((node: any) => {
156
- graph.setNode(node.id, { width: 150, height: 100 });
156
+ graph.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
157
157
  });
158
158
 
159
159
  edges.forEach((edge: any) => {
@@ -24,7 +24,15 @@ import {
24
24
  import type { CollectionMessageTypes } from '@types';
25
25
  import { getCommands } from '@utils/collections/commands';
26
26
  import { getQueries } from '@utils/collections/queries';
27
- import { createNode, buildContextMenuForMessage, buildContextMenuForService, buildContextMenuForResource } from './utils/utils';
27
+ import {
28
+ createNode,
29
+ buildContextMenuForMessage,
30
+ buildContextMenuForService,
31
+ buildContextMenuForResource,
32
+ getOperationFields,
33
+ DEFAULT_NODE_WIDTH,
34
+ DEFAULT_NODE_HEIGHT,
35
+ } from './utils/utils';
28
36
  import { getConsumersOfMessage, getProducersOfMessage } from '@utils/collections/services';
29
37
  import { getNodesAndEdgesForChannelChain } from './channel-node-graph';
30
38
  import { getChannelChain, isChannelsConnected } from '@utils/collections/channels';
@@ -79,6 +87,7 @@ const getNodesAndEdges = async ({
79
87
  mode,
80
88
  message: {
81
89
  ...message.data,
90
+ ...getOperationFields(message.data),
82
91
  },
83
92
  contextMenu: buildContextMenuForMessage({
84
93
  id: message.data.id,
@@ -458,7 +467,7 @@ const getNodesAndEdges = async ({
458
467
  });
459
468
 
460
469
  nodes.forEach((node: any) => {
461
- flow.setNode(node.id, { width: 150, height: 100 });
470
+ flow.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
462
471
  });
463
472
 
464
473
  edges.forEach((edge: any) => {
@@ -546,7 +555,7 @@ export const getNodesAndEdgesForConsumedMessage = ({
546
555
  type: message.collection,
547
556
  data: {
548
557
  mode,
549
- message: { ...message.data },
558
+ message: { ...message.data, ...getOperationFields(message.data) },
550
559
  contextMenu: buildContextMenuForMessage({
551
560
  id: message.data.id,
552
561
  version: message.data.version,
@@ -893,7 +902,7 @@ export const getNodesAndEdgesForProducedMessage = ({
893
902
  type: message.collection,
894
903
  data: {
895
904
  mode,
896
- message: { ...message.data },
905
+ message: { ...message.data, ...getOperationFields(message.data) },
897
906
  contextMenu: buildContextMenuForMessage({
898
907
  id: message.data.id,
899
908
  version: message.data.version,
@@ -9,6 +9,8 @@ import {
9
9
  buildContextMenuForService,
10
10
  buildContextMenuForResource,
11
11
  versionMatches,
12
+ DEFAULT_NODE_WIDTH,
13
+ DEFAULT_NODE_HEIGHT,
12
14
  } from '@utils/node-graphs/utils/utils';
13
15
 
14
16
  import { findMatchingNodes, findInMap, createVersionedMap } from '@utils/collections/util';
@@ -275,6 +277,7 @@ export const getNodesAndEdges = async ({
275
277
  },
276
278
  style: {
277
279
  strokeWidth: 1,
280
+ stroke: 'var(--ec-edge-stroke, #6b7280)',
278
281
  },
279
282
  });
280
283
  }
@@ -305,7 +308,7 @@ export const getNodesAndEdges = async ({
305
308
  });
306
309
 
307
310
  nodes.forEach((node: any) => {
308
- flow.setNode(node.id, { width: 150, height: 100 });
311
+ flow.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
309
312
  });
310
313
 
311
314
  edges.forEach((edge: any) => {
@@ -98,6 +98,9 @@ export const calculatedNodes = (flow: dagre.graphlib.Graph, nodes: Node[]) => {
98
98
  });
99
99
  };
100
100
 
101
+ export const DEFAULT_NODE_WIDTH = 150;
102
+ export const DEFAULT_NODE_HEIGHT = 120;
103
+
101
104
  // Creates a new dagre graph
102
105
  export const createDagreGraph = ({ ranksep = 180, nodesep = 50, ...rest }: any) => {
103
106
  const graph = new dagre.graphlib.Graph({ compound: true });
@@ -122,6 +125,7 @@ export const createEdge = (edgeOptions: Edge) => {
122
125
  },
123
126
  style: {
124
127
  strokeWidth: 1,
128
+ stroke: 'var(--ec-edge-stroke, #6b7280)',
125
129
  },
126
130
  ...edgeOptions,
127
131
  };
@@ -180,6 +184,61 @@ export const buildContextMenuForMessage = ({
180
184
  return items;
181
185
  };
182
186
 
187
+ const getSpecMenuItems = (
188
+ specs: unknown,
189
+ id: string,
190
+ version: string
191
+ ): { label: string; href: string; separator?: boolean }[] => {
192
+ const items: { label: string; href: string; separator?: boolean }[] = [];
193
+
194
+ const addSpec = (type: string, filePath: string, isFirst: boolean) => {
195
+ const filename = filePath.split('/').pop() || filePath;
196
+ const filenameNoExt = filename.replace(/\.[^/.]+$/, '');
197
+ const typeLower = type.toLowerCase();
198
+
199
+ let label = 'View specification';
200
+ let urlSegment = 'spec';
201
+ if (typeLower === 'asyncapi') {
202
+ label = 'View AsyncAPI spec';
203
+ urlSegment = 'asyncapi';
204
+ } else if (typeLower === 'openapi') {
205
+ label = 'View OpenAPI spec';
206
+ urlSegment = 'spec';
207
+ } else if (typeLower === 'graphql') {
208
+ label = 'View GraphQL spec';
209
+ urlSegment = 'graphql';
210
+ }
211
+
212
+ items.push({
213
+ label,
214
+ href: buildUrl(`/docs/services/${id}/${version}/${urlSegment}/${filenameNoExt}`),
215
+ separator: isFirst,
216
+ });
217
+ };
218
+
219
+ if (Array.isArray(specs)) {
220
+ specs.forEach((spec: any, i: number) => {
221
+ if (spec?.type && spec?.path) addSpec(spec.type, spec.path, i === 0);
222
+ });
223
+ } else if (specs && typeof specs === 'object') {
224
+ const legacy = specs as Record<string, string>;
225
+ let first = true;
226
+ if (legacy.asyncapiPath) {
227
+ addSpec('asyncapi', legacy.asyncapiPath, first);
228
+ first = false;
229
+ }
230
+ if (legacy.openapiPath) {
231
+ addSpec('openapi', legacy.openapiPath, first);
232
+ first = false;
233
+ }
234
+ if (legacy.graphqlPath) {
235
+ addSpec('graphql', legacy.graphqlPath, first);
236
+ }
237
+ }
238
+
239
+ return items;
240
+ };
241
+
183
242
  export const buildContextMenuForService = ({
184
243
  id,
185
244
  version,
@@ -188,25 +247,13 @@ export const buildContextMenuForService = ({
188
247
  }: {
189
248
  id: string;
190
249
  version: string;
191
- specifications?: { type: string; path: string }[];
250
+ specifications?: unknown;
192
251
  repository?: { url: string };
193
252
  }): ContextMenuItem[] => {
194
253
  const items: ContextMenuItem[] = [{ label: 'Read documentation', href: buildUrl(`/docs/services/${id}/${version}`) }];
195
254
 
196
- if (specifications && Array.isArray(specifications)) {
197
- for (const spec of specifications) {
198
- const specType = spec.type?.toLowerCase() || '';
199
- let label = 'View specification';
200
- if (specType.includes('asyncapi')) label = 'View AsyncAPI spec';
201
- else if (specType.includes('openapi')) label = 'View OpenAPI spec';
202
-
203
- items.push({
204
- label,
205
- href: buildUrl(`/docs/services/${id}/${version}/spec/${spec.type}`),
206
- separator: items.length === 1,
207
- });
208
- }
209
- }
255
+ const specItems = getSpecMenuItems(specifications, id, version);
256
+ items.push(...specItems);
210
257
 
211
258
  if (repository?.url) {
212
259
  items.push({
@@ -221,7 +268,7 @@ export const buildContextMenuForService = ({
221
268
  label: 'Read changelog',
222
269
  href: buildUrl(`/docs/services/${id}/${version}/changelog`),
223
270
  external: true,
224
- separator: !repository?.url && (!specifications || specifications.length === 0),
271
+ separator: !repository?.url && specItems.length === 0,
225
272
  });
226
273
 
227
274
  return items;
@@ -247,6 +294,22 @@ export const buildContextMenuForResource = ({
247
294
  ];
248
295
  };
249
296
 
297
+ /**
298
+ * Extracts operation fields (method, path, statusCodes) from a message's
299
+ * `operation` frontmatter and returns them as top-level props the visualiser expects.
300
+ */
301
+ export const getOperationFields = (data: Record<string, any>) => {
302
+ const op = data.operation;
303
+ if (!op) return {};
304
+ return {
305
+ ...(op.method ? { method: op.method } : {}),
306
+ ...(op.path ? { path: op.path } : {}),
307
+ ...(Array.isArray(op.statusCodes) && op.statusCodes.length > 0
308
+ ? { statusCodes: op.statusCodes.map(Number).filter((n: number) => !isNaN(n)) }
309
+ : {}),
310
+ };
311
+ };
312
+
250
313
  export const getNodesAndEdgesFromDagre = ({
251
314
  nodes,
252
315
  edges,
@@ -259,7 +322,7 @@ export const getNodesAndEdgesFromDagre = ({
259
322
  const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
260
323
 
261
324
  nodes.forEach((node: any) => {
262
- flow.setNode(node.id, { width: 150, height: 100 });
325
+ flow.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
263
326
  });
264
327
 
265
328
  edges.forEach((edge: any) => {
@@ -7,7 +7,16 @@ const theme = config.theme || {};
7
7
  /** @type {import('tailwindcss').Config} */
8
8
  export default {
9
9
  darkMode: ['selector', '[data-theme="dark"]'],
10
- content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
10
+ content: {
11
+ // Resolve globs relative to this config file, not process.cwd().
12
+ // This prevents production builds from missing utilities when Astro is launched from a different working directory.
13
+ relative: true,
14
+ files: [
15
+ './src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}',
16
+ // Include visualizer components so core Tailwind generates their utilities.
17
+ '../../visualiser/src/**/*.{js,jsx,ts,tsx}',
18
+ ],
19
+ },
11
20
  theme: {
12
21
  extend: {
13
22
  fontFamily: {
@@ -67,7 +76,7 @@ export default {
67
76
  { pattern: /bg-.*-500\/(10|20)/, variants: ['dark'] },
68
77
  { pattern: /from-.*-(100|200|300|400|500|600|700)/ },
69
78
  { pattern: /to-.*-(100|200|300|400|500|600|700)/ },
70
- { pattern: /text-.*-(300|400|500|800)/, variants: ['dark', 'group-hover', 'dark:group-hover'] },
79
+ { pattern: /text-.*-(100|300|400|500|800)/, variants: ['dark', 'group-hover', 'dark:group-hover'] },
71
80
  { pattern: /ring-.*-500\/30/, variants: ['dark'] },
72
81
  'border-blue-200',
73
82
  'border-green-300',
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/event-catalog/eventcatalog.git"
7
7
  },
8
8
  "type": "module",
9
- "version": "3.17.5",
9
+ "version": "3.18.0",
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
@@ -91,7 +91,7 @@
91
91
  "remark-comment": "^1.0.0",
92
92
  "remark-directive": "^3.0.0",
93
93
  "remark-gfm": "^4.0.1",
94
- "rimraf": "^5.0.7",
94
+ "rimraf": "^6.1.3",
95
95
  "semver": "7.6.3",
96
96
  "shelljs": "^0.9.0",
97
97
  "svg-pan-zoom": "^3.6.2",
@@ -101,9 +101,9 @@
101
101
  "update-notifier": "^7.3.1",
102
102
  "uuid": "^10.0.0",
103
103
  "zod": "^3.25.0",
104
- "@eventcatalog/linter": "1.0.8",
104
+ "@eventcatalog/linter": "1.0.7",
105
105
  "@eventcatalog/sdk": "2.15.0",
106
- "@eventcatalog/visualiser": "^3.14.1"
106
+ "@eventcatalog/visualiser": "^3.15.0"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@astrojs/check": "^0.9.6",