@eventcatalog/core 4.10.7 → 4.10.9
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-RJYRPQOA.js → chunk-3EEFSHHW.js} +1 -1
- package/dist/{chunk-Z7YK3QA3.js → chunk-5WB6CXZH.js} +1 -1
- package/dist/{chunk-YBRQCBWG.js → chunk-BYPWHDX6.js} +1 -1
- package/dist/{chunk-YJVD7UW3.js → chunk-ONRJA5DX.js} +1 -1
- package/dist/{chunk-TFALFJEC.js → chunk-WD5UW4A4.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +8 -8
- 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/src/components/MDX/NodeGraph/NodeGraph.astro +6 -2
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/_index.data.spec.ts +52 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/_index.data.ts +20 -11
- package/eventcatalog/src/stores/sidebar-store/state.ts +3 -28
- package/eventcatalog/src/utils/collections/field-usage.ts +48 -0
- package/eventcatalog/src/utils/node-graphs/channel-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/compact-visualiser-graph.ts +246 -0
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +2 -2
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +8 -3
- package/eventcatalog/src/utils/node-graphs/utils/utils.ts +30 -2
- package/package.json +4 -4
|
@@ -140,7 +140,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
|
|
|
140
140
|
var import_os = __toESM(require("os"), 1);
|
|
141
141
|
|
|
142
142
|
// package.json
|
|
143
|
-
var version = "4.10.
|
|
143
|
+
var version = "4.10.9";
|
|
144
144
|
|
|
145
145
|
// src/constants.ts
|
|
146
146
|
var VERSION = version;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log_build_default
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-ONRJA5DX.js";
|
|
4
|
+
import "../chunk-5WB6CXZH.js";
|
|
5
5
|
import "../chunk-ZAZHAVKB.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-3EEFSHHW.js";
|
|
7
7
|
import "../chunk-6QENHZZP.js";
|
|
8
8
|
export {
|
|
9
9
|
log_build_default as default
|
package/dist/constants.cjs
CHANGED
package/dist/constants.js
CHANGED
package/dist/eventcatalog.cjs
CHANGED
|
@@ -144,7 +144,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
|
|
|
144
144
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
145
145
|
|
|
146
146
|
// package.json
|
|
147
|
-
var version = "4.10.
|
|
147
|
+
var version = "4.10.9";
|
|
148
148
|
|
|
149
149
|
// src/constants.ts
|
|
150
150
|
var VERSION = version;
|
package/dist/eventcatalog.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
log_build_default
|
|
3
|
+
} from "./chunk-ONRJA5DX.js";
|
|
4
|
+
import "./chunk-5WB6CXZH.js";
|
|
5
|
+
import "./chunk-ZAZHAVKB.js";
|
|
1
6
|
import {
|
|
2
7
|
runMigrations
|
|
3
8
|
} from "./chunk-XUAF2H54.js";
|
|
4
9
|
import "./chunk-CA4U2JP7.js";
|
|
5
|
-
import {
|
|
6
|
-
log_build_default
|
|
7
|
-
} from "./chunk-YJVD7UW3.js";
|
|
8
|
-
import "./chunk-Z7YK3QA3.js";
|
|
9
|
-
import "./chunk-ZAZHAVKB.js";
|
|
10
10
|
import {
|
|
11
11
|
FederationConflictError,
|
|
12
12
|
FederationDiagnosticError,
|
|
@@ -31,10 +31,10 @@ import {
|
|
|
31
31
|
} from "./chunk-B7HCX5HM.js";
|
|
32
32
|
import {
|
|
33
33
|
generate
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-WD5UW4A4.js";
|
|
35
35
|
import {
|
|
36
36
|
logger
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-BYPWHDX6.js";
|
|
38
38
|
import {
|
|
39
39
|
resolve_catalog_dependencies_default
|
|
40
40
|
} from "./chunk-LHR4G2UO.js";
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
import "./chunk-W5JQON7Z.js";
|
|
55
55
|
import {
|
|
56
56
|
VERSION
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-3EEFSHHW.js";
|
|
58
58
|
import {
|
|
59
59
|
linkCoreNodeModules,
|
|
60
60
|
resolveInstalledCoreNodeModules
|
package/dist/generate.cjs
CHANGED
|
@@ -108,7 +108,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
|
|
|
108
108
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
109
109
|
|
|
110
110
|
// package.json
|
|
111
|
-
var version = "4.10.
|
|
111
|
+
var version = "4.10.9";
|
|
112
112
|
|
|
113
113
|
// src/constants.ts
|
|
114
114
|
var VERSION = version;
|
package/dist/generate.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generate
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-WD5UW4A4.js";
|
|
4
|
+
import "./chunk-BYPWHDX6.js";
|
|
5
|
+
import "./chunk-3EEFSHHW.js";
|
|
6
6
|
import "./chunk-6QENHZZP.js";
|
|
7
7
|
export {
|
|
8
8
|
generate
|
package/dist/utils/cli-logger.js
CHANGED
|
@@ -31,6 +31,7 @@ import { getNodesAndEdges as getNodesAndEdgesForChannel } from '@utils/node-grap
|
|
|
31
31
|
import config from '@config';
|
|
32
32
|
import { isEventCatalogChatEnabled, isDevMode } from '@utils/feature';
|
|
33
33
|
import { loadSavedLayout, applyLayoutToNodes, buildResourceKey } from '@utils/node-graphs/layout-persistence';
|
|
34
|
+
import { compactVisualiserGraph } from '@utils/node-graphs/compact-visualiser-graph';
|
|
34
35
|
|
|
35
36
|
const isChatEnabled = isEventCatalogChatEnabled();
|
|
36
37
|
|
|
@@ -198,13 +199,16 @@ if (collection === 'services-containers') {
|
|
|
198
199
|
const resourceKey = buildResourceKey(collection, id, version);
|
|
199
200
|
const savedLayout = await loadSavedLayout(resourceKey);
|
|
200
201
|
const nodesWithLayout = applyLayoutToNodes(nodes as any[], savedLayout);
|
|
202
|
+
// Drop hydrated collection entries / markdown bodies before Astro serialises
|
|
203
|
+
// the graph into the page. Visualiser components only need a small field set.
|
|
204
|
+
const { nodes: clientNodes, edges: clientEdges } = compactVisualiserGraph(nodesWithLayout as any[], edges as any[]);
|
|
201
205
|
---
|
|
202
206
|
|
|
203
207
|
<div>
|
|
204
208
|
<AstroNodeGraph
|
|
205
209
|
id={id}
|
|
206
|
-
nodes={
|
|
207
|
-
edges={
|
|
210
|
+
nodes={clientNodes}
|
|
211
|
+
edges={clientEdges}
|
|
208
212
|
title={title}
|
|
209
213
|
hrefLabel={href?.label}
|
|
210
214
|
href={href?.url}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
const getMessageIdsWithFieldUsage = vi.fn();
|
|
4
|
+
const pageDataLoader = {
|
|
5
|
+
events: vi.fn(),
|
|
6
|
+
commands: vi.fn(),
|
|
7
|
+
queries: vi.fn(),
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
vi.mock('@utils/feature', () => ({
|
|
11
|
+
isSSR: () => false,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock('@utils/collections/field-usage', () => ({
|
|
15
|
+
getMessageIdsWithFieldUsage: () => getMessageIdsWithFieldUsage(),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
vi.mock('@utils/page-loaders/page-data-loader', () => ({
|
|
19
|
+
pageDataLoader,
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
import { Page } from './_index.data';
|
|
23
|
+
|
|
24
|
+
const event = (id: string) => ({
|
|
25
|
+
collection: 'events',
|
|
26
|
+
data: { id, version: '1.0.0', name: id },
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('field-lineage static paths', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
getMessageIdsWithFieldUsage.mockReset();
|
|
32
|
+
pageDataLoader.events.mockReset();
|
|
33
|
+
pageDataLoader.commands.mockReset();
|
|
34
|
+
pageDataLoader.queries.mockReset();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('when we build a catalog, field usage pages are only created for messages that declare fields', async () => {
|
|
38
|
+
getMessageIdsWithFieldUsage.mockResolvedValue(new Set(['OrderCreated']));
|
|
39
|
+
pageDataLoader.events.mockResolvedValue([event('OrderCreated'), event('OrderCancelled')]);
|
|
40
|
+
pageDataLoader.commands.mockResolvedValue([]);
|
|
41
|
+
pageDataLoader.queries.mockResolvedValue([]);
|
|
42
|
+
|
|
43
|
+
const paths = await Page.getStaticPaths();
|
|
44
|
+
|
|
45
|
+
expect(paths).toEqual([
|
|
46
|
+
{
|
|
47
|
+
params: { type: 'events', id: 'OrderCreated', version: '1.0.0' },
|
|
48
|
+
props: { type: 'events', ...event('OrderCreated') },
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isSSR } from '@utils/feature';
|
|
2
2
|
import { HybridPage } from '@utils/page-loaders/hybrid-page';
|
|
3
3
|
import type { PageTypes } from '@types';
|
|
4
|
+
import { getMessageIdsWithFieldUsage } from '@utils/collections/field-usage';
|
|
4
5
|
|
|
5
6
|
const MESSAGE_TYPES: PageTypes[] = ['events', 'commands', 'queries'];
|
|
6
7
|
|
|
@@ -15,21 +16,24 @@ export class Page extends HybridPage {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
|
|
19
|
+
const messagesWithFieldUsage = await getMessageIdsWithFieldUsage();
|
|
18
20
|
|
|
19
21
|
const allItems = await Promise.all(MESSAGE_TYPES.map((type) => pageDataLoader[type]()));
|
|
20
22
|
|
|
21
23
|
return allItems.flatMap((items, index) =>
|
|
22
|
-
items
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
items
|
|
25
|
+
.filter((item) => messagesWithFieldUsage.has(item.data.id))
|
|
26
|
+
.map((item) => ({
|
|
27
|
+
params: {
|
|
28
|
+
type: MESSAGE_TYPES[index],
|
|
29
|
+
id: item.data.id,
|
|
30
|
+
version: item.data.version,
|
|
31
|
+
},
|
|
32
|
+
props: {
|
|
33
|
+
type: MESSAGE_TYPES[index],
|
|
34
|
+
...item,
|
|
35
|
+
},
|
|
36
|
+
}))
|
|
33
37
|
);
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -40,6 +44,11 @@ export class Page extends HybridPage {
|
|
|
40
44
|
return null;
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
const messagesWithFieldUsage = await getMessageIdsWithFieldUsage();
|
|
48
|
+
if (!messagesWithFieldUsage.has(id)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
|
|
44
53
|
|
|
45
54
|
const items = await pageDataLoader[type as PageTypes]();
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
withArchitectureDecisionsSection,
|
|
43
43
|
} from './builders/shared';
|
|
44
44
|
import { isArchitectureGraphEnabled, isChangelogEnabled, isResourceDocsEnabled } from '@utils/feature';
|
|
45
|
+
import { collectMessageIdsWithFieldUsage } from '@utils/collections/field-usage';
|
|
45
46
|
|
|
46
47
|
export type { NavigationData, NavNode, ChildRef };
|
|
47
48
|
|
|
@@ -580,34 +581,8 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
580
581
|
{} as Record<string, NavNode | string>
|
|
581
582
|
);
|
|
582
583
|
|
|
583
|
-
//
|
|
584
|
-
|
|
585
|
-
// sends/receives pointers with resolved message entries, which strips the fields property.
|
|
586
|
-
const messagesWithFieldUsage = new Set<string>();
|
|
587
|
-
for (const agent of rawAgents) {
|
|
588
|
-
for (const pointer of agent.data.sends || []) {
|
|
589
|
-
if (pointer.fields?.length) messagesWithFieldUsage.add(pointer.id);
|
|
590
|
-
}
|
|
591
|
-
for (const pointer of agent.data.receives || []) {
|
|
592
|
-
if (pointer.fields?.length) messagesWithFieldUsage.add(pointer.id);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
for (const service of rawServices) {
|
|
596
|
-
for (const pointer of service.data.sends || []) {
|
|
597
|
-
if (pointer.fields?.length) messagesWithFieldUsage.add(pointer.id);
|
|
598
|
-
}
|
|
599
|
-
for (const pointer of service.data.receives || []) {
|
|
600
|
-
if (pointer.fields?.length) messagesWithFieldUsage.add(pointer.id);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
for (const domain of rawDomains) {
|
|
604
|
-
for (const pointer of domain.data.sends || []) {
|
|
605
|
-
if (pointer.fields?.length) messagesWithFieldUsage.add(pointer.id);
|
|
606
|
-
}
|
|
607
|
-
for (const pointer of domain.data.receives || []) {
|
|
608
|
-
if (pointer.fields?.length) messagesWithFieldUsage.add(pointer.id);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
584
|
+
// Raw collections keep send/receive pointers (and their `fields`) which hydration strips.
|
|
585
|
+
const messagesWithFieldUsage = collectMessageIdsWithFieldUsage(rawAgents, rawServices, rawDomains);
|
|
611
586
|
|
|
612
587
|
const flowRefsByMessage = buildFlowReferencesByMessage({
|
|
613
588
|
flows,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getCollection } from 'astro:content';
|
|
2
|
+
|
|
3
|
+
type PointerWithFields = { id?: string; fields?: string[] };
|
|
4
|
+
|
|
5
|
+
type ResourceWithMessagePointers = {
|
|
6
|
+
data: {
|
|
7
|
+
sends?: PointerWithFields[];
|
|
8
|
+
receives?: PointerWithFields[];
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const addFieldUsageFromPointers = (messageIds: Set<string>, pointers: PointerWithFields[] | undefined) => {
|
|
13
|
+
for (const pointer of pointers || []) {
|
|
14
|
+
if (pointer.id && pointer.fields?.length) {
|
|
15
|
+
messageIds.add(pointer.id);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Message ids that have field-level lineage declared on a send/receive pointer.
|
|
22
|
+
* Uses raw (unhydrated) resources because hydration replaces those pointers and drops `fields`.
|
|
23
|
+
* Matches the sidebar "Field Usage" link gate.
|
|
24
|
+
*/
|
|
25
|
+
export const collectMessageIdsWithFieldUsage = (
|
|
26
|
+
agents: ResourceWithMessagePointers[],
|
|
27
|
+
services: ResourceWithMessagePointers[],
|
|
28
|
+
domains: ResourceWithMessagePointers[]
|
|
29
|
+
): Set<string> => {
|
|
30
|
+
const messageIds = new Set<string>();
|
|
31
|
+
|
|
32
|
+
for (const resource of [...agents, ...services, ...domains]) {
|
|
33
|
+
addFieldUsageFromPointers(messageIds, resource.data.sends);
|
|
34
|
+
addFieldUsageFromPointers(messageIds, resource.data.receives);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return messageIds;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const getMessageIdsWithFieldUsage = async (): Promise<Set<string>> => {
|
|
41
|
+
const [agents, services, domains] = await Promise.all([
|
|
42
|
+
getCollection('agents'),
|
|
43
|
+
getCollection('services'),
|
|
44
|
+
getCollection('domains'),
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
return collectMessageIdsWithFieldUsage(agents, services, domains);
|
|
48
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
|
-
import dagre from 'dagre';
|
|
3
2
|
import {
|
|
4
3
|
buildContextMenuForAgent,
|
|
5
4
|
buildContextMenuForMessage,
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
getOperationFields,
|
|
18
17
|
DEFAULT_NODE_WIDTH,
|
|
19
18
|
DEFAULT_NODE_HEIGHT,
|
|
19
|
+
layoutDagreGraph,
|
|
20
20
|
} from './utils/utils';
|
|
21
21
|
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
22
22
|
import { getChannelChain, getChannels } from '@utils/collections/channels';
|
|
@@ -457,7 +457,7 @@ export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simpl
|
|
|
457
457
|
});
|
|
458
458
|
|
|
459
459
|
if (layout) {
|
|
460
|
-
|
|
460
|
+
layoutDagreGraph(flow);
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
return {
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import type { Edge, Node } from '@xyflow/react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fields the visualiser nodes actually read from a resource. Everything else
|
|
5
|
+
* (markdown bodies, file paths, hydrated producers/consumers, full send/receive
|
|
6
|
+
* collections) is dropped before Astro serialises the graph into the page.
|
|
7
|
+
*/
|
|
8
|
+
const RESOURCE_DATA_KEYS = [
|
|
9
|
+
'id',
|
|
10
|
+
'name',
|
|
11
|
+
'version',
|
|
12
|
+
'summary',
|
|
13
|
+
'owners',
|
|
14
|
+
'deprecated',
|
|
15
|
+
'draft',
|
|
16
|
+
'notes',
|
|
17
|
+
'styles',
|
|
18
|
+
'badges',
|
|
19
|
+
'latestVersion',
|
|
20
|
+
'method',
|
|
21
|
+
'path',
|
|
22
|
+
'statusCodes',
|
|
23
|
+
'specifications',
|
|
24
|
+
'externalSystem',
|
|
25
|
+
'repository',
|
|
26
|
+
'model',
|
|
27
|
+
'tools',
|
|
28
|
+
'parameters',
|
|
29
|
+
'protocols',
|
|
30
|
+
'address',
|
|
31
|
+
'deliveryGuarantee',
|
|
32
|
+
'type',
|
|
33
|
+
'container_type',
|
|
34
|
+
'schemas',
|
|
35
|
+
'properties',
|
|
36
|
+
'aggregateRoot',
|
|
37
|
+
'sidebar',
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
40
|
+
const RESOURCE_OBJECT_KEYS = new Set([
|
|
41
|
+
'message',
|
|
42
|
+
'service',
|
|
43
|
+
'agent',
|
|
44
|
+
'domain',
|
|
45
|
+
'channel',
|
|
46
|
+
'dataProduct',
|
|
47
|
+
'container',
|
|
48
|
+
'entity',
|
|
49
|
+
'flow',
|
|
50
|
+
'data',
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
const DROP_EDGE_RESOURCE_KEYS = new Set(['publisherService', 'consumerService']);
|
|
54
|
+
|
|
55
|
+
const isPlainObject = (value: unknown): value is Record<string, unknown> =>
|
|
56
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
57
|
+
|
|
58
|
+
const isCollectionEntry = (value: Record<string, unknown>): boolean =>
|
|
59
|
+
isPlainObject(value.data) &&
|
|
60
|
+
('collection' in value || 'filePath' in value || 'digest' in value || 'body' in value || 'rendered' in value);
|
|
61
|
+
|
|
62
|
+
const compactDomainService = (service: unknown) => {
|
|
63
|
+
if (!isPlainObject(service)) return service;
|
|
64
|
+
|
|
65
|
+
const data = isPlainObject(service.data) ? service.data : service;
|
|
66
|
+
const id = data.id ?? service.id;
|
|
67
|
+
const name = data.name ?? service.name;
|
|
68
|
+
const version = data.version ?? service.version;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
data: {
|
|
72
|
+
...(id !== undefined ? { id } : {}),
|
|
73
|
+
...(name !== undefined ? { name } : {}),
|
|
74
|
+
...(version !== undefined ? { version } : {}),
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const compactOwners = (owners: unknown): unknown => {
|
|
80
|
+
if (!Array.isArray(owners)) return owners;
|
|
81
|
+
return owners.map((owner) => {
|
|
82
|
+
if (typeof owner === 'string') return owner;
|
|
83
|
+
if (!isPlainObject(owner)) return owner;
|
|
84
|
+
const data = isPlainObject(owner.data) ? owner.data : owner;
|
|
85
|
+
const id = data.id ?? owner.id;
|
|
86
|
+
const name = data.name ?? owner.name;
|
|
87
|
+
if (id === undefined && name === undefined) return owner;
|
|
88
|
+
return {
|
|
89
|
+
...(id !== undefined ? { id } : {}),
|
|
90
|
+
...(name !== undefined ? { name } : {}),
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const compactVisualiserResource = (value: unknown): unknown => {
|
|
96
|
+
if (value == null || typeof value !== 'object') return value;
|
|
97
|
+
if (Array.isArray(value)) return value.map(compactVisualiserResource);
|
|
98
|
+
|
|
99
|
+
const obj = value as Record<string, unknown>;
|
|
100
|
+
|
|
101
|
+
if (isCollectionEntry(obj)) {
|
|
102
|
+
const data = compactVisualiserResourceData(obj.data);
|
|
103
|
+
const resourceId = isPlainObject(data) && data.id !== undefined ? data.id : obj.id;
|
|
104
|
+
return {
|
|
105
|
+
...(resourceId !== undefined ? { id: resourceId } : {}),
|
|
106
|
+
...(obj.collection !== undefined ? { collection: obj.collection } : {}),
|
|
107
|
+
data,
|
|
108
|
+
// EventNode / ServiceNode / ChannelNode read name/version/summary from the
|
|
109
|
+
// top level. Collection-entry shaped payloads only have those on `.data`.
|
|
110
|
+
...(isPlainObject(data) ? data : {}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return compactVisualiserResourceData(obj);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const compactVisualiserResourceData = (value: unknown): unknown => {
|
|
118
|
+
if (!isPlainObject(value)) return value;
|
|
119
|
+
|
|
120
|
+
const out: Record<string, unknown> = {};
|
|
121
|
+
for (const key of RESOURCE_DATA_KEYS) {
|
|
122
|
+
if (value[key] === undefined) continue;
|
|
123
|
+
if (key === 'owners') {
|
|
124
|
+
out[key] = compactOwners(value[key]);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (key === 'tools' && Array.isArray(value[key])) {
|
|
128
|
+
out[key] = value[key];
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
out[key] = value[key];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Domain nodes render `domain.data.services[].data.{id,name,version}`.
|
|
135
|
+
if (Array.isArray(value.services)) {
|
|
136
|
+
out.services = value.services.map(compactDomainService);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return out;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const compactEndpoint = (endpoint: unknown): unknown => {
|
|
143
|
+
if (!isPlainObject(endpoint)) return endpoint;
|
|
144
|
+
|
|
145
|
+
const data = isPlainObject(endpoint.data) ? endpoint.data : undefined;
|
|
146
|
+
const collection = endpoint.collection ?? data?.collection;
|
|
147
|
+
const id = endpoint.id ?? (data?.id !== undefined && data?.version !== undefined ? `${data.id}-${data.version}` : data?.id);
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
...(id !== undefined ? { id } : {}),
|
|
151
|
+
...(collection !== undefined ? { collection } : {}),
|
|
152
|
+
...(data
|
|
153
|
+
? {
|
|
154
|
+
data: {
|
|
155
|
+
...(data.id !== undefined ? { id: data.id } : {}),
|
|
156
|
+
...(data.version !== undefined ? { version: data.version } : {}),
|
|
157
|
+
...(collection !== undefined ? { collection } : {}),
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
: {}),
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const compactNodeData = (data: unknown): unknown => {
|
|
165
|
+
if (!isPlainObject(data)) return data;
|
|
166
|
+
|
|
167
|
+
const out: Record<string, unknown> = {};
|
|
168
|
+
|
|
169
|
+
for (const [key, value] of Object.entries(data)) {
|
|
170
|
+
if (value === undefined) continue;
|
|
171
|
+
|
|
172
|
+
if (RESOURCE_OBJECT_KEYS.has(key)) {
|
|
173
|
+
out[key] = compactVisualiserResource(value);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (key === 'messages' && Array.isArray(value)) {
|
|
178
|
+
out[key] = value.map((entry) => {
|
|
179
|
+
if (!isPlainObject(entry)) return entry;
|
|
180
|
+
return {
|
|
181
|
+
...entry,
|
|
182
|
+
...(entry.message !== undefined ? { message: compactVisualiserResource(entry.message) } : {}),
|
|
183
|
+
...(Array.isArray(entry.channels) ? { channels: entry.channels.map(compactVisualiserResource) } : {}),
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
out[key] = value;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return out;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const compactEdgeData = (data: unknown): unknown => {
|
|
196
|
+
if (!isPlainObject(data)) return data;
|
|
197
|
+
|
|
198
|
+
const out: Record<string, unknown> = {};
|
|
199
|
+
|
|
200
|
+
for (const [key, value] of Object.entries(data)) {
|
|
201
|
+
if (value === undefined || DROP_EDGE_RESOURCE_KEYS.has(key)) continue;
|
|
202
|
+
|
|
203
|
+
if (key === 'rootSourceAndTarget' && isPlainObject(value)) {
|
|
204
|
+
out[key] = {
|
|
205
|
+
source: compactEndpoint(value.source),
|
|
206
|
+
target: compactEndpoint(value.target),
|
|
207
|
+
};
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (RESOURCE_OBJECT_KEYS.has(key) || key === 'message') {
|
|
212
|
+
out[key] = compactVisualiserResource(value);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
out[key] = value;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return out;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const compactNode = <T extends Node>(node: T): T => {
|
|
223
|
+
const { data, ...rest } = node;
|
|
224
|
+
return {
|
|
225
|
+
...rest,
|
|
226
|
+
...(data !== undefined ? { data: compactNodeData(data) } : {}),
|
|
227
|
+
} as T;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const compactEdge = <T extends Edge>(edge: T): T => {
|
|
231
|
+
const { data, ...rest } = edge;
|
|
232
|
+
return {
|
|
233
|
+
...rest,
|
|
234
|
+
...(data !== undefined ? { data: compactEdgeData(data) } : {}),
|
|
235
|
+
} as T;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Strip collection-entry weight from a React Flow graph before it is serialised
|
|
240
|
+
* into an Astro island. Node/edge structure and the fields visualiser components
|
|
241
|
+
* read are preserved.
|
|
242
|
+
*/
|
|
243
|
+
export const compactVisualiserGraph = <N extends Node, E extends Edge>(nodes: N[], edges: E[]): { nodes: N[]; edges: E[] } => ({
|
|
244
|
+
nodes: nodes.map(compactNode),
|
|
245
|
+
edges: edges.map(compactEdge),
|
|
246
|
+
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { CollectionEntry } from 'astro:content';
|
|
2
|
-
import dagre from 'dagre';
|
|
3
2
|
import {
|
|
4
3
|
calculatedNodes,
|
|
5
4
|
createDagreGraph,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
buildContextMenuForResource,
|
|
11
10
|
DEFAULT_NODE_WIDTH,
|
|
12
11
|
DEFAULT_NODE_HEIGHT,
|
|
12
|
+
layoutDagreGraph,
|
|
13
13
|
} from './utils/utils';
|
|
14
14
|
import { MarkerType } from '@xyflow/react';
|
|
15
15
|
import { findMatchingNodes } from '@utils/collections/util';
|
|
@@ -299,7 +299,7 @@ export const getNodesAndEdges = async ({
|
|
|
299
299
|
|
|
300
300
|
// Render the diagram in memory getting hte X and Y
|
|
301
301
|
if (layout) {
|
|
302
|
-
|
|
302
|
+
layoutDagreGraph(flow);
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
return {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
|
-
import dagre from 'dagre';
|
|
3
2
|
import {
|
|
4
3
|
createDagreGraph,
|
|
5
4
|
generateIdForNode,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
buildContextMenuForResource,
|
|
11
10
|
DEFAULT_NODE_WIDTH,
|
|
12
11
|
DEFAULT_NODE_HEIGHT,
|
|
12
|
+
layoutDagreGraph,
|
|
13
13
|
} from '@utils/node-graphs/utils/utils';
|
|
14
14
|
|
|
15
15
|
import { findInMap, createVersionedMap, mergeMaps, collectionToResourceMap } from '@utils/collections/util';
|
|
@@ -220,7 +220,7 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
|
|
|
220
220
|
|
|
221
221
|
if (layout) {
|
|
222
222
|
// Render the diagram in memory getting the X and Y
|
|
223
|
-
|
|
223
|
+
layoutDagreGraph(flow);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// Find any duplicated edges, and merge them into one edge
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
|
-
import dagre from 'dagre';
|
|
3
2
|
import {
|
|
4
3
|
generateIdForNode,
|
|
5
4
|
createDagreGraph,
|
|
6
5
|
calculatedNodes,
|
|
7
6
|
createEdge,
|
|
8
7
|
getOperationFields,
|
|
8
|
+
layoutDagreGraph,
|
|
9
9
|
} from '@utils/node-graphs/utils/utils';
|
|
10
10
|
import { findInMap, createVersionedMap } from '@utils/collections/util';
|
|
11
11
|
import type { Node, Edge } from '@xyflow/react';
|
|
@@ -247,7 +247,7 @@ export const getDomainsCanvasData = async (): Promise<DomainCanvasData> => {
|
|
|
247
247
|
});
|
|
248
248
|
|
|
249
249
|
// Calculate layout using dagre
|
|
250
|
-
|
|
250
|
+
layoutDagreGraph(dagreGraph);
|
|
251
251
|
|
|
252
252
|
// Apply calculated positions to nodes
|
|
253
253
|
const layoutedDomainNodes = calculatedNodes(dagreGraph, domainNodes);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
|
-
import dagre from 'dagre';
|
|
3
2
|
import {
|
|
4
3
|
createDagreGraph,
|
|
5
4
|
calculatedNodes,
|
|
@@ -7,6 +6,7 @@ import {
|
|
|
7
6
|
getEdgeLabelForServiceAsTarget,
|
|
8
7
|
generatedIdForEdge,
|
|
9
8
|
createEdge,
|
|
9
|
+
layoutDagreGraph,
|
|
10
10
|
} from '@utils/node-graphs/utils/utils';
|
|
11
11
|
import { getNodesAndEdges as getServicesNodeAndEdges } from './services-node-graph';
|
|
12
12
|
import { getNodesAndEdges as getAgentsNodeAndEdges } from './agents-node-graph';
|
|
@@ -176,7 +176,7 @@ export const getNodesAndEdges = async ({
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
if (layout) {
|
|
179
|
-
|
|
179
|
+
layoutDagreGraph(flow);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
return {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
|
-
import dagre from 'dagre';
|
|
3
2
|
import {
|
|
4
3
|
createDagreGraph,
|
|
5
4
|
calculatedNodes,
|
|
@@ -7,6 +6,7 @@ import {
|
|
|
7
6
|
DEFAULT_NODE_HEIGHT,
|
|
8
7
|
buildContextMenuForResource,
|
|
9
8
|
buildContextMenuForService,
|
|
9
|
+
layoutDagreGraph,
|
|
10
10
|
} from '@utils/node-graphs/utils/utils';
|
|
11
11
|
import { MarkerType } from '@xyflow/react';
|
|
12
12
|
import type { Node as NodeType } from '@xyflow/react';
|
|
@@ -321,7 +321,7 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
|
|
|
321
321
|
graph.setEdge(edge.source, edge.target);
|
|
322
322
|
});
|
|
323
323
|
|
|
324
|
-
|
|
324
|
+
layoutDagreGraph(graph);
|
|
325
325
|
|
|
326
326
|
return {
|
|
327
327
|
nodes: calculatedNodes(graph, nodes),
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// import { getColor } from '@utils/colors';
|
|
2
2
|
import { getEvents } from '@utils/collections/events';
|
|
3
3
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
4
|
-
import dagre from 'dagre';
|
|
5
4
|
import {
|
|
6
5
|
calculatedNodes,
|
|
7
6
|
createDagreGraph,
|
|
@@ -12,6 +11,7 @@ import {
|
|
|
12
11
|
getEdgeLabelForMessageAsSource,
|
|
13
12
|
getEdgeLabelForServiceAsTarget,
|
|
14
13
|
versionMatches,
|
|
14
|
+
layoutDagreGraph,
|
|
15
15
|
} from './utils/utils';
|
|
16
16
|
import { MarkerType, type Node, type Edge } from '@xyflow/react';
|
|
17
17
|
import {
|
|
@@ -691,7 +691,7 @@ const getNodesAndEdges = async ({
|
|
|
691
691
|
});
|
|
692
692
|
|
|
693
693
|
// Render the diagram in memory getting hte X and Y
|
|
694
|
-
|
|
694
|
+
layoutDagreGraph(flow);
|
|
695
695
|
|
|
696
696
|
return {
|
|
697
697
|
nodes: calculatedNodes(flow, nodes),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
|
-
import dagre from 'dagre';
|
|
3
2
|
import {
|
|
4
3
|
createDagreGraph,
|
|
5
4
|
generateIdForNode,
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
DEFAULT_NODE_HEIGHT,
|
|
15
14
|
partitionMessagesByGroup,
|
|
16
15
|
getOperationFields,
|
|
16
|
+
layoutDagreGraph,
|
|
17
17
|
} from '@utils/node-graphs/utils/utils';
|
|
18
18
|
|
|
19
19
|
const sanitizeGroupId = (name: string) => name.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase();
|
|
@@ -636,7 +636,7 @@ export const getNodesAndEdges = async ({
|
|
|
636
636
|
|
|
637
637
|
if (layout) {
|
|
638
638
|
// Render the diagram in memory getting the X and Y
|
|
639
|
-
|
|
639
|
+
layoutDagreGraph(flow);
|
|
640
640
|
}
|
|
641
641
|
|
|
642
642
|
// Find any duplicated edges, and merge them into one edge
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
|
-
import dagre from 'dagre';
|
|
4
3
|
import {
|
|
5
4
|
createDagreGraph,
|
|
6
5
|
calculatedNodes,
|
|
@@ -8,6 +7,7 @@ import {
|
|
|
8
7
|
generateIdForNode,
|
|
9
8
|
buildContextMenuForSystem,
|
|
10
9
|
DEFAULT_NODE_HEIGHT,
|
|
10
|
+
layoutDagreGraph,
|
|
11
11
|
} from '@utils/node-graphs/utils/utils';
|
|
12
12
|
import { MarkerType } from '@xyflow/react';
|
|
13
13
|
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
@@ -302,7 +302,7 @@ const buildContextGraphFromSeeds = ({
|
|
|
302
302
|
edges.forEach((edge) => flow.setEdge(edge.source, edge.target));
|
|
303
303
|
|
|
304
304
|
if (layout) {
|
|
305
|
-
|
|
305
|
+
layoutDagreGraph(flow);
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
return {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
|
-
import
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
createDagreGraph,
|
|
4
|
+
calculatedNodes,
|
|
5
|
+
DEFAULT_NODE_WIDTH,
|
|
6
|
+
DEFAULT_NODE_HEIGHT,
|
|
7
|
+
layoutDagreGraph,
|
|
8
|
+
} from '@utils/node-graphs/utils/utils';
|
|
4
9
|
import { getNodesAndEdges as getServicesNodeAndEdges } from './services-node-graph';
|
|
5
10
|
import { getNodesAndEdges as getContainerNodeAndEdges } from './container-node-graph';
|
|
6
11
|
import merge from 'lodash.merge';
|
|
@@ -121,7 +126,7 @@ export const getNodesAndEdges = async ({
|
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
if (layout) {
|
|
124
|
-
|
|
129
|
+
layoutDagreGraph(flow);
|
|
125
130
|
}
|
|
126
131
|
|
|
127
132
|
let laidOutNodes = calculatedNodes(flow, Array.from(nodes.values()));
|
|
@@ -109,6 +109,34 @@ export const createDagreGraph = ({ ranksep = 180, nodesep = 50, ...rest }: any)
|
|
|
109
109
|
return graph;
|
|
110
110
|
};
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* network-simplex produces the nicest layered layout but is O(V·E) and hangs on
|
|
114
|
+
* large architecture maps. tight-tree keeps the same LR layering with far less
|
|
115
|
+
* work. Callers can still force a ranker via createDagreGraph({ ranker }).
|
|
116
|
+
*/
|
|
117
|
+
export const LARGE_GRAPH_NODE_THRESHOLD = 80;
|
|
118
|
+
export const LARGE_GRAPH_EDGE_THRESHOLD = 200;
|
|
119
|
+
export const LARGE_GRAPH_RANKER = 'tight-tree';
|
|
120
|
+
|
|
121
|
+
export const selectDagreRanker = (nodeCount: number, edgeCount: number, explicitRanker?: string) => {
|
|
122
|
+
if (explicitRanker) return explicitRanker;
|
|
123
|
+
if (nodeCount >= LARGE_GRAPH_NODE_THRESHOLD || edgeCount >= LARGE_GRAPH_EDGE_THRESHOLD) {
|
|
124
|
+
return LARGE_GRAPH_RANKER;
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export const layoutDagreGraph = (flow: dagre.graphlib.Graph) => {
|
|
130
|
+
const label = (flow.graph() || {}) as { ranker?: string };
|
|
131
|
+
const nodeCount = flow.nodeCount();
|
|
132
|
+
const edgeCount = flow.edgeCount();
|
|
133
|
+
const ranker = selectDagreRanker(nodeCount, edgeCount, label.ranker);
|
|
134
|
+
if (ranker && label.ranker !== ranker) {
|
|
135
|
+
flow.setGraph({ ...label, ranker });
|
|
136
|
+
}
|
|
137
|
+
dagre.layout(flow);
|
|
138
|
+
};
|
|
139
|
+
|
|
112
140
|
export const createEdge = (edgeOptions: Edge) => {
|
|
113
141
|
return {
|
|
114
142
|
label: 'subscribed by',
|
|
@@ -430,8 +458,8 @@ export const getNodesAndEdgesFromDagre = ({
|
|
|
430
458
|
flow.setEdge(edge.source, edge.target);
|
|
431
459
|
});
|
|
432
460
|
|
|
433
|
-
// Render the diagram in memory getting
|
|
434
|
-
|
|
461
|
+
// Render the diagram in memory getting the X and Y
|
|
462
|
+
layoutDagreGraph(flow);
|
|
435
463
|
|
|
436
464
|
return {
|
|
437
465
|
nodes: calculatedNodes(flow, nodes),
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE",
|
|
9
9
|
"type": "module",
|
|
10
|
-
"version": "4.10.
|
|
10
|
+
"version": "4.10.9",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
@@ -118,9 +118,9 @@
|
|
|
118
118
|
"update-notifier": "^7.3.1",
|
|
119
119
|
"uuid": "^11.1.1",
|
|
120
120
|
"zod": "^4.3.6",
|
|
121
|
-
"@eventcatalog/
|
|
122
|
-
"@eventcatalog/
|
|
123
|
-
"@eventcatalog/
|
|
121
|
+
"@eventcatalog/linter": "1.1.18",
|
|
122
|
+
"@eventcatalog/visualiser": "^4.1.4",
|
|
123
|
+
"@eventcatalog/sdk": "2.29.0"
|
|
124
124
|
},
|
|
125
125
|
"devDependencies": {
|
|
126
126
|
"@astrojs/check": "^0.9.10",
|