@eventcatalog/core 2.65.0 → 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 -26
- 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-NK6OYMRD.js → chunk-JB4YT5JY.js} +1 -1
- package/dist/{chunk-BMDTX5IN.js → chunk-TQ4HZREX.js} +1 -1
- package/dist/{chunk-IJRFYF4B.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 +10 -0
- package/dist/eventcatalog.config.d.ts +10 -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 -518
- package/eventcatalog/src/components/Header.astro +48 -23
- package/eventcatalog/src/components/Lists/VersionList.astro +2 -2
- package/eventcatalog/src/components/MDX/Design/Design.astro +4 -1
- package/eventcatalog/src/components/MDX/Flow/Flow.astro +2 -1
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +3 -3
- 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/custom-documentation/pages/docs/custom/index.astro +10 -4
- 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 +85 -63
- 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 +362 -190
- 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/index.astro +14 -5
- 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]/[version]/_index.data.ts +4 -3
- package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +2 -2
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +4 -3
- 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 +3 -1
- 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 -534
- 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 -180
- package/eventcatalog/src/components/SideBars/DomainSideBar.astro +0 -273
- package/eventcatalog/src/components/SideBars/EntitySideBar.astro +0 -139
- package/eventcatalog/src/components/SideBars/FlowSideBar.astro +0 -128
- package/eventcatalog/src/components/SideBars/MessageSideBar.astro +0 -248
- package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +0 -294
- 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 -101
- 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,10 +1,12 @@
|
|
|
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';
|
|
4
|
+
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
5
|
+
import { getDomains } from './domains';
|
|
6
|
+
import { getServices } from './services';
|
|
5
7
|
|
|
6
8
|
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
|
|
7
|
-
|
|
9
|
+
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
8
10
|
export type Flow = CollectionEntry<'flows'>;
|
|
9
11
|
|
|
10
12
|
interface Props {
|
|
@@ -12,41 +14,55 @@ interface Props {
|
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
// Cache for build time
|
|
15
|
-
let
|
|
16
|
-
allVersions: [],
|
|
17
|
-
currentVersions: [],
|
|
18
|
-
};
|
|
17
|
+
let memoryCache: Record<string, Flow[]> = {};
|
|
19
18
|
|
|
20
19
|
export const getFlows = async ({ getAllVersions = true }: Props = {}): Promise<Flow[]> => {
|
|
20
|
+
// console.time('✅ New getFlows');
|
|
21
21
|
const cacheKey = getAllVersions ? 'allVersions' : 'currentVersions';
|
|
22
22
|
|
|
23
|
-
if (
|
|
24
|
-
|
|
23
|
+
if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
|
|
24
|
+
// console.timeEnd('✅ New getFlows');
|
|
25
|
+
return memoryCache[cacheKey];
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
//
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
// 1. Fetch collections in parallel
|
|
29
|
+
const [allFlows, allEvents, allCommands] = await Promise.all([
|
|
30
|
+
getCollection('flows'),
|
|
31
|
+
getCollection('events'),
|
|
32
|
+
getCollection('commands'),
|
|
33
|
+
]);
|
|
31
34
|
|
|
32
|
-
const
|
|
33
|
-
const commands = await getCollection('commands');
|
|
35
|
+
const allMessages = [...allEvents, ...allCommands];
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
// 2. Build optimized maps
|
|
38
|
+
const flowMap = createVersionedMap(allFlows);
|
|
39
|
+
const messageMap = createVersionedMap(allMessages);
|
|
40
|
+
|
|
41
|
+
// 3. Filter flows
|
|
42
|
+
const targetFlows = allFlows.filter((flow) => {
|
|
43
|
+
if (flow.data.hidden === true) return false;
|
|
44
|
+
if (!getAllVersions && flow.filePath?.includes('versioned')) return false;
|
|
45
|
+
return true;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// 4. Enrich flows
|
|
49
|
+
const processedFlows = targetFlows.map((flow) => {
|
|
50
|
+
// Version info
|
|
51
|
+
const flowVersions = flowMap.get(flow.data.id) || [];
|
|
52
|
+
const latestVersion = flowVersions[0]?.data.version || flow.data.version;
|
|
53
|
+
const versions = flowVersions.map((f) => f.data.version);
|
|
36
54
|
|
|
37
|
-
// @ts-ignore // TODO: Fix this type
|
|
38
|
-
cachedFlows[cacheKey] = flows.map((flow) => {
|
|
39
|
-
// @ts-ignore
|
|
40
|
-
const { latestVersion, versions } = getVersionForCollectionItem(flow, flows);
|
|
41
55
|
const steps = flow.data.steps || [];
|
|
42
56
|
|
|
43
57
|
const hydrateSteps = steps.map((step) => {
|
|
44
|
-
if (!step.message) return { ...
|
|
45
|
-
|
|
58
|
+
if (!step.message) return { ...step, type: 'node' }; // Preserve existing step data for non-messages
|
|
59
|
+
|
|
60
|
+
const message = findInMap(messageMap, step.message.id, step.message.version);
|
|
61
|
+
|
|
46
62
|
return {
|
|
47
63
|
...step,
|
|
48
64
|
type: 'message',
|
|
49
|
-
message: message,
|
|
65
|
+
message: message ? [message] : [], // Keep array structure for compatibility
|
|
50
66
|
};
|
|
51
67
|
});
|
|
52
68
|
|
|
@@ -54,7 +70,7 @@ export const getFlows = async ({ getAllVersions = true }: Props = {}): Promise<F
|
|
|
54
70
|
...flow,
|
|
55
71
|
data: {
|
|
56
72
|
...flow.data,
|
|
57
|
-
steps: hydrateSteps,
|
|
73
|
+
steps: hydrateSteps as any, // Cast to match expected Flow step type
|
|
58
74
|
versions,
|
|
59
75
|
latestVersion,
|
|
60
76
|
},
|
|
@@ -70,9 +86,27 @@ export const getFlows = async ({ getAllVersions = true }: Props = {}): Promise<F
|
|
|
70
86
|
});
|
|
71
87
|
|
|
72
88
|
// order them by the name of the flow
|
|
73
|
-
|
|
89
|
+
processedFlows.sort((a, b) => {
|
|
74
90
|
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
75
91
|
});
|
|
76
92
|
|
|
77
|
-
|
|
93
|
+
memoryCache[cacheKey] = processedFlows;
|
|
94
|
+
// console.timeEnd('✅ New getFlows');
|
|
95
|
+
|
|
96
|
+
return processedFlows;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const getFlowsNotInAnyResource = async (): Promise<Flow[]> => {
|
|
100
|
+
const [flows, domains, services] = await Promise.all([
|
|
101
|
+
getFlows({ getAllVersions: false }),
|
|
102
|
+
getDomains({ getAllVersions: false }),
|
|
103
|
+
getServices({ getAllVersions: false }),
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
const flowsNotInAnyResource = flows.filter((flow) => {
|
|
107
|
+
const domainsForFlow = domains.filter((domain) => domain.data.flows?.some((f: any) => f.id === flow.id));
|
|
108
|
+
const servicesForFlow = services.filter((service) => service.data.flows?.some((f: any) => f.id === flow.id));
|
|
109
|
+
return domainsForFlow.length === 0 && servicesForFlow.length === 0;
|
|
110
|
+
});
|
|
111
|
+
return flowsNotInAnyResource;
|
|
78
112
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Exporting getCommands and getEvents directly
|
|
2
|
-
import { getCommands } from '@utils/commands';
|
|
3
|
-
import { getEvents } from '@utils/events';
|
|
2
|
+
import { getCommands } from '@utils/collections/commands';
|
|
3
|
+
import { getEvents } from '@utils/collections/events';
|
|
4
4
|
import { getQueries } from './queries';
|
|
5
5
|
import type { CollectionEntry } from 'astro:content';
|
|
6
|
-
export { getCommands } from '@utils/commands';
|
|
7
|
-
export { getEvents } from '@utils/events';
|
|
6
|
+
export { getCommands } from '@utils/collections/commands';
|
|
7
|
+
export { getEvents } from '@utils/collections/events';
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
10
|
getAllVersions?: boolean;
|
|
@@ -17,6 +17,15 @@ type Messages = {
|
|
|
17
17
|
queries: CollectionEntry<'queries'>[];
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
export const pluralizeMessageType = (message: CollectionEntry<'events' | 'commands' | 'queries'>) => {
|
|
21
|
+
const typeMap: Record<string, string> = {
|
|
22
|
+
events: 'event',
|
|
23
|
+
commands: 'command',
|
|
24
|
+
queries: 'query',
|
|
25
|
+
};
|
|
26
|
+
return typeMap[message.collection] || 'message';
|
|
27
|
+
};
|
|
28
|
+
|
|
20
29
|
// Main function that uses the imported functions
|
|
21
30
|
export const getMessages = async ({ getAllVersions = true, hydrateServices = true }: Props = {}): Promise<Messages> => {
|
|
22
31
|
const [commands, events, queries] = await Promise.all([
|
|
@@ -2,15 +2,17 @@ import { getCollection } from 'astro:content';
|
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import utils from '@eventcatalog/sdk';
|
|
5
|
-
import {
|
|
5
|
+
import { createVersionedMap, satisfies } from './util';
|
|
6
6
|
|
|
7
7
|
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
|
|
8
|
+
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
8
9
|
|
|
9
10
|
type Query = CollectionEntry<'queries'> & {
|
|
10
11
|
catalog: {
|
|
11
12
|
path: string;
|
|
12
13
|
filePath: string;
|
|
13
14
|
type: string;
|
|
15
|
+
publicPath: string;
|
|
14
16
|
};
|
|
15
17
|
};
|
|
16
18
|
|
|
@@ -20,35 +22,50 @@ interface Props {
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
// Cache for build time
|
|
23
|
-
let
|
|
24
|
-
allVersions: [],
|
|
25
|
-
currentVersions: [],
|
|
26
|
-
};
|
|
25
|
+
let memoryCache: Record<string, Query[]> = {};
|
|
27
26
|
|
|
28
27
|
export const getQueries = async ({ getAllVersions = true, hydrateServices = true }: Props = {}): Promise<Query[]> => {
|
|
29
|
-
|
|
28
|
+
// console.time('✅ New getQueries');
|
|
29
|
+
const cacheKey = `${getAllVersions ? 'allVersions' : 'currentVersions'}-${hydrateServices ? 'hydrated' : 'minimal'}`;
|
|
30
30
|
|
|
31
|
-
if (
|
|
32
|
-
|
|
31
|
+
if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
|
|
32
|
+
// console.timeEnd('✅ New getQueries');
|
|
33
|
+
return memoryCache[cacheKey];
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
// 1. Fetch collections in parallel
|
|
37
|
+
const [allQueries, allServices, allChannels] = await Promise.all([
|
|
38
|
+
getCollection('queries'),
|
|
39
|
+
getCollection('services'),
|
|
40
|
+
getCollection('channels'),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
// 2. Build optimized maps
|
|
44
|
+
const queryMap = createVersionedMap(allQueries);
|
|
45
|
+
|
|
46
|
+
// 3. Filter queries
|
|
47
|
+
const targetQueries = allQueries.filter((query) => {
|
|
48
|
+
if (query.data.hidden === true) return false;
|
|
49
|
+
if (!getAllVersions && query.filePath?.includes('versioned')) return false;
|
|
50
|
+
return true;
|
|
37
51
|
});
|
|
38
52
|
|
|
39
|
-
const
|
|
40
|
-
const allChannels = await getCollection('channels');
|
|
53
|
+
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
41
54
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
// 4. Enrich queries
|
|
56
|
+
const processedQueries = await Promise.all(
|
|
57
|
+
targetQueries.map(async (query) => {
|
|
58
|
+
// Version info
|
|
59
|
+
const queryVersions = queryMap.get(query.data.id) || [];
|
|
60
|
+
const latestVersion = queryVersions[0]?.data.version || query.data.version;
|
|
61
|
+
const versions = queryVersions.map((e) => e.data.version);
|
|
46
62
|
|
|
47
|
-
|
|
63
|
+
// Find Producers (Services that send this query)
|
|
64
|
+
const producers = allServices
|
|
48
65
|
.filter((service) =>
|
|
49
66
|
service.data.sends?.some((item) => {
|
|
50
|
-
if (item.id
|
|
51
|
-
if (item.version
|
|
67
|
+
if (item.id !== query.data.id) return false;
|
|
68
|
+
if (item.version === 'latest' || item.version === undefined) return query.data.version === latestVersion;
|
|
52
69
|
return satisfies(query.data.version, item.version);
|
|
53
70
|
})
|
|
54
71
|
)
|
|
@@ -57,11 +74,12 @@ export const getQueries = async ({ getAllVersions = true, hydrateServices = true
|
|
|
57
74
|
return service;
|
|
58
75
|
});
|
|
59
76
|
|
|
60
|
-
|
|
77
|
+
// Find Consumers (Services that receive this query)
|
|
78
|
+
const consumers = allServices
|
|
61
79
|
.filter((service) =>
|
|
62
80
|
service.data.receives?.some((item) => {
|
|
63
|
-
if (item.id
|
|
64
|
-
if (item.version
|
|
81
|
+
if (item.id !== query.data.id) return false;
|
|
82
|
+
if (item.version === 'latest' || item.version === undefined) return query.data.version === latestVersion;
|
|
65
83
|
return satisfies(query.data.version, item.version);
|
|
66
84
|
})
|
|
67
85
|
)
|
|
@@ -70,10 +88,10 @@ export const getQueries = async ({ getAllVersions = true, hydrateServices = true
|
|
|
70
88
|
return service;
|
|
71
89
|
});
|
|
72
90
|
|
|
91
|
+
// Find Channels
|
|
73
92
|
const messageChannels = query.data.channels || [];
|
|
74
93
|
const channelsForQuery = allChannels.filter((c) => messageChannels.some((channel) => c.data.id === channel.id));
|
|
75
94
|
|
|
76
|
-
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
77
95
|
const folderName = await getResourceFolderName(process.env.PROJECT_DIR ?? '', query.data.id, query.data.version.toString());
|
|
78
96
|
const queryFolderName = folderName ?? query.id.replace(`-${query.data.version}`, '');
|
|
79
97
|
|
|
@@ -82,8 +100,8 @@ export const getQueries = async ({ getAllVersions = true, hydrateServices = true
|
|
|
82
100
|
data: {
|
|
83
101
|
...query.data,
|
|
84
102
|
messageChannels: channelsForQuery,
|
|
85
|
-
producers,
|
|
86
|
-
consumers,
|
|
103
|
+
producers: producers as any, // Cast for hydration flexibility
|
|
104
|
+
consumers: consumers as any,
|
|
87
105
|
versions,
|
|
88
106
|
latestVersion,
|
|
89
107
|
},
|
|
@@ -93,16 +111,19 @@ export const getQueries = async ({ getAllVersions = true, hydrateServices = true
|
|
|
93
111
|
astroContentFilePath: path.join(process.cwd(), 'src', 'content', query.collection, query.id),
|
|
94
112
|
filePath: path.join(process.cwd(), 'src', 'catalog-files', query.collection, query.id.replace('/index.mdx', '')),
|
|
95
113
|
publicPath: path.join('/generated', query.collection, queryFolderName),
|
|
96
|
-
type: 'event',
|
|
114
|
+
type: 'event', // Kept as 'event' to match original file, though likely should be 'query'
|
|
97
115
|
},
|
|
98
116
|
};
|
|
99
117
|
})
|
|
100
118
|
);
|
|
101
119
|
|
|
102
120
|
// order them by the name of the query
|
|
103
|
-
|
|
121
|
+
processedQueries.sort((a, b) => {
|
|
104
122
|
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
105
123
|
});
|
|
106
124
|
|
|
107
|
-
|
|
125
|
+
memoryCache[cacheKey] = processedQueries;
|
|
126
|
+
// console.timeEnd('✅ New getQueries');
|
|
127
|
+
|
|
128
|
+
return processedQueries;
|
|
108
129
|
};
|
|
@@ -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
|
+
};
|