@eventcatalog/core 5.9.0 → 5.10.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/{chunk-WN6ZFSXF.js → chunk-5QOG7UYZ.js} +1 -1
- package/dist/{chunk-C4L6B5KR.js → chunk-EETSYUKN.js} +1 -1
- package/dist/{chunk-UIJUSHOT.js → chunk-EGOTM5ZG.js} +3 -2
- package/dist/{chunk-26C26LFE.js → chunk-EXBUNFIM.js} +1 -1
- package/dist/{chunk-SZU7I2PD.js → chunk-ZE2RPUNY.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/docs/development/00-why-eventcatalog.md +3 -0
- package/dist/docs/development/ask-your-architecture/01-intro.md +17 -4
- package/dist/docs/development/ask-your-architecture/06-sync-docs-with-your-code.md +8 -1
- package/dist/docs/development/ask-your-architecture/07-catch-breaking-changes.md +8 -1
- package/dist/docs/development/ask-your-architecture/08-check-code-against-adrs.md +169 -0
- package/dist/docs/development/guides/resources/adrs/01-introduction.md +1 -0
- package/dist/docs/development/guides/resources/entities/05-entity-maps.md +5 -0
- package/dist/docs/development/guides/resources/entities/06-global-entity-map.md +101 -0
- package/dist/docs/development/guides/resources/entities/{06-reference.md → 07-reference.md} +2 -1
- package/dist/eventcatalog.cjs +6 -5
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +3 -2
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/auth.config.ts +7 -9
- package/eventcatalog/src/components/MDX/EntityMap/CatalogEntityMap.tsx +301 -0
- package/eventcatalog/src/features/ai/chat-api.ts +2 -4
- package/eventcatalog/src/features/auth/login.astro +2 -4
- package/eventcatalog/src/features/auth/middleware/middleware.ts +2 -3
- package/eventcatalog/src/features/mcp/apps/generated/canvas.html +61 -61
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +72 -72
- package/eventcatalog/src/features/mcp/mcp-server.ts +2 -1
- package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +1 -1
- package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +2 -2
- package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +1 -1
- package/eventcatalog/src/features/studio/webmcp-relay/README.md +1 -1
- package/eventcatalog/src/features/studio/webmcp-relay/embed.js +1 -2
- package/eventcatalog/src/features/studio/webmcp-relay/widget.html +2 -1
- package/eventcatalog/src/features/studio/webmcp-relay/widget.js +2 -1
- package/eventcatalog/src/pages/visualiser/entity-map/index.astro +47 -0
- package/eventcatalog/src/pages/visualiser/graph/index.astro +2 -2
- package/eventcatalog/src/stores/sidebar-store/state.ts +10 -1
- package/eventcatalog/src/utils/catalog-modules.ts +16 -0
- package/eventcatalog/src/utils/node-graphs/catalog-entity-map-view.ts +82 -0
- package/eventcatalog/src/utils/node-graphs/catalog-entity-map.ts +113 -0
- package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +17 -61
- package/eventcatalog/src/utils/node-graphs/entity-layout.ts +53 -0
- package/eventcatalog/src/utils/node-graphs/flow-lanes.ts +2 -2
- package/package.json +6 -6
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { getCollection, getEntry } from 'astro:content';
|
|
2
2
|
import { generateIdForNode } from './utils/utils';
|
|
3
|
-
import ELK from 'elkjs/lib/elk.bundled.js';
|
|
4
3
|
import { MarkerType } from '@xyflow/react';
|
|
5
4
|
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
6
5
|
import { getVersionFromCollection } from '@utils/collections/versions';
|
|
7
6
|
import { getEntities, type Entity } from '@utils/collections/entities';
|
|
8
7
|
import { getDomains, type Domain } from '@utils/collections/domains';
|
|
9
8
|
import { getServices, type Service } from '@utils/collections/services';
|
|
10
|
-
|
|
11
|
-
const elk = new ELK();
|
|
9
|
+
import { layoutEntityNodes } from './entity-layout';
|
|
12
10
|
|
|
13
11
|
export const ENTITY_TARGET_HANDLE_ID = '__eventcatalog-entity-target';
|
|
14
12
|
|
|
15
|
-
const getReferencedEntityId = (property: any, entityMap: Map<string, Entity[]>) => {
|
|
13
|
+
export const getReferencedEntityId = (property: any, entityMap: Map<string, Entity[]>) => {
|
|
16
14
|
if (property.references) return property.references;
|
|
17
15
|
if (property.type === 'array' && property.items?.type && entityMap.has(property.items.type)) return property.items.type;
|
|
18
16
|
return undefined;
|
|
19
17
|
};
|
|
20
18
|
|
|
21
|
-
const getReferencePropertyNames = (entity: Entity, entityMap: Map<string, Entity[]>) =>
|
|
19
|
+
export const getReferencePropertyNames = (entity: Entity, entityMap: Map<string, Entity[]>) =>
|
|
22
20
|
entity.data.properties
|
|
23
21
|
?.filter((property: any) => getReferencedEntityId(property, entityMap))
|
|
24
22
|
.map((property: any) => property.name) ?? [];
|
|
@@ -151,6 +149,19 @@ export const getNodesAndEdges = async ({ id, version, entities, type = 'domains'
|
|
|
151
149
|
// Create complete list of entities for edge creation and layout
|
|
152
150
|
const allEntitiesInGraph = [...resourceEntities, ...addedExternalEntities];
|
|
153
151
|
|
|
152
|
+
edges = createEntityReferenceEdges(entitiesWithReferences, allEntitiesInGraph, entityMap);
|
|
153
|
+
|
|
154
|
+
return { nodes: await layoutEntityNodes(nodes, edges), edges };
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/** The edges between entities: one for each property referencing another entity in the graph */
|
|
158
|
+
export const createEntityReferenceEdges = (
|
|
159
|
+
entitiesWithReferences: Entity[],
|
|
160
|
+
allEntitiesInGraph: Entity[],
|
|
161
|
+
entityMap: Map<string, Entity[]>
|
|
162
|
+
) => {
|
|
163
|
+
const edges: any[] = [];
|
|
164
|
+
|
|
154
165
|
// Go through any entities that are related to other entities
|
|
155
166
|
for (const entity of entitiesWithReferences) {
|
|
156
167
|
// Get a list of properties that reference other entities
|
|
@@ -220,60 +231,5 @@ export const getNodesAndEdges = async ({ id, version, entities, type = 'domains'
|
|
|
220
231
|
}
|
|
221
232
|
}
|
|
222
233
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
// Separate entities with and without relationships (including external entities)
|
|
226
|
-
const entitiesWithRelationships = allEntitiesInGraph.filter((entity) => {
|
|
227
|
-
// Has outgoing references
|
|
228
|
-
const hasOutgoingRefs = entity.data.properties?.some((property: any) => getReferencedEntityId(property, entityMap));
|
|
229
|
-
// Has incoming references (is referenced by others)
|
|
230
|
-
const hasIncomingRefs = entitiesWithReferences.some((e: any) =>
|
|
231
|
-
e.data.properties?.some((prop: any) => getReferencedEntityId(prop, entityMap) === entity.data.id)
|
|
232
|
-
);
|
|
233
|
-
return hasOutgoingRefs || hasIncomingRefs;
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
// Prepare ELK graph structure
|
|
237
|
-
const elkNodes = nodes.map((node: any) => ({
|
|
238
|
-
id: node.id,
|
|
239
|
-
width: 220,
|
|
240
|
-
height: Math.max(120, 72 + (node.data.entity.data.properties?.length ?? 0) * 40),
|
|
241
|
-
}));
|
|
242
|
-
|
|
243
|
-
const elkEdges = edges.map((edge: any) => ({
|
|
244
|
-
id: edge.id,
|
|
245
|
-
sources: [edge.source],
|
|
246
|
-
targets: [edge.target],
|
|
247
|
-
}));
|
|
248
|
-
|
|
249
|
-
const elkGraph = {
|
|
250
|
-
id: 'root',
|
|
251
|
-
layoutOptions: {
|
|
252
|
-
'elk.algorithm': 'force',
|
|
253
|
-
'elk.force.iterations': '300',
|
|
254
|
-
'elk.spacing.nodeNode': '45',
|
|
255
|
-
'elk.spacing.componentComponent': '50',
|
|
256
|
-
'elk.padding': '[top=30,left=30,bottom=30,right=30]',
|
|
257
|
-
'elk.separateConnectedComponents': 'true',
|
|
258
|
-
},
|
|
259
|
-
children: elkNodes,
|
|
260
|
-
edges: elkEdges,
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
// Run ELK layout
|
|
264
|
-
const layoutedGraph = await elk.layout(elkGraph);
|
|
265
|
-
|
|
266
|
-
// Apply positions to nodes
|
|
267
|
-
const positionedNodes = nodes.map((node: any) => {
|
|
268
|
-
const elkNode = layoutedGraph.children?.find((n: any) => n.id === node.id);
|
|
269
|
-
return {
|
|
270
|
-
...node,
|
|
271
|
-
position: {
|
|
272
|
-
x: elkNode?.x || 0,
|
|
273
|
-
y: elkNode?.y || 0,
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
return { nodes: positionedNodes, edges };
|
|
234
|
+
return edges;
|
|
279
235
|
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How entity maps are laid out: ELK's force layout, each entity sized by how many properties it has.
|
|
3
|
+
* Kept apart from the graph builders (which read the catalog's collections), so the catalog's entity
|
|
4
|
+
* map can lay out what it shows in the browser the same way.
|
|
5
|
+
*/
|
|
6
|
+
import ELK from 'elkjs/lib/elk.bundled.js';
|
|
7
|
+
import { getNodeSize } from '@eventcatalog/visualiser/layout';
|
|
8
|
+
|
|
9
|
+
const elk = new ELK();
|
|
10
|
+
|
|
11
|
+
/** Places entities with ELK's force layout, sized by how many properties they have */
|
|
12
|
+
export const layoutEntityNodes = async (nodes: any[], edges: any[]) => {
|
|
13
|
+
// Prepare ELK graph structure
|
|
14
|
+
// Sized as the visualiser estimates them (a row for each property), so the catalog and the browser agree
|
|
15
|
+
const elkNodes = nodes.map((node: any) => ({ id: node.id, ...getNodeSize(node) }));
|
|
16
|
+
|
|
17
|
+
const elkEdges = edges.map((edge: any) => ({
|
|
18
|
+
id: edge.id,
|
|
19
|
+
sources: [edge.source],
|
|
20
|
+
targets: [edge.target],
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
const elkGraph = {
|
|
24
|
+
id: 'root',
|
|
25
|
+
layoutOptions: {
|
|
26
|
+
'elk.algorithm': 'force',
|
|
27
|
+
'elk.force.iterations': '300',
|
|
28
|
+
'elk.spacing.nodeNode': '45',
|
|
29
|
+
'elk.spacing.componentComponent': '50',
|
|
30
|
+
'elk.padding': '[top=30,left=30,bottom=30,right=30]',
|
|
31
|
+
'elk.separateConnectedComponents': 'true',
|
|
32
|
+
},
|
|
33
|
+
children: elkNodes,
|
|
34
|
+
edges: elkEdges,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Run ELK layout
|
|
38
|
+
const layoutedGraph = await elk.layout(elkGraph);
|
|
39
|
+
|
|
40
|
+
// Apply positions to nodes
|
|
41
|
+
const positionedNodes = nodes.map((node: any) => {
|
|
42
|
+
const elkNode = layoutedGraph.children?.find((n: any) => n.id === node.id);
|
|
43
|
+
return {
|
|
44
|
+
...node,
|
|
45
|
+
position: {
|
|
46
|
+
x: elkNode?.x || 0,
|
|
47
|
+
y: elkNode?.y || 0,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return positionedNodes;
|
|
53
|
+
};
|
|
@@ -30,8 +30,8 @@ type Resource = { data: { id: string; name?: string; owners?: (string | { id: st
|
|
|
30
30
|
|
|
31
31
|
// Lanes use the latest version of each domain and system (as the collection
|
|
32
32
|
// utils do when they don't ask for every version)
|
|
33
|
-
const isLatest = (entry: { filePath?: string }) => !entry.filePath?.includes('versioned');
|
|
34
|
-
const toLane = (entry: Resource): Lane => ({ id: entry.data.id, name: entry.data.name || entry.data.id });
|
|
33
|
+
export const isLatest = (entry: { filePath?: string }) => !entry.filePath?.includes('versioned');
|
|
34
|
+
export const toLane = (entry: Resource): Lane => ({ id: entry.data.id, name: entry.data.name || entry.data.id });
|
|
35
35
|
const pointerIds = (pointers?: { id: string }[]) => (pointers || []).map((pointer) => pointer.id);
|
|
36
36
|
|
|
37
37
|
/**
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"license": "BUSL-1.1",
|
|
9
9
|
"type": "module",
|
|
10
|
-
"version": "5.
|
|
10
|
+
"version": "5.10.0",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@hocuspocus/provider": "^4.7.0",
|
|
64
64
|
"@hocuspocus/server": "^4.7.0",
|
|
65
65
|
"@iconify-json/logos": "^1.2.4",
|
|
66
|
-
"@mcp-b/webmcp-polyfill": "
|
|
66
|
+
"@mcp-b/webmcp-polyfill": "6.0.3",
|
|
67
67
|
"@mermaid-js/layout-elk": "^0.2.0",
|
|
68
68
|
"@modelcontextprotocol/client": "2.3.1",
|
|
69
69
|
"@modelcontextprotocol/ext-apps": "2.0.3",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"diff2html": "^3.4.56",
|
|
96
96
|
"dotenv": "^16.5.0",
|
|
97
97
|
"elkjs": "^0.10.0",
|
|
98
|
-
"glob": "^13.0.
|
|
98
|
+
"glob": "^13.0.7",
|
|
99
99
|
"gray-matter": "^4.0.3",
|
|
100
100
|
"hono": "^4.13.7",
|
|
101
101
|
"html-to-image": "^1.11.11",
|
|
@@ -142,10 +142,10 @@
|
|
|
142
142
|
"yjs": "^13.6.33",
|
|
143
143
|
"zod": "^4.6.6",
|
|
144
144
|
"@eventcatalog/exporters": "0.1.4",
|
|
145
|
-
"@eventcatalog/sdk": "2.32.0",
|
|
146
|
-
"@eventcatalog/visualiser": "^5.2.5",
|
|
147
145
|
"@eventcatalog/fitness": "0.1.1",
|
|
148
|
-
"@eventcatalog/linter": "1.3.1"
|
|
146
|
+
"@eventcatalog/linter": "1.3.1",
|
|
147
|
+
"@eventcatalog/sdk": "2.32.0",
|
|
148
|
+
"@eventcatalog/visualiser": "^5.3.0"
|
|
149
149
|
},
|
|
150
150
|
"devDependencies": {
|
|
151
151
|
"@astrojs/check": "^0.9.10",
|