@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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/catalog-to-astro-content-directory.cjs +1 -1
- package/dist/{chunk-NIGGP5OH.js → chunk-7CRFNX47.js} +1 -1
- package/dist/{chunk-G3KLCHZ7.js → chunk-ASC3AR2X.js} +1 -1
- package/dist/{chunk-KMBHKZX5.js → chunk-FQNBDDUF.js} +1 -1
- package/dist/{chunk-TQQ3EOI3.js → chunk-GCNIIIFG.js} +1 -1
- package/dist/{chunk-6QMOE3KE.js → chunk-XUN32ZVJ.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +563 -20
- package/dist/eventcatalog.js +572 -27
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +2 -1
- package/eventcatalog/integrations/eventcatalog-features.ts +13 -0
- package/eventcatalog/public/icons/graphql.svg +3 -1
- package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +225 -0
- package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +521 -0
- package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +501 -0
- package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +236 -0
- package/eventcatalog/src/enterprise/fields/field-extractor.test.ts +241 -0
- package/eventcatalog/src/enterprise/fields/field-extractor.ts +183 -0
- package/eventcatalog/src/enterprise/fields/field-indexer.ts +131 -0
- package/eventcatalog/src/enterprise/fields/fields-db.test.ts +186 -0
- package/eventcatalog/src/enterprise/fields/fields-db.ts +453 -0
- package/eventcatalog/src/enterprise/fields/pages/api/fields.ts +43 -0
- package/eventcatalog/src/enterprise/fields/pages/fields.astro +19 -0
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +23 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +14 -16
- package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +192 -0
- 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.
|
|
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.
|
|
25
|
-
"@astrojs/mdx": "^5.0.
|
|
26
|
-
"@astrojs/node": "^10.0.
|
|
27
|
-
"@astrojs/react": "^5.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.
|
|
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/
|
|
106
|
-
"@eventcatalog/
|
|
106
|
+
"@eventcatalog/visualiser": "^3.16.0",
|
|
107
|
+
"@eventcatalog/sdk": "2.18.2"
|
|
107
108
|
},
|
|
108
109
|
"devDependencies": {
|
|
109
|
-
"@astrojs/check": "^0.9.
|
|
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",
|