@eventcatalog/core 2.65.1 → 3.0.0-beta.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/README.md +1 -1
- 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-2TTD2MLE.js → chunk-JB4YT5JY.js} +1 -1
- package/dist/{chunk-BTS6L3KY.js → chunk-TQ4HZREX.js} +1 -1
- package/dist/{chunk-XB4SZX3I.js → chunk-X4W4YC3U.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -21
- package/dist/eventcatalog.config.d.cts +9 -0
- package/dist/eventcatalog.config.d.ts +9 -0
- package/dist/eventcatalog.js +3 -20
- package/eventcatalog/src/components/CopyAsMarkdown.tsx +19 -1
- package/eventcatalog/src/components/FavoriteButton.tsx +54 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +386 -362
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +166 -523
- package/eventcatalog/src/components/Header.astro +48 -23
- package/eventcatalog/src/components/Lists/VersionList.astro +2 -2
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +8 -2
- package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +37 -0
- package/eventcatalog/src/components/Search/Search.astro +48 -28
- package/eventcatalog/src/components/Search/SearchModal.tsx +393 -702
- package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +298 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/container.ts +66 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/domain.ts +101 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/flow.ts +29 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/message.ts +84 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/service.ts +147 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/shared.ts +146 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +1073 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/sidebar-builder.ts +365 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +90 -0
- package/eventcatalog/src/components/SideNav/SideNav.astro +18 -28
- package/eventcatalog/src/content.config.ts +2 -0
- package/eventcatalog/src/enterprise/eventcatalog-chat/pages/chat/index.astro +3 -3
- package/eventcatalog/src/layouts/DirectoryLayout.astro +2 -2
- package/eventcatalog/src/layouts/DiscoverLayout.astro +3 -3
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +83 -64
- package/eventcatalog/src/layouts/VisualiserLayout.astro +3 -3
- package/eventcatalog/src/pages/_index.astro +530 -110
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +64 -0
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +29 -0
- package/eventcatalog/src/pages/directory/[type]/_index.data.ts +4 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +3 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -5
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +354 -186
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +1 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +4 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +1 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +3 -27
- package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +2 -2
- package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +2 -2
- package/eventcatalog/src/pages/nav-index.json.ts +30 -0
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +77 -0
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +90 -0
- package/eventcatalog/src/pages/schemas/{index.astro → explorer/index.astro} +3 -3
- package/eventcatalog/src/pages/studio.astro +3 -3
- package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +2 -2
- package/eventcatalog/src/stores/favorites-store.ts +83 -0
- package/eventcatalog/src/stores/sidebar-store.ts +8 -0
- package/eventcatalog/src/utils/collections/changelogs.ts +7 -4
- package/eventcatalog/src/utils/{channels.ts → collections/channels.ts} +81 -31
- package/eventcatalog/src/utils/collections/commands.ts +134 -0
- package/eventcatalog/src/utils/collections/containers.ts +44 -33
- package/eventcatalog/src/utils/collections/domains.ts +204 -62
- package/eventcatalog/src/utils/{entities.ts → collections/entities.ts} +44 -24
- package/eventcatalog/src/utils/collections/events.ts +136 -0
- package/eventcatalog/src/utils/collections/flows.ts +59 -25
- package/eventcatalog/src/utils/{messages.ts → collections/messages.ts} +13 -4
- package/eventcatalog/src/utils/{queries.ts → collections/queries.ts} +49 -28
- package/eventcatalog/src/utils/collections/services.ts +100 -68
- package/eventcatalog/src/utils/collections/teams.ts +94 -0
- package/eventcatalog/src/utils/collections/users.ts +122 -0
- package/eventcatalog/src/utils/collections/util.ts +57 -1
- package/eventcatalog/src/utils/feature.ts +2 -2
- package/eventcatalog/src/utils/{collections/file-diffs.ts → file-diffs.ts} +1 -1
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +2 -0
- package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +16 -6
- package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +14 -10
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +36 -64
- package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +23 -19
- package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +36 -49
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +22 -18
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +4 -4
- package/eventcatalog/tailwind.config.mjs +14 -0
- package/eventcatalog/tsconfig.json +2 -1
- package/package.json +7 -4
- package/eventcatalog/public/logo_old.png +0 -0
- package/eventcatalog/src/components/DiscoverInsight.astro +0 -61
- package/eventcatalog/src/components/Grids/ServiceGrid.tsx +0 -540
- package/eventcatalog/src/components/Lists/CustomSideBarSectionList.astro +0 -55
- package/eventcatalog/src/components/Lists/ProtocolList.tsx +0 -74
- package/eventcatalog/src/components/Lists/RepositoryList.astro +0 -37
- package/eventcatalog/src/components/Lists/SpecificationsList.astro +0 -67
- package/eventcatalog/src/components/SideBars/ChannelSideBar.astro +0 -204
- package/eventcatalog/src/components/SideBars/ContainerSideBar.astro +0 -183
- package/eventcatalog/src/components/SideBars/DomainSideBar.astro +0 -277
- package/eventcatalog/src/components/SideBars/EntitySideBar.astro +0 -139
- package/eventcatalog/src/components/SideBars/FlowSideBar.astro +0 -132
- package/eventcatalog/src/components/SideBars/MessageSideBar.astro +0 -251
- package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +0 -298
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +0 -46
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +0 -78
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/SpecificationList.tsx +0 -83
- package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +0 -1250
- package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +0 -91
- package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +0 -201
- package/eventcatalog/src/components/SideNav/TreeView/getTreeView.ts +0 -190
- package/eventcatalog/src/components/SideNav/TreeView/index.tsx +0 -94
- package/eventcatalog/src/components/TreeView/index.tsx +0 -328
- package/eventcatalog/src/components/TreeView/styles.module.css +0 -264
- package/eventcatalog/src/components/TreeView/useSlots.ts +0 -95
- package/eventcatalog/src/pages/architecture/[type]/index.astro +0 -14
- package/eventcatalog/src/pages/architecture/architecture.astro +0 -110
- package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +0 -14
- package/eventcatalog/src/utils/commands.ts +0 -112
- package/eventcatalog/src/utils/events.ts +0 -108
- package/eventcatalog/src/utils/generators/index.ts +0 -10
- package/eventcatalog/src/utils/teams.ts +0 -72
- package/eventcatalog/src/utils/users.ts +0 -72
|
@@ -1,81 +1,95 @@
|
|
|
1
|
-
import { getItemsFromCollectionByIdAndSemverOrLatest, getVersionForCollectionItem } from '@utils/collections/util';
|
|
2
1
|
import { getCollection } from 'astro:content';
|
|
3
2
|
import type { CollectionEntry } from 'astro:content';
|
|
4
3
|
import path from 'path';
|
|
5
4
|
import semver from 'semver';
|
|
6
|
-
import type { CollectionTypes } from '@types';
|
|
5
|
+
import type { CollectionMessageTypes, CollectionTypes } from '@types';
|
|
7
6
|
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
|
|
8
|
-
import utils from '@eventcatalog/sdk';
|
|
7
|
+
import utils, { type Domain } from '@eventcatalog/sdk';
|
|
8
|
+
import { getDomains, getDomainsForService } from './domains';
|
|
9
|
+
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
9
10
|
|
|
10
11
|
export type Service = CollectionEntry<'services'>;
|
|
11
12
|
|
|
13
|
+
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
12
14
|
interface Props {
|
|
13
15
|
getAllVersions?: boolean;
|
|
16
|
+
returnBody?: boolean;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
//
|
|
17
|
-
let
|
|
18
|
-
allVersions: [],
|
|
19
|
-
currentVersions: [],
|
|
20
|
-
};
|
|
19
|
+
// Simple in-memory cache
|
|
20
|
+
let memoryCache: Record<string, Service[]> = {};
|
|
21
21
|
|
|
22
|
-
export const getServices = async ({ getAllVersions = true }: Props = {}): Promise<Service[]> => {
|
|
23
|
-
|
|
22
|
+
export const getServices = async ({ getAllVersions = true, returnBody = false }: Props = {}): Promise<Service[]> => {
|
|
23
|
+
// console.time('✅ New getServices');
|
|
24
|
+
const cacheKey = `${getAllVersions ? 'allVersions' : 'currentVersions'}-${returnBody ? 'withBody' : 'noBody'}`;
|
|
24
25
|
|
|
25
|
-
// Check if we have cached
|
|
26
|
-
if (
|
|
27
|
-
|
|
26
|
+
// Check if we have cached services
|
|
27
|
+
if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
|
|
28
|
+
// console.timeEnd('✅ New getServices');
|
|
29
|
+
return memoryCache[cacheKey];
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
//
|
|
31
|
-
const
|
|
32
|
-
|
|
32
|
+
// 1. Fetch all collections in parallel
|
|
33
|
+
const [allServices, allEvents, allCommands, allQueries, allEntities, allContainers, allFlows] = await Promise.all([
|
|
34
|
+
getCollection('services'),
|
|
35
|
+
getCollection('events'),
|
|
36
|
+
getCollection('commands'),
|
|
37
|
+
getCollection('queries'),
|
|
38
|
+
getCollection('entities'),
|
|
39
|
+
getCollection('containers'),
|
|
40
|
+
getCollection('flows'),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const allMessages = [...allEvents, ...allCommands, ...allQueries];
|
|
44
|
+
|
|
45
|
+
// 2. Build optimized maps
|
|
46
|
+
const serviceMap = createVersionedMap(allServices);
|
|
47
|
+
const messageMap = createVersionedMap(allMessages);
|
|
48
|
+
const entityMap = createVersionedMap(allEntities);
|
|
49
|
+
const containerMap = createVersionedMap(allContainers);
|
|
50
|
+
const flowMap = createVersionedMap(allFlows);
|
|
51
|
+
|
|
52
|
+
// 3. Filter services
|
|
53
|
+
const targetServices = allServices.filter((service) => {
|
|
54
|
+
if (service.data.hidden === true) return false;
|
|
55
|
+
if (!getAllVersions && service.filePath?.includes('versioned')) return false;
|
|
56
|
+
return true;
|
|
33
57
|
});
|
|
34
58
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
60
|
+
|
|
61
|
+
// 4. Enrich services using Map lookups (O(1))
|
|
62
|
+
const processedServices = await Promise.all(
|
|
63
|
+
targetServices.map(async (service) => {
|
|
64
|
+
// Version info
|
|
65
|
+
const serviceVersions = serviceMap.get(service.data.id) || [];
|
|
66
|
+
const latestVersion = serviceVersions[0]?.data.version || service.data.version;
|
|
67
|
+
const versions = serviceVersions.map((s) => s.data.version);
|
|
68
|
+
|
|
69
|
+
const sends = (service.data.sends || [])
|
|
70
|
+
.map((m) => findInMap(messageMap, m.id, m.version))
|
|
71
|
+
.filter((e): e is CollectionEntry<CollectionMessageTypes> => !!e);
|
|
72
|
+
|
|
73
|
+
const receives = (service.data.receives || [])
|
|
74
|
+
.map((m) => findInMap(messageMap, m.id, m.version))
|
|
75
|
+
.filter((e): e is CollectionEntry<CollectionMessageTypes> => !!e);
|
|
76
|
+
|
|
77
|
+
const mappedEntities = (service.data.entities || [])
|
|
78
|
+
.map((e) => findInMap(entityMap, e.id, e.version))
|
|
79
|
+
.filter((e): e is CollectionEntry<'entities'> => !!e);
|
|
80
|
+
|
|
81
|
+
const mappedWritesTo = (service.data.writesTo || [])
|
|
82
|
+
.map((c) => findInMap(containerMap, c.id, c.version))
|
|
83
|
+
.filter((e): e is CollectionEntry<'containers'> => !!e);
|
|
84
|
+
|
|
85
|
+
const mappedReadsFrom = (service.data.readsFrom || [])
|
|
86
|
+
.map((c) => findInMap(containerMap, c.id, c.version))
|
|
87
|
+
.filter((e): e is CollectionEntry<'containers'> => !!e);
|
|
88
|
+
|
|
89
|
+
const mappedFlows = (service.data.flows || [])
|
|
90
|
+
.map((f) => findInMap(flowMap, f.id, f.version))
|
|
91
|
+
.filter((f): f is CollectionEntry<'flows'> => !!f);
|
|
41
92
|
|
|
42
|
-
// @ts-ignore // TODO: Fix this type
|
|
43
|
-
cachedServices[cacheKey] = await Promise.all(
|
|
44
|
-
services.map(async (service) => {
|
|
45
|
-
const { latestVersion, versions } = getVersionForCollectionItem(service, services);
|
|
46
|
-
|
|
47
|
-
const sendsMessages = service.data.sends || [];
|
|
48
|
-
const receivesMessages = service.data.receives || [];
|
|
49
|
-
const serviceEntities = service.data.entities || [];
|
|
50
|
-
const serviceWritesTo = service.data.writesTo || [];
|
|
51
|
-
const serviceReadsFrom = service.data.readsFrom || [];
|
|
52
|
-
|
|
53
|
-
const sends = sendsMessages
|
|
54
|
-
.map((message: any) => getItemsFromCollectionByIdAndSemverOrLatest(allMessages, message.id, message.version))
|
|
55
|
-
.flat()
|
|
56
|
-
.filter((e: any) => e !== undefined);
|
|
57
|
-
|
|
58
|
-
const receives = receivesMessages
|
|
59
|
-
.map((message: any) => getItemsFromCollectionByIdAndSemverOrLatest(allMessages, message.id, message.version))
|
|
60
|
-
.flat()
|
|
61
|
-
.filter((e: any) => e !== undefined);
|
|
62
|
-
|
|
63
|
-
const mappedEntities = serviceEntities
|
|
64
|
-
.map((entity: any) => getItemsFromCollectionByIdAndSemverOrLatest(entities, entity.id, entity.version))
|
|
65
|
-
.flat()
|
|
66
|
-
.filter((e: any) => e !== undefined);
|
|
67
|
-
|
|
68
|
-
const mappedWritesTo = serviceWritesTo
|
|
69
|
-
.map((container: any) => getItemsFromCollectionByIdAndSemverOrLatest(containers, container.id, container.version))
|
|
70
|
-
.flat()
|
|
71
|
-
.filter((e: any) => e !== undefined);
|
|
72
|
-
|
|
73
|
-
const mappedReadsFrom = serviceReadsFrom
|
|
74
|
-
.map((container: any) => getItemsFromCollectionByIdAndSemverOrLatest(containers, container.id, container.version))
|
|
75
|
-
.flat()
|
|
76
|
-
.filter((e: any) => e !== undefined);
|
|
77
|
-
|
|
78
|
-
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
79
93
|
const folderName = await getResourceFolderName(
|
|
80
94
|
process.env.PROJECT_DIR ?? '',
|
|
81
95
|
service.data.id,
|
|
@@ -87,18 +101,19 @@ export const getServices = async ({ getAllVersions = true }: Props = {}): Promis
|
|
|
87
101
|
...service,
|
|
88
102
|
data: {
|
|
89
103
|
...service.data,
|
|
90
|
-
writesTo: mappedWritesTo,
|
|
91
|
-
readsFrom: mappedReadsFrom,
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
writesTo: mappedWritesTo as any,
|
|
105
|
+
readsFrom: mappedReadsFrom as any,
|
|
106
|
+
flows: mappedFlows as any,
|
|
107
|
+
receives: receives as any,
|
|
108
|
+
sends: sends as any,
|
|
94
109
|
versions,
|
|
95
110
|
latestVersion,
|
|
96
|
-
entities: mappedEntities,
|
|
111
|
+
entities: mappedEntities as any,
|
|
97
112
|
},
|
|
98
113
|
// TODO: verify if it could be deleted.
|
|
99
114
|
nodes: {
|
|
100
|
-
receives,
|
|
101
|
-
sends,
|
|
115
|
+
receives: receives as any,
|
|
116
|
+
sends: sends as any,
|
|
102
117
|
},
|
|
103
118
|
catalog: {
|
|
104
119
|
// TODO: avoid use string replace at path due to win32
|
|
@@ -110,16 +125,20 @@ export const getServices = async ({ getAllVersions = true }: Props = {}): Promis
|
|
|
110
125
|
publicPath: path.join('/generated', service.collection, serviceFolderName),
|
|
111
126
|
type: 'service',
|
|
112
127
|
},
|
|
128
|
+
body: returnBody ? service.body : undefined,
|
|
113
129
|
};
|
|
114
130
|
})
|
|
115
131
|
);
|
|
116
132
|
|
|
117
133
|
// order them by the name of the service
|
|
118
|
-
|
|
134
|
+
processedServices.sort((a, b) => {
|
|
119
135
|
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
120
136
|
});
|
|
121
137
|
|
|
122
|
-
|
|
138
|
+
memoryCache[cacheKey] = processedServices;
|
|
139
|
+
// console.timeEnd('✅ New getServices');
|
|
140
|
+
|
|
141
|
+
return processedServices;
|
|
123
142
|
};
|
|
124
143
|
|
|
125
144
|
export const getProducersOfMessage = (services: Service[], message: CollectionEntry<'events' | 'commands' | 'queries'>) => {
|
|
@@ -209,3 +228,16 @@ export const getProducersAndConsumersForChannel = async (channel: CollectionEntr
|
|
|
209
228
|
consumers: consumers ?? [],
|
|
210
229
|
};
|
|
211
230
|
};
|
|
231
|
+
export const getServicesNotInAnyDomain = async (): Promise<Service[]> => {
|
|
232
|
+
const services = await getServices({ getAllVersions: false });
|
|
233
|
+
|
|
234
|
+
// We need an async-aware filter: run all lookups, then filter by the results
|
|
235
|
+
const domainCountsForServices = await Promise.all(
|
|
236
|
+
services.map(async (service) => {
|
|
237
|
+
const domainsForService = await getDomainsForService(service);
|
|
238
|
+
return domainsForService.length;
|
|
239
|
+
})
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
return services.filter((_, index) => domainCountsForServices[index] === 0);
|
|
243
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { CollectionTypes } from '@types';
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
import type { CollectionEntry } from 'astro:content';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
export type Team = CollectionEntry<'teams'>;
|
|
7
|
+
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
8
|
+
// Cache for build time
|
|
9
|
+
let memoryCache: Team[] = [];
|
|
10
|
+
|
|
11
|
+
export const getTeams = async (): Promise<Team[]> => {
|
|
12
|
+
// console.time('✅ New getTeams');
|
|
13
|
+
if (memoryCache.length > 0 && CACHE_ENABLED) {
|
|
14
|
+
// console.timeEnd('✅ New getTeams');
|
|
15
|
+
return memoryCache;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 1. Fetch all collections in parallel
|
|
19
|
+
const [allTeams, allDomains, allServices, allEvents, allCommands, allQueries] = await Promise.all([
|
|
20
|
+
getCollection('teams'),
|
|
21
|
+
getCollection('domains'),
|
|
22
|
+
getCollection('services'),
|
|
23
|
+
getCollection('events'),
|
|
24
|
+
getCollection('commands'),
|
|
25
|
+
getCollection('queries'),
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
// 2. Filter teams
|
|
29
|
+
const targetTeams = allTeams.filter((team) => team.data.hidden !== true);
|
|
30
|
+
|
|
31
|
+
// 3. Build Owner Index: Map<OwnerID, Item[]>
|
|
32
|
+
// This index groups all items (domains, services, etc.) by their owner IDs.
|
|
33
|
+
// This allows O(1) lookup to find all items owned by a specific team.
|
|
34
|
+
const ownershipMap = new Map<string, CollectionEntry<CollectionTypes>[]>();
|
|
35
|
+
|
|
36
|
+
const addToIndex = (items: CollectionEntry<CollectionTypes>[]) => {
|
|
37
|
+
for (const item of items) {
|
|
38
|
+
if (item.data.owners) {
|
|
39
|
+
for (const owner of item.data.owners) {
|
|
40
|
+
if (!ownershipMap.has(owner.id)) {
|
|
41
|
+
ownershipMap.set(owner.id, []);
|
|
42
|
+
}
|
|
43
|
+
ownershipMap.get(owner.id)!.push(item);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
addToIndex(allDomains);
|
|
50
|
+
addToIndex(allServices);
|
|
51
|
+
addToIndex(allEvents);
|
|
52
|
+
addToIndex(allCommands);
|
|
53
|
+
addToIndex(allQueries);
|
|
54
|
+
|
|
55
|
+
// 4. Enrich teams using the ownership index
|
|
56
|
+
const processedTeams = targetTeams.map((team) => {
|
|
57
|
+
const teamId = team.data.id;
|
|
58
|
+
const ownedItems = ownershipMap.get(teamId) || [];
|
|
59
|
+
|
|
60
|
+
// Categorize items
|
|
61
|
+
const ownedDomains = ownedItems.filter((i) => i.collection === 'domains') as CollectionEntry<'domains'>[];
|
|
62
|
+
const ownedServices = ownedItems.filter((i) => i.collection === 'services') as CollectionEntry<'services'>[];
|
|
63
|
+
const ownedEvents = ownedItems.filter((i) => i.collection === 'events') as CollectionEntry<'events'>[];
|
|
64
|
+
const ownedCommands = ownedItems.filter((i) => i.collection === 'commands') as CollectionEntry<'commands'>[];
|
|
65
|
+
const ownedQueries = ownedItems.filter((i) => i.collection === 'queries') as CollectionEntry<'queries'>[];
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
...team,
|
|
69
|
+
data: {
|
|
70
|
+
...team.data,
|
|
71
|
+
ownedDomains,
|
|
72
|
+
ownedServices,
|
|
73
|
+
ownedCommands,
|
|
74
|
+
ownedQueries,
|
|
75
|
+
ownedEvents,
|
|
76
|
+
},
|
|
77
|
+
catalog: {
|
|
78
|
+
path: path.join(team.collection, team.id.replace('/index.mdx', '')),
|
|
79
|
+
filePath: path.join(process.cwd(), 'src', 'catalog-files', team.collection, team.id.replace('/index.mdx', '')),
|
|
80
|
+
type: 'team',
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// order them by the name of the team
|
|
86
|
+
processedTeams.sort((a, b) => {
|
|
87
|
+
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
memoryCache = processedTeams;
|
|
91
|
+
// console.timeEnd('✅ New getTeams');
|
|
92
|
+
|
|
93
|
+
return processedTeams;
|
|
94
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { CollectionTypes } from '@types';
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
import type { CollectionEntry } from 'astro:content';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
export type User = CollectionEntry<'users'>;
|
|
7
|
+
|
|
8
|
+
// Simple in-memory cache
|
|
9
|
+
let memoryCache: User[] = [];
|
|
10
|
+
|
|
11
|
+
export const getUsers = async (): Promise<User[]> => {
|
|
12
|
+
// console.time('✅ New getUsers');
|
|
13
|
+
|
|
14
|
+
if (memoryCache.length > 0) {
|
|
15
|
+
// console.timeEnd('✅ New getUsers');
|
|
16
|
+
return memoryCache;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 1. Fetch all collections in parallel
|
|
20
|
+
const [allUsers, allDomains, allServices, allEvents, allCommands, allQueries, allTeams] = await Promise.all([
|
|
21
|
+
getCollection('users'),
|
|
22
|
+
getCollection('domains'),
|
|
23
|
+
getCollection('services'),
|
|
24
|
+
getCollection('events'),
|
|
25
|
+
getCollection('commands'),
|
|
26
|
+
getCollection('queries'),
|
|
27
|
+
getCollection('teams'),
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
// 2. Filter users
|
|
31
|
+
const targetUsers = allUsers.filter((user) => user.data.hidden !== true);
|
|
32
|
+
const visibleTeams = allTeams.filter((team) => team.data.hidden !== true);
|
|
33
|
+
|
|
34
|
+
// 3. Process users (Optimization: Iterate once over relationships if possible,
|
|
35
|
+
// but since we need to check ownership for EACH user against ALL items,
|
|
36
|
+
// we can't easily invert the map without building an "owner" index first.
|
|
37
|
+
// Given users/teams count is usually lower than events/services, iterating users and filtering items is acceptable,
|
|
38
|
+
// OR we can index items by ownerID for O(1) lookup. Let's try indexing items by ownerID.)
|
|
39
|
+
|
|
40
|
+
// Build Owner Index: Map<OwnerID, Item[]>
|
|
41
|
+
const ownershipMap = new Map<string, CollectionEntry<CollectionTypes>[]>();
|
|
42
|
+
|
|
43
|
+
const addToIndex = (items: CollectionEntry<CollectionTypes>[]) => {
|
|
44
|
+
for (const item of items) {
|
|
45
|
+
if (item.data.owners) {
|
|
46
|
+
for (const owner of item.data.owners) {
|
|
47
|
+
if (!ownershipMap.has(owner.id)) {
|
|
48
|
+
ownershipMap.set(owner.id, []);
|
|
49
|
+
}
|
|
50
|
+
ownershipMap.get(owner.id)!.push(item);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
addToIndex(allDomains);
|
|
57
|
+
addToIndex(allServices);
|
|
58
|
+
addToIndex(allEvents);
|
|
59
|
+
addToIndex(allCommands);
|
|
60
|
+
addToIndex(allQueries);
|
|
61
|
+
|
|
62
|
+
// Team Membership Index: Map<UserID, Team[]>
|
|
63
|
+
const teamMembershipMap = new Map<string, typeof visibleTeams>();
|
|
64
|
+
for (const team of visibleTeams) {
|
|
65
|
+
if (team.data.members) {
|
|
66
|
+
for (const member of team.data.members) {
|
|
67
|
+
if (!teamMembershipMap.has(member.id)) {
|
|
68
|
+
teamMembershipMap.set(member.id, []);
|
|
69
|
+
}
|
|
70
|
+
teamMembershipMap.get(member.id)!.push(team);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const mappedUsers = targetUsers.map((user) => {
|
|
76
|
+
const userId = user.data.id;
|
|
77
|
+
const associatedTeams = teamMembershipMap.get(userId) || [];
|
|
78
|
+
const associatedTeamIds = associatedTeams.map((t) => t.data.id);
|
|
79
|
+
|
|
80
|
+
// Collect all owned items directly owned by user OR by their teams
|
|
81
|
+
const directOwnedItems = ownershipMap.get(userId) || [];
|
|
82
|
+
const teamOwnedItems = associatedTeamIds.flatMap((teamId) => ownershipMap.get(teamId) || []);
|
|
83
|
+
|
|
84
|
+
// Combine and deduplicate items (by ID+Version or just reference equality since they come from same source arrays)
|
|
85
|
+
const allOwnedItems = Array.from(new Set([...directOwnedItems, ...teamOwnedItems]));
|
|
86
|
+
|
|
87
|
+
// Categorize items
|
|
88
|
+
const ownedDomains = allOwnedItems.filter((i) => i.collection === 'domains') as CollectionEntry<'domains'>[];
|
|
89
|
+
const ownedServices = allOwnedItems.filter((i) => i.collection === 'services') as CollectionEntry<'services'>[];
|
|
90
|
+
const ownedEvents = allOwnedItems.filter((i) => i.collection === 'events') as CollectionEntry<'events'>[];
|
|
91
|
+
const ownedCommands = allOwnedItems.filter((i) => i.collection === 'commands') as CollectionEntry<'commands'>[];
|
|
92
|
+
const ownedQueries = allOwnedItems.filter((i) => i.collection === 'queries') as CollectionEntry<'queries'>[];
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
...user,
|
|
96
|
+
data: {
|
|
97
|
+
...user.data,
|
|
98
|
+
ownedDomains,
|
|
99
|
+
ownedServices,
|
|
100
|
+
ownedEvents,
|
|
101
|
+
ownedCommands,
|
|
102
|
+
ownedQueries,
|
|
103
|
+
associatedTeams,
|
|
104
|
+
},
|
|
105
|
+
catalog: {
|
|
106
|
+
path: path.join(user.collection, user.id.replace('/index.mdx', '')),
|
|
107
|
+
filePath: path.join(process.cwd(), 'src', 'catalog-files', user.collection, user.id.replace('/index.mdx', '')),
|
|
108
|
+
type: 'user',
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// order them by the name of the user
|
|
114
|
+
mappedUsers.sort((a, b) => {
|
|
115
|
+
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
memoryCache = mappedUsers;
|
|
119
|
+
// console.timeEnd('✅ New getUsers');
|
|
120
|
+
|
|
121
|
+
return mappedUsers;
|
|
122
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CollectionTypes } from '@types';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
|
-
import { coerce, compare, eq, satisfies as satisfiesRange } from 'semver';
|
|
3
|
+
import semver, { coerce, compare, eq, satisfies as satisfiesRange } from 'semver';
|
|
4
4
|
|
|
5
5
|
export const getPreviousVersion = (version: string, versions: string[]) => {
|
|
6
6
|
const index = versions.indexOf(version);
|
|
@@ -116,6 +116,7 @@ export const resourceToCollectionMap = {
|
|
|
116
116
|
user: 'users',
|
|
117
117
|
team: 'teams',
|
|
118
118
|
container: 'containers',
|
|
119
|
+
entity: 'entities',
|
|
119
120
|
} as const;
|
|
120
121
|
|
|
121
122
|
export const collectionToResourceMap = {
|
|
@@ -129,6 +130,7 @@ export const collectionToResourceMap = {
|
|
|
129
130
|
users: 'user',
|
|
130
131
|
teams: 'team',
|
|
131
132
|
containers: 'container',
|
|
133
|
+
entities: 'entity',
|
|
132
134
|
} as const;
|
|
133
135
|
|
|
134
136
|
export const getDeprecatedDetails = (item: CollectionEntry<CollectionTypes>) => {
|
|
@@ -165,3 +167,57 @@ export const removeContentFromCollection = (collection: CollectionEntry<Collecti
|
|
|
165
167
|
catalog: undefined,
|
|
166
168
|
}));
|
|
167
169
|
};
|
|
170
|
+
|
|
171
|
+
// --- OPTIMIZATION HELPERS ---
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Groups items by ID and sorts them by version (Newest first).
|
|
175
|
+
* This allows O(1) lookup for "latest" (index 0) and specific versions.
|
|
176
|
+
*/
|
|
177
|
+
export const createVersionedMap = <T extends { data: { id: string; version?: string } }>(items: T[]) => {
|
|
178
|
+
const map = new Map<string, T[]>();
|
|
179
|
+
|
|
180
|
+
for (const item of items) {
|
|
181
|
+
const id = item.data.id;
|
|
182
|
+
if (!map.has(id)) map.set(id, []);
|
|
183
|
+
map.get(id)!.push(item);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Sort every entry so index [0] is always the latest version
|
|
187
|
+
for (const [key, list] of map.entries()) {
|
|
188
|
+
list.sort((a, b) => {
|
|
189
|
+
// specific version sorting logic (fallback to string compare if not valid semver)
|
|
190
|
+
const vA = a.data.version || '0.0.0';
|
|
191
|
+
const vB = b.data.version || '0.0.0';
|
|
192
|
+
return semver.valid(vB) && semver.valid(vA) ? semver.rcompare(vA, vB) : vB.localeCompare(vA);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return map;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Fast lookup helper.
|
|
200
|
+
* If version is provided, find it. If not, return the first (latest) item.
|
|
201
|
+
*/
|
|
202
|
+
export const findInMap = <T extends { data: { version?: string } }>(
|
|
203
|
+
map: Map<string, T[]>,
|
|
204
|
+
id: string,
|
|
205
|
+
version?: string
|
|
206
|
+
): T | undefined => {
|
|
207
|
+
const items = map.get(id);
|
|
208
|
+
if (!items || items.length === 0) return undefined;
|
|
209
|
+
|
|
210
|
+
// If no version specified or 'latest', return the first item (which is sorted to be latest)
|
|
211
|
+
if (!version || version === 'latest') return items[0];
|
|
212
|
+
|
|
213
|
+
// Try exact match
|
|
214
|
+
const exactMatch = items.find((i) => i.data.version === version);
|
|
215
|
+
if (exactMatch) return exactMatch;
|
|
216
|
+
|
|
217
|
+
// Try semver match if not exact
|
|
218
|
+
if (semver.validRange(version)) {
|
|
219
|
+
return items.find((i) => semver.satisfies(i.data.version || '0.0.0', version));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return undefined;
|
|
223
|
+
};
|
|
@@ -34,7 +34,7 @@ export const showCustomBranding = () => {
|
|
|
34
34
|
return isEventCatalogStarterEnabled() || isEventCatalogScaleEnabled();
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
export const isChangelogEnabled = () => config?.changelog?.enabled ??
|
|
37
|
+
export const isChangelogEnabled = () => config?.changelog?.enabled ?? false;
|
|
38
38
|
|
|
39
39
|
export const isCustomDocsEnabled = () => isEventCatalogStarterEnabled() || isEventCatalogScaleEnabled();
|
|
40
40
|
export const isEventCatalogChatEnabled = () => {
|
|
@@ -55,5 +55,5 @@ export const isAuthEnabled = () => {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
export const isSSR = () => config?.output === 'server';
|
|
58
|
-
|
|
58
|
+
export const isRSSEnabled = () => config?.rss?.enabled ?? false;
|
|
59
59
|
export const isVisualiserEnabled = () => config?.visualiser?.enabled ?? true;
|
|
@@ -2,7 +2,7 @@ import { readdir, readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { formatPatch, structuredPatch } from 'diff';
|
|
4
4
|
import { html, parse } from 'diff2html';
|
|
5
|
-
import { getItemsFromCollectionByIdAndSemverOrLatest } from './util';
|
|
5
|
+
import { getItemsFromCollectionByIdAndSemverOrLatest } from './collections/util';
|
|
6
6
|
import type { CollectionEntry } from 'astro:content';
|
|
7
7
|
import type { CollectionTypes } from '@types';
|
|
8
8
|
|
|
@@ -17,12 +17,14 @@ interface Props {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simple', channelRenderMode = 'flat' }: Props) => {
|
|
20
|
+
// 1. Fetch data
|
|
20
21
|
const containers = await getContainers();
|
|
21
22
|
|
|
22
23
|
const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
|
|
23
24
|
const nodes = [] as any,
|
|
24
25
|
edges = [] as any;
|
|
25
26
|
|
|
27
|
+
// Optimized: Use find since we're looking for a specific item
|
|
26
28
|
const container = containers.find((container) => container.data.id === id && container.data.version === version);
|
|
27
29
|
|
|
28
30
|
// Nothing found...
|
|
@@ -2,9 +2,9 @@ import { getCollection, getEntry } from 'astro:content';
|
|
|
2
2
|
import { generateIdForNode } from './utils/utils';
|
|
3
3
|
import ELK from 'elkjs/lib/elk.bundled.js';
|
|
4
4
|
import { MarkerType } from '@xyflow/react';
|
|
5
|
-
import {
|
|
5
|
+
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
6
6
|
import { getVersionFromCollection } from '@utils/collections/versions';
|
|
7
|
-
import { getEntities, type Entity } from '@utils/entities';
|
|
7
|
+
import { getEntities, type Entity } from '@utils/collections/entities';
|
|
8
8
|
import { getDomains, type Domain } from '@utils/collections/domains';
|
|
9
9
|
import { getServices, type Service } from '@utils/collections/services';
|
|
10
10
|
|
|
@@ -21,9 +21,8 @@ export const getNodesAndEdges = async ({ id, version, entities, type = 'domains'
|
|
|
21
21
|
let nodes = [] as any,
|
|
22
22
|
edges = [] as any;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
const allEntities = await getEntities();
|
|
26
|
-
const allServices = await getServices();
|
|
24
|
+
// 1. Fetch all collections in parallel
|
|
25
|
+
const [allDomains, allEntities, allServices] = await Promise.all([getDomains(), getEntities(), getServices()]);
|
|
27
26
|
|
|
28
27
|
let resource = null;
|
|
29
28
|
|
|
@@ -65,14 +64,25 @@ export const getNodesAndEdges = async ({ id, version, entities, type = 'domains'
|
|
|
65
64
|
const externalToDomain = Array.from(new Set<string>(listOfReferencedEntities as string[])) // Remove duplicates
|
|
66
65
|
.filter((entityId: any) => !resourceEntities.some((domainEntity: any) => domainEntity.id === entityId));
|
|
67
66
|
|
|
67
|
+
// 2. Build optimized maps
|
|
68
|
+
// Only build domain map if we have domains to search
|
|
69
|
+
// Only build entity map if we have entities to search
|
|
70
|
+
const entityMap = createVersionedMap(allEntities);
|
|
71
|
+
|
|
68
72
|
// Helper function to find which domain an entity belongs to
|
|
73
|
+
// Optimized to use direct iteration over domains (domains usually contain entity arrays)
|
|
74
|
+
// We can't easily map entity->domain without scanning domains first unless we build a reverse index.
|
|
75
|
+
// Given domains count is usually manageable, scanning is acceptable, OR we could build an index if needed.
|
|
76
|
+
// For now, let's keep the scan but make it efficient.
|
|
69
77
|
const findEntityDomain = (entityId: string) => {
|
|
70
78
|
return allDomains.find((domain) => domain.data.entities?.some((domainEntity: any) => domainEntity.data.id === entityId));
|
|
71
79
|
};
|
|
72
80
|
|
|
73
81
|
const addedExternalEntities = [];
|
|
82
|
+
|
|
74
83
|
for (const entityId of externalToDomain) {
|
|
75
|
-
|
|
84
|
+
// 3. Use map lookup
|
|
85
|
+
const externalEntity = findInMap(entityMap, entityId as string, 'latest') as Entity;
|
|
76
86
|
|
|
77
87
|
if (externalEntity) {
|
|
78
88
|
const nodeId = generateIdForNode(externalEntity);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
2
|
import dagre from 'dagre';
|
|
3
3
|
import { generateIdForNode, createDagreGraph, calculatedNodes, createEdge } from '@utils/node-graphs/utils/utils';
|
|
4
|
-
import {
|
|
4
|
+
import { findInMap, createVersionedMap } from '@utils/collections/util';
|
|
5
5
|
import type { Node, Edge } from '@xyflow/react';
|
|
6
6
|
import { getDomains } from '@utils/collections/domains';
|
|
7
|
+
import type { CollectionMessageTypes } from '@types';
|
|
7
8
|
|
|
8
9
|
interface DomainCanvasData {
|
|
9
10
|
domainNodes: Node[];
|
|
@@ -69,10 +70,14 @@ export const getDomainsCanvasData = async (): Promise<DomainCanvasData> => {
|
|
|
69
70
|
} as Node);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
// Get all messages for version resolution
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
// Get all messages for version resolution in parallel
|
|
74
|
+
const [events, commands, queries] = await Promise.all([
|
|
75
|
+
getCollection('events'),
|
|
76
|
+
getCollection('commands'),
|
|
77
|
+
getCollection('queries'),
|
|
78
|
+
]);
|
|
79
|
+
const allMessages = [...events, ...commands, ...queries];
|
|
80
|
+
const messageMap = createVersionedMap(allMessages);
|
|
76
81
|
|
|
77
82
|
// Map to track unique messages and their publishers/consumers across domains
|
|
78
83
|
const messageRelationships = new Map<
|
|
@@ -89,9 +94,9 @@ export const getDomainsCanvasData = async (): Promise<DomainCanvasData> => {
|
|
|
89
94
|
domainData.services.forEach((service: any) => {
|
|
90
95
|
// Track messages this service sends
|
|
91
96
|
const sendsRaw = service.data.sends ?? [];
|
|
97
|
+
|
|
92
98
|
const sendsHydrated = sendsRaw
|
|
93
|
-
.map((message: any) =>
|
|
94
|
-
.flat()
|
|
99
|
+
.map((message: any) => findInMap(messageMap, message.id, message.version))
|
|
95
100
|
.filter((e: any) => e !== undefined);
|
|
96
101
|
|
|
97
102
|
sendsHydrated.forEach((sentMessage: any) => {
|
|
@@ -115,8 +120,7 @@ export const getDomainsCanvasData = async (): Promise<DomainCanvasData> => {
|
|
|
115
120
|
// Track messages this service receives
|
|
116
121
|
const receivesRaw = service.data.receives ?? [];
|
|
117
122
|
const receivesHydrated = receivesRaw
|
|
118
|
-
.map((message: any) =>
|
|
119
|
-
.flat()
|
|
123
|
+
.map((message: any) => findInMap(messageMap, message.id, message.version))
|
|
120
124
|
.filter((e: any) => e !== undefined);
|
|
121
125
|
|
|
122
126
|
receivesHydrated.forEach((receivedMessage: any) => {
|
|
@@ -154,7 +158,7 @@ export const getDomainsCanvasData = async (): Promise<DomainCanvasData> => {
|
|
|
154
158
|
|
|
155
159
|
if (crossesDomainBoundary) {
|
|
156
160
|
// Find the actual message object
|
|
157
|
-
const messageObject =
|
|
161
|
+
const messageObject = findInMap(messageMap, message.id, message.version) as CollectionEntry<CollectionMessageTypes>;
|
|
158
162
|
|
|
159
163
|
if (messageObject) {
|
|
160
164
|
const messageNodeId = `message-${messageKey}`;
|