@eventcatalog/core 3.25.5 → 3.26.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 (36) 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/catalog-to-astro-content-directory.cjs +1 -1
  6. package/dist/{chunk-NIGGP5OH.js → chunk-7CRFNX47.js} +1 -1
  7. package/dist/{chunk-G3KLCHZ7.js → chunk-ASC3AR2X.js} +1 -1
  8. package/dist/{chunk-KMBHKZX5.js → chunk-FQNBDDUF.js} +1 -1
  9. package/dist/{chunk-TQQ3EOI3.js → chunk-GCNIIIFG.js} +1 -1
  10. package/dist/{chunk-6QMOE3KE.js → chunk-XUN32ZVJ.js} +1 -1
  11. package/dist/constants.cjs +1 -1
  12. package/dist/constants.js +1 -1
  13. package/dist/eventcatalog.cjs +563 -20
  14. package/dist/eventcatalog.js +572 -27
  15. package/dist/generate.cjs +1 -1
  16. package/dist/generate.js +3 -3
  17. package/dist/utils/cli-logger.cjs +1 -1
  18. package/dist/utils/cli-logger.js +2 -2
  19. package/eventcatalog/astro.config.mjs +2 -1
  20. package/eventcatalog/integrations/eventcatalog-features.ts +13 -0
  21. package/eventcatalog/public/icons/graphql.svg +3 -1
  22. package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +225 -0
  23. package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +521 -0
  24. package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +501 -0
  25. package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +236 -0
  26. package/eventcatalog/src/enterprise/fields/field-extractor.test.ts +241 -0
  27. package/eventcatalog/src/enterprise/fields/field-extractor.ts +183 -0
  28. package/eventcatalog/src/enterprise/fields/field-indexer.ts +131 -0
  29. package/eventcatalog/src/enterprise/fields/fields-db.test.ts +186 -0
  30. package/eventcatalog/src/enterprise/fields/fields-db.ts +453 -0
  31. package/eventcatalog/src/enterprise/fields/pages/api/fields.ts +43 -0
  32. package/eventcatalog/src/enterprise/fields/pages/fields.astro +19 -0
  33. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +23 -3
  34. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +14 -16
  35. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +192 -0
  36. package/package.json +11 -9
@@ -0,0 +1,192 @@
1
+ import type { Node, Edge } from '@xyflow/react';
2
+ import dagre from 'dagre';
3
+ import {
4
+ createDagreGraph,
5
+ calculatedNodes,
6
+ createEdge,
7
+ createNode,
8
+ buildContextMenuForMessage,
9
+ buildContextMenuForService,
10
+ DEFAULT_NODE_WIDTH,
11
+ DEFAULT_NODE_HEIGHT,
12
+ } from './utils/utils';
13
+
14
+ export interface FieldOccurrence {
15
+ messageId: string;
16
+ messageVersion: string;
17
+ messageType: string;
18
+ messageName?: string;
19
+ messageSummary?: string;
20
+ messageOwners?: string[];
21
+ fieldType?: string;
22
+ producers: { id: string; version: string; name?: string; summary?: string; owners?: string[] }[];
23
+ consumers: { id: string; version: string; name?: string; summary?: string; owners?: string[] }[];
24
+ }
25
+
26
+ interface Props {
27
+ fieldPath: string;
28
+ fieldType: string;
29
+ occurrences: FieldOccurrence[];
30
+ mode?: 'simple' | 'full';
31
+ }
32
+
33
+ export const getNodesAndEdges = ({
34
+ fieldPath,
35
+ fieldType,
36
+ occurrences,
37
+ mode = 'full',
38
+ }: Props): { nodes: Node[]; edges: Edge[] } => {
39
+ const flow = createDagreGraph({ ranksep: 200, nodesep: 50 });
40
+ const nodes: Node[] = [];
41
+ const edges: Edge[] = [];
42
+ const addedNodes = new Set<string>();
43
+
44
+ // Detect distinct types across occurrences
45
+ const typeCounts = new Map<string, number>();
46
+ for (const occ of occurrences) {
47
+ const t = occ.fieldType || fieldType;
48
+ typeCounts.set(t, (typeCounts.get(t) || 0) + 1);
49
+ }
50
+ const hasConflicts = typeCounts.size > 1;
51
+
52
+ // Create field node(s) — one per type if conflicts, otherwise a single node
53
+ const fieldNodeIds = new Map<string, string>();
54
+
55
+ if (hasConflicts) {
56
+ for (const [type] of typeCounts) {
57
+ const nodeId = `field-${fieldPath}-${type}`;
58
+ fieldNodeIds.set(type, nodeId);
59
+ nodes.push(
60
+ createNode({
61
+ id: nodeId,
62
+ type: 'field',
63
+ position: { x: 0, y: 0 },
64
+ data: { name: fieldPath, type, mode },
65
+ })
66
+ );
67
+ addedNodes.add(nodeId);
68
+ }
69
+ } else {
70
+ const nodeId = `field-${fieldPath}`;
71
+ fieldNodeIds.set(fieldType, nodeId);
72
+ nodes.push(
73
+ createNode({
74
+ id: nodeId,
75
+ type: 'field',
76
+ position: { x: 0, y: 0 },
77
+ data: { name: fieldPath, type: fieldType, mode },
78
+ })
79
+ );
80
+ addedNodes.add(nodeId);
81
+ }
82
+
83
+ for (const occ of occurrences) {
84
+ const msgNodeId = `msg-${occ.messageId}-${occ.messageVersion}`;
85
+ const occType = occ.fieldType || fieldType;
86
+ const fieldNodeId = fieldNodeIds.get(occType) || fieldNodeIds.values().next().value;
87
+
88
+ if (!addedNodes.has(msgNodeId)) {
89
+ nodes.push(
90
+ createNode({
91
+ id: msgNodeId,
92
+ type: occ.messageType,
93
+ position: { x: 0, y: 0 },
94
+ data: {
95
+ message: {
96
+ name: occ.messageName || occ.messageId,
97
+ version: occ.messageVersion,
98
+ summary: occ.messageSummary || '',
99
+ id: occ.messageId,
100
+ owners: occ.messageOwners || [],
101
+ },
102
+ contextMenu: buildContextMenuForMessage({
103
+ id: occ.messageId,
104
+ version: occ.messageVersion,
105
+ name: occ.messageName || occ.messageId,
106
+ collection: occ.messageType === 'query' ? 'queries' : `${occ.messageType}s`,
107
+ }),
108
+ mode,
109
+ },
110
+ })
111
+ );
112
+ addedNodes.add(msgNodeId);
113
+ }
114
+
115
+ // Producer services
116
+ for (const p of occ.producers) {
117
+ const svcNodeId = `svc-producer-${p.id}-${p.version}`;
118
+ if (!addedNodes.has(svcNodeId)) {
119
+ nodes.push(
120
+ createNode({
121
+ id: svcNodeId,
122
+ type: 'service',
123
+ position: { x: 0, y: 0 },
124
+ data: {
125
+ service: { name: p.name || p.id, version: p.version, summary: p.summary || '', id: p.id, owners: p.owners || [] },
126
+ contextMenu: buildContextMenuForService({ id: p.id, version: p.version }),
127
+ mode,
128
+ },
129
+ })
130
+ );
131
+ addedNodes.add(svcNodeId);
132
+ }
133
+
134
+ const prodEdgeId = `e-${svcNodeId}-${msgNodeId}`;
135
+ if (!edges.find((e) => e.id === prodEdgeId)) {
136
+ edges.push(createEdge({ id: prodEdgeId, source: svcNodeId, target: msgNodeId, label: 'produces', type: 'smoothstep' }));
137
+ }
138
+ }
139
+
140
+ // Message → Field (connects to the field node matching this occurrence's type)
141
+ const msgFieldEdgeId = `e-${msgNodeId}-${fieldNodeId}`;
142
+ if (!edges.find((e) => e.id === msgFieldEdgeId)) {
143
+ edges.push(
144
+ createEdge({
145
+ id: msgFieldEdgeId,
146
+ source: msgNodeId,
147
+ target: fieldNodeId,
148
+ label: hasConflicts ? `contains (${occType})` : 'contains',
149
+ type: 'smoothstep',
150
+ })
151
+ );
152
+ }
153
+
154
+ // Field → Consumer services (from the specific field type node)
155
+ for (const c of occ.consumers) {
156
+ const svcNodeId = `svc-consumer-${c.id}-${c.version}`;
157
+ if (!addedNodes.has(svcNodeId)) {
158
+ nodes.push(
159
+ createNode({
160
+ id: svcNodeId,
161
+ type: 'service',
162
+ position: { x: 0, y: 0 },
163
+ data: {
164
+ service: { name: c.name || c.id, version: c.version, summary: c.summary || '', id: c.id, owners: c.owners || [] },
165
+ contextMenu: buildContextMenuForService({ id: c.id, version: c.version }),
166
+ mode,
167
+ },
168
+ })
169
+ );
170
+ addedNodes.add(svcNodeId);
171
+ }
172
+
173
+ const consEdgeId = `e-${fieldNodeId}-${svcNodeId}`;
174
+ if (!edges.find((e) => e.id === consEdgeId)) {
175
+ edges.push(
176
+ createEdge({ id: consEdgeId, source: fieldNodeId, target: svcNodeId, label: 'consumed by', type: 'smoothstep' })
177
+ );
178
+ }
179
+ }
180
+ }
181
+
182
+ // Apply layout
183
+ for (const node of nodes) {
184
+ flow.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
185
+ }
186
+ for (const edge of edges) {
187
+ flow.setEdge(edge.source, edge.target);
188
+ }
189
+ dagre.layout(flow);
190
+
191
+ return { nodes: calculatedNodes(flow, nodes), edges };
192
+ };
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.25.5",
9
+ "version": "3.26.0",
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
@@ -21,10 +21,10 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "@ai-sdk/react": "^3.0.17",
24
- "@astrojs/markdown-remark": "^7.0.0",
25
- "@astrojs/mdx": "^5.0.0",
26
- "@astrojs/node": "^10.0.0",
27
- "@astrojs/react": "^5.0.0",
24
+ "@astrojs/markdown-remark": "^7.0.1",
25
+ "@astrojs/mdx": "^5.0.2",
26
+ "@astrojs/node": "^10.0.3",
27
+ "@astrojs/react": "^5.0.1",
28
28
  "@astrojs/rss": "^4.0.17",
29
29
  "@asyncapi/avro-schema-parser": "3.0.24",
30
30
  "@asyncapi/parser": "^3.6.0",
@@ -50,12 +50,13 @@
50
50
  "@tanstack/react-table": "^8.17.3",
51
51
  "@xyflow/react": "^12.3.6",
52
52
  "ai": "^6.0.17",
53
- "astro": "^6.0.2",
53
+ "astro": "^6.0.7",
54
54
  "astro-compress": "^2.3.9",
55
55
  "astro-expressive-code": "^0.41.7",
56
56
  "astro-seo": "^0.8.4",
57
57
  "auth-astro": "^4.2.0",
58
58
  "axios": "^1.13.5",
59
+ "better-sqlite3": "^12.8.0",
59
60
  "boxen": "^8.0.1",
60
61
  "commander": "^12.1.0",
61
62
  "concurrently": "^8.2.2",
@@ -102,11 +103,12 @@
102
103
  "uuid": "^10.0.0",
103
104
  "zod": "^4.3.6",
104
105
  "@eventcatalog/linter": "1.0.17",
105
- "@eventcatalog/sdk": "2.18.2",
106
- "@eventcatalog/visualiser": "^3.15.4"
106
+ "@eventcatalog/visualiser": "^3.16.0",
107
+ "@eventcatalog/sdk": "2.18.2"
107
108
  },
108
109
  "devDependencies": {
109
- "@astrojs/check": "^0.9.7",
110
+ "@astrojs/check": "^0.9.8",
111
+ "@types/better-sqlite3": "^7.6.13",
110
112
  "@types/dagre": "^0.7.52",
111
113
  "@types/diff": "^5.2.2",
112
114
  "@types/js-yaml": "^4.0.9",