@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,79 +1,202 @@
|
|
|
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 type { CollectionMessageTypes } from '@types';
|
|
6
5
|
import type { Service } from './services';
|
|
7
6
|
import utils from '@eventcatalog/sdk';
|
|
7
|
+
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
8
8
|
|
|
9
9
|
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
|
|
10
|
+
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
10
11
|
|
|
11
12
|
export type Domain = CollectionEntry<'domains'>;
|
|
12
13
|
export type UbiquitousLanguage = CollectionEntry<'ubiquitousLanguages'>;
|
|
14
|
+
|
|
13
15
|
interface Props {
|
|
14
16
|
getAllVersions?: boolean;
|
|
17
|
+
includeServicesInSubdomains?: boolean;
|
|
18
|
+
enrichServices?: boolean;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
//
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
// Simple in-memory cache variable
|
|
22
|
+
let memoryCache: Record<string, Domain[]> = {};
|
|
23
|
+
|
|
24
|
+
// Helper to hydrate services
|
|
25
|
+
const hydrateServices = (
|
|
26
|
+
servicesList: any[],
|
|
27
|
+
serviceMap: Map<string, any[]>,
|
|
28
|
+
messageMap: Map<string, any[]>,
|
|
29
|
+
containerMap: Map<string, any[]>
|
|
30
|
+
) => {
|
|
31
|
+
return servicesList
|
|
32
|
+
.map((service: { id: string; version: string | undefined }) => findInMap(serviceMap, service.id, service.version))
|
|
33
|
+
.filter((s) => !!s)
|
|
34
|
+
.map((service) => {
|
|
35
|
+
// Hydrate service messages and containers
|
|
36
|
+
const sends = (service.data.sends || [])
|
|
37
|
+
.map((msg: any) => findInMap(messageMap, msg.id, msg.version))
|
|
38
|
+
.filter((m: any) => !!m);
|
|
39
|
+
|
|
40
|
+
const receives = (service.data.receives || [])
|
|
41
|
+
.map((msg: any) => findInMap(messageMap, msg.id, msg.version))
|
|
42
|
+
.filter((m: any) => !!m);
|
|
43
|
+
|
|
44
|
+
const readsFrom = (service.data.readsFrom || [])
|
|
45
|
+
.map((c: any) => findInMap(containerMap, c.id, c.version))
|
|
46
|
+
.filter((c: any) => !!c);
|
|
47
|
+
|
|
48
|
+
const writesTo = (service.data.writesTo || [])
|
|
49
|
+
.map((c: any) => findInMap(containerMap, c.id, c.version))
|
|
50
|
+
.filter((c: any) => !!c);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
...service,
|
|
54
|
+
data: {
|
|
55
|
+
...service.data,
|
|
56
|
+
sends: sends as any,
|
|
57
|
+
receives: receives as any,
|
|
58
|
+
readsFrom: readsFrom as any,
|
|
59
|
+
writesTo: writesTo as any,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
});
|
|
21
63
|
};
|
|
22
64
|
|
|
23
|
-
|
|
24
|
-
|
|
65
|
+
// --- MAIN FUNCTION ---
|
|
66
|
+
|
|
67
|
+
export const getDomains = async ({
|
|
68
|
+
getAllVersions = true,
|
|
69
|
+
includeServicesInSubdomains = true,
|
|
70
|
+
enrichServices = false,
|
|
71
|
+
}: Props = {}): Promise<Domain[]> => {
|
|
72
|
+
// console.time('✅ New getDomains');
|
|
25
73
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
74
|
+
const cacheKey = `${getAllVersions ? 'allVersions' : 'currentVersions'}-${includeServicesInSubdomains ? 'true' : 'false'}-${enrichServices ? 'enriched' : 'simple'}`;
|
|
75
|
+
|
|
76
|
+
// Check cache
|
|
77
|
+
if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
|
|
78
|
+
// console.timeEnd('✅ New getDomains');
|
|
79
|
+
return memoryCache[cacheKey];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 1. Fetch collections
|
|
83
|
+
const collectionsToFetch: any[] = [
|
|
84
|
+
getCollection('domains'),
|
|
85
|
+
getCollection('services'),
|
|
86
|
+
getCollection('entities'),
|
|
87
|
+
getCollection('flows'),
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
if (enrichServices) {
|
|
91
|
+
collectionsToFetch.push(
|
|
92
|
+
getCollection('events'),
|
|
93
|
+
getCollection('commands'),
|
|
94
|
+
getCollection('queries'),
|
|
95
|
+
getCollection('containers')
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const results = await Promise.all(collectionsToFetch);
|
|
100
|
+
const [allDomains, allServices, allEntities, allFlows] = results;
|
|
101
|
+
|
|
102
|
+
let messageMap = new Map();
|
|
103
|
+
let containerMap = new Map();
|
|
104
|
+
|
|
105
|
+
if (enrichServices) {
|
|
106
|
+
const [, , , , allEvents, allCommands, allQueries, allContainers] = results;
|
|
107
|
+
const allMessages = [...allEvents, ...allCommands, ...allQueries];
|
|
108
|
+
messageMap = createVersionedMap(allMessages);
|
|
109
|
+
containerMap = createVersionedMap(allContainers);
|
|
29
110
|
}
|
|
30
111
|
|
|
31
|
-
//
|
|
32
|
-
const
|
|
33
|
-
|
|
112
|
+
// 2. Build optimized maps
|
|
113
|
+
const domainMap = createVersionedMap(allDomains);
|
|
114
|
+
const serviceMap = createVersionedMap(allServices);
|
|
115
|
+
const entityMap = createVersionedMap(allEntities);
|
|
116
|
+
const flowMap = createVersionedMap(allFlows);
|
|
117
|
+
|
|
118
|
+
// 3. Filter the domains we actually want to process/return
|
|
119
|
+
const targetDomains = allDomains.filter((domain: Domain) => {
|
|
120
|
+
// Filter out hidden
|
|
121
|
+
if (domain.data.hidden === true) return false;
|
|
122
|
+
// Handle version filtering
|
|
123
|
+
if (!getAllVersions && domain.filePath?.includes('versioned')) return false;
|
|
124
|
+
return true;
|
|
34
125
|
});
|
|
35
126
|
|
|
36
|
-
|
|
37
|
-
const servicesCollection = await getCollection('services');
|
|
38
|
-
const entitiesCollection = await getCollection('entities');
|
|
127
|
+
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
39
128
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
129
|
+
// 4. Process domains using Map lookups (O(1))
|
|
130
|
+
const processedDomains = await Promise.all(
|
|
131
|
+
targetDomains.map(async (domain: Domain) => {
|
|
132
|
+
// Get version info from the map
|
|
133
|
+
const domainVersions = domainMap.get(domain.data.id) || [];
|
|
134
|
+
const latestVersion = domainVersions[0]?.data.version || domain.data.version;
|
|
135
|
+
const versions = domainVersions.map((d) => d.data.version);
|
|
44
136
|
|
|
45
|
-
//
|
|
46
|
-
const servicesInDomain = domain.data.services || [];
|
|
137
|
+
// Resolve Subdomains
|
|
47
138
|
const subDomainsInDomain = domain.data.domains || [];
|
|
48
|
-
const entitiesInDomain = domain.data.entities || [];
|
|
49
139
|
const subDomains = subDomainsInDomain
|
|
50
|
-
.map((
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
140
|
+
.map((sd: { id: string; version: string | undefined }) => findInMap(domainMap, sd.id, sd.version))
|
|
141
|
+
.filter((sd): sd is Domain => !!sd && sd.data.id !== domain.data.id) // Filter nulls and self-refs
|
|
142
|
+
.map((subDomain: any) => {
|
|
143
|
+
// Hydrate services for the subdomain
|
|
144
|
+
let hydratedServices = subDomain.data.services || [];
|
|
145
|
+
if (enrichServices) {
|
|
146
|
+
hydratedServices = hydrateServices(subDomain.data.services || [], serviceMap, messageMap, containerMap);
|
|
147
|
+
} else {
|
|
148
|
+
// Just resolve the service objects without enrichment
|
|
149
|
+
hydratedServices = (subDomain.data.services || [])
|
|
150
|
+
.map((service: { id: string; version: string | undefined }) => findInMap(serviceMap, service.id, service.version))
|
|
151
|
+
.filter((s: any) => !!s);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
...subDomain,
|
|
156
|
+
data: {
|
|
157
|
+
...subDomain.data,
|
|
158
|
+
services: hydratedServices as any,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Resolve Entities
|
|
164
|
+
const entitiesInDomain = domain.data.entities || [];
|
|
165
|
+
const entities = entitiesInDomain
|
|
166
|
+
.map((entity: { id: string; version: string | undefined }) => findInMap(entityMap, entity.id, entity.version))
|
|
167
|
+
.filter((e): e is CollectionEntry<'entities'> => !!e);
|
|
168
|
+
|
|
169
|
+
// Resolve Flows
|
|
170
|
+
const flowsInDomain = domain.data.flows || [];
|
|
171
|
+
const flows = flowsInDomain
|
|
172
|
+
.map((flow: { id: string; version: string | undefined }) => findInMap(flowMap, flow.id, flow.version))
|
|
173
|
+
.filter((f): f is CollectionEntry<'flows'> => !!f);
|
|
174
|
+
|
|
175
|
+
// Resolve Services for Main Domain
|
|
176
|
+
const servicesInDomain = domain.data.services || [];
|
|
177
|
+
|
|
178
|
+
// Hydrate main domain services
|
|
179
|
+
let hydratedMainServices = [];
|
|
180
|
+
if (enrichServices) {
|
|
181
|
+
hydratedMainServices = hydrateServices(servicesInDomain, serviceMap, messageMap, containerMap);
|
|
182
|
+
} else {
|
|
183
|
+
hydratedMainServices = servicesInDomain
|
|
184
|
+
.map((service: { id: string; version: string | undefined }) => findInMap(serviceMap, service.id, service.version))
|
|
185
|
+
.filter((s) => !!s);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Get already-hydrated subdomain services
|
|
189
|
+
const hydratedSubdomainServices = subDomains.flatMap((subDomain: any) => subDomain.data.services || []);
|
|
190
|
+
|
|
191
|
+
const services = includeServicesInSubdomains
|
|
192
|
+
? [...(hydratedMainServices as any), ...(hydratedSubdomainServices as any)]
|
|
193
|
+
: (hydratedMainServices as any);
|
|
194
|
+
|
|
195
|
+
// Calculate folder paths
|
|
73
196
|
const folderName = await getResourceFolderName(
|
|
74
197
|
process.env.PROJECT_DIR ?? '',
|
|
75
198
|
domain.data.id,
|
|
76
|
-
domain.data.version
|
|
199
|
+
domain.data.version?.toString()
|
|
77
200
|
);
|
|
78
201
|
const domainFolderName = folderName ?? domain.id.replace(`-${domain.data.version}`, '');
|
|
79
202
|
|
|
@@ -81,9 +204,10 @@ export const getDomains = async ({ getAllVersions = true }: Props = {}): Promise
|
|
|
81
204
|
...domain,
|
|
82
205
|
data: {
|
|
83
206
|
...domain.data,
|
|
84
|
-
services: services,
|
|
85
|
-
domains: subDomains,
|
|
86
|
-
entities: entities,
|
|
207
|
+
services: services as any, // Cast to avoid deep type issues with enriched data
|
|
208
|
+
domains: subDomains as any,
|
|
209
|
+
entities: entities as any,
|
|
210
|
+
flows: flows as any,
|
|
87
211
|
latestVersion,
|
|
88
212
|
versions,
|
|
89
213
|
},
|
|
@@ -99,12 +223,17 @@ export const getDomains = async ({ getAllVersions = true }: Props = {}): Promise
|
|
|
99
223
|
})
|
|
100
224
|
);
|
|
101
225
|
|
|
102
|
-
//
|
|
103
|
-
|
|
226
|
+
// Sort by name
|
|
227
|
+
processedDomains.sort((a, b) => {
|
|
104
228
|
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
105
229
|
});
|
|
106
230
|
|
|
107
|
-
|
|
231
|
+
// Cache result
|
|
232
|
+
memoryCache[cacheKey] = processedDomains;
|
|
233
|
+
|
|
234
|
+
// console.timeEnd('✅ New getDomains');
|
|
235
|
+
|
|
236
|
+
return processedDomains;
|
|
108
237
|
};
|
|
109
238
|
|
|
110
239
|
export const getMessagesForDomain = async (
|
|
@@ -113,23 +242,29 @@ export const getMessagesForDomain = async (
|
|
|
113
242
|
// We already have the services from the domain
|
|
114
243
|
const services = domain.data.services as unknown as CollectionEntry<'services'>[];
|
|
115
244
|
|
|
116
|
-
const events = await
|
|
117
|
-
|
|
118
|
-
|
|
245
|
+
const [events, commands, queries] = await Promise.all([
|
|
246
|
+
getCollection('events'),
|
|
247
|
+
getCollection('commands'),
|
|
248
|
+
getCollection('queries'),
|
|
249
|
+
]);
|
|
119
250
|
|
|
120
251
|
const allMessages = [...events, ...commands, ...queries];
|
|
252
|
+
const messageMap = createVersionedMap(allMessages);
|
|
121
253
|
|
|
122
254
|
const sends = services.flatMap((service) => service.data.sends || []);
|
|
123
255
|
const receives = services.flatMap((service) => service.data.receives || []);
|
|
124
256
|
|
|
125
|
-
const sendsMessages = sends
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
257
|
+
const sendsMessages = sends
|
|
258
|
+
.map((send) => findInMap(messageMap, send.id, send.version))
|
|
259
|
+
.filter((msg): msg is CollectionEntry<CollectionMessageTypes> => !!msg);
|
|
260
|
+
|
|
261
|
+
const receivesMessages = receives
|
|
262
|
+
.map((receive) => findInMap(messageMap, receive.id, receive.version))
|
|
263
|
+
.filter((msg): msg is CollectionEntry<CollectionMessageTypes> => !!msg);
|
|
129
264
|
|
|
130
265
|
return {
|
|
131
|
-
sends: sendsMessages
|
|
132
|
-
receives: receivesMessages
|
|
266
|
+
sends: sendsMessages,
|
|
267
|
+
receives: receivesMessages,
|
|
133
268
|
};
|
|
134
269
|
};
|
|
135
270
|
|
|
@@ -212,6 +347,13 @@ export const getParentDomains = async (domain: Domain): Promise<Domain[]> => {
|
|
|
212
347
|
});
|
|
213
348
|
};
|
|
214
349
|
|
|
350
|
+
// Only return domains that are not found any any subdomain configuration
|
|
351
|
+
export const getRootDomains = async (): Promise<Domain[]> => {
|
|
352
|
+
const domains = await getDomains({ getAllVersions: false });
|
|
353
|
+
const allSubDomains = domains.flatMap((d) => d.data.domains as unknown as Domain[]);
|
|
354
|
+
return domains.filter((d) => !allSubDomains.some((sd) => sd.data.id === d.data.id));
|
|
355
|
+
};
|
|
356
|
+
|
|
215
357
|
export const getDomainsForService = async (service: Service): Promise<Domain[]> => {
|
|
216
358
|
const domains = await getDomains({ getAllVersions: false });
|
|
217
359
|
return domains.filter((d) => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { getVersionForCollectionItem, satisfies } from './collections/util';
|
|
5
4
|
import utils from '@eventcatalog/sdk';
|
|
5
|
+
import { createVersionedMap, satisfies } from './util';
|
|
6
6
|
|
|
7
7
|
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
|
|
8
8
|
|
|
@@ -11,6 +11,7 @@ export type Entity = CollectionEntry<'entities'> & {
|
|
|
11
11
|
path: string;
|
|
12
12
|
filePath: string;
|
|
13
13
|
type: string;
|
|
14
|
+
publicPath: string;
|
|
14
15
|
};
|
|
15
16
|
};
|
|
16
17
|
|
|
@@ -19,46 +20,62 @@ interface Props {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
// cache for build time
|
|
22
|
-
let
|
|
23
|
-
allVersions: [],
|
|
24
|
-
currentVersions: [],
|
|
25
|
-
};
|
|
23
|
+
let memoryCache: Record<string, Entity[]> = {};
|
|
26
24
|
|
|
27
25
|
export const getEntities = async ({ getAllVersions = true }: Props = {}): Promise<Entity[]> => {
|
|
26
|
+
// console.time('✅ New getEntities');
|
|
28
27
|
const cacheKey = getAllVersions ? 'allVersions' : 'currentVersions';
|
|
29
28
|
|
|
30
|
-
if (
|
|
31
|
-
|
|
29
|
+
if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0) {
|
|
30
|
+
// console.timeEnd('✅ New getEntities');
|
|
31
|
+
return memoryCache[cacheKey];
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
// 1. Fetch collections in parallel
|
|
35
|
+
const [allEntities, allServices, allDomains] = await Promise.all([
|
|
36
|
+
getCollection('entities'),
|
|
37
|
+
getCollection('services'),
|
|
38
|
+
getCollection('domains'),
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
// 2. Build optimized maps
|
|
42
|
+
const entityMap = createVersionedMap(allEntities);
|
|
43
|
+
|
|
44
|
+
// 3. Filter entities
|
|
45
|
+
const targetEntities = allEntities.filter((entity) => {
|
|
46
|
+
if (entity.data.hidden === true) return false;
|
|
47
|
+
if (!getAllVersions && entity.filePath?.includes('versioned')) return false;
|
|
48
|
+
return true;
|
|
36
49
|
});
|
|
37
50
|
|
|
38
|
-
const
|
|
39
|
-
const domains = await getCollection('domains');
|
|
51
|
+
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
// 4. Enrich entities
|
|
54
|
+
const processedEntities = await Promise.all(
|
|
55
|
+
targetEntities.map(async (entity) => {
|
|
56
|
+
// Version info
|
|
57
|
+
const entityVersions = entityMap.get(entity.data.id) || [];
|
|
58
|
+
const latestVersion = entityVersions[0]?.data.version || entity.data.version;
|
|
59
|
+
const versions = entityVersions.map((e) => e.data.version);
|
|
44
60
|
|
|
45
|
-
|
|
61
|
+
// Find Services that reference this entity
|
|
62
|
+
const servicesThatReferenceEntity = allServices.filter((service) =>
|
|
46
63
|
service.data.entities?.some((item) => {
|
|
47
|
-
if (item.id
|
|
48
|
-
if (item.version
|
|
64
|
+
if (item.id !== entity.data.id) return false;
|
|
65
|
+
if (item.version === 'latest' || item.version === undefined) return entity.data.version === latestVersion;
|
|
49
66
|
return satisfies(entity.data.version, item.version);
|
|
50
67
|
})
|
|
51
68
|
);
|
|
52
69
|
|
|
53
|
-
|
|
70
|
+
// Find Domains that reference this entity
|
|
71
|
+
const domainsThatReferenceEntity = allDomains.filter((domain) =>
|
|
54
72
|
domain.data.entities?.some((item) => {
|
|
55
|
-
if (item.id
|
|
56
|
-
if (item.version
|
|
73
|
+
if (item.id !== entity.data.id) return false;
|
|
74
|
+
if (item.version === 'latest' || item.version === undefined) return entity.data.version === latestVersion;
|
|
57
75
|
return satisfies(entity.data.version, item.version);
|
|
58
76
|
})
|
|
59
77
|
);
|
|
60
78
|
|
|
61
|
-
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
62
79
|
const folderName = await getResourceFolderName(
|
|
63
80
|
process.env.PROJECT_DIR ?? '',
|
|
64
81
|
entity.data.id,
|
|
@@ -87,10 +104,13 @@ export const getEntities = async ({ getAllVersions = true }: Props = {}): Promis
|
|
|
87
104
|
})
|
|
88
105
|
);
|
|
89
106
|
|
|
90
|
-
// order them by the name of the
|
|
91
|
-
|
|
107
|
+
// order them by the name of the entity
|
|
108
|
+
processedEntities.sort((a, b) => {
|
|
92
109
|
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
93
110
|
});
|
|
94
111
|
|
|
95
|
-
|
|
112
|
+
memoryCache[cacheKey] = processedEntities;
|
|
113
|
+
// console.timeEnd('✅ New getEntities');
|
|
114
|
+
|
|
115
|
+
return processedEntities;
|
|
96
116
|
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { getCollection } from 'astro:content';
|
|
2
|
+
import type { CollectionEntry } from 'astro:content';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { createVersionedMap, findInMap, satisfies } from './util';
|
|
5
|
+
import utils from '@eventcatalog/sdk';
|
|
6
|
+
|
|
7
|
+
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
|
|
8
|
+
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
9
|
+
|
|
10
|
+
type Event = CollectionEntry<'events'> & {
|
|
11
|
+
catalog: {
|
|
12
|
+
path: string;
|
|
13
|
+
filePath: string;
|
|
14
|
+
type: string;
|
|
15
|
+
publicPath: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
getAllVersions?: boolean;
|
|
21
|
+
hydrateServices?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Simple in-memory cache
|
|
25
|
+
let memoryCache: Record<string, Event[]> = {};
|
|
26
|
+
|
|
27
|
+
export const getEvents = async ({ getAllVersions = true, hydrateServices = true }: Props = {}): Promise<Event[]> => {
|
|
28
|
+
// console.time('✅ New getEvents');
|
|
29
|
+
const cacheKey = `${getAllVersions ? 'allVersions' : 'currentVersions'}-${hydrateServices ? 'hydrated' : 'minimal'}`;
|
|
30
|
+
|
|
31
|
+
// Check cache
|
|
32
|
+
if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
|
|
33
|
+
// console.timeEnd('✅ New getEvents');
|
|
34
|
+
return memoryCache[cacheKey];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 1. Fetch collections in parallel
|
|
38
|
+
const [allEvents, allServices, allChannels] = await Promise.all([
|
|
39
|
+
getCollection('events'),
|
|
40
|
+
getCollection('services'),
|
|
41
|
+
getCollection('channels'),
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
// 2. Build optimized maps
|
|
45
|
+
const eventMap = createVersionedMap(allEvents);
|
|
46
|
+
// We don't map services/channels by ID because we need to iterate them to find relationships (reverse lookup)
|
|
47
|
+
// or use them for hydration.
|
|
48
|
+
// Actually, for hydration we CAN use a map if we know the IDs, but here we scan services to find producers/consumers.
|
|
49
|
+
|
|
50
|
+
// 3. Filter events
|
|
51
|
+
const targetEvents = allEvents.filter((event) => {
|
|
52
|
+
if (event.data.hidden === true) return false;
|
|
53
|
+
if (!getAllVersions && event.filePath?.includes('versioned')) return false;
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
|
|
58
|
+
|
|
59
|
+
// 4. Enrich events
|
|
60
|
+
const processedEvents = await Promise.all(
|
|
61
|
+
targetEvents.map(async (event) => {
|
|
62
|
+
// Version info
|
|
63
|
+
const eventVersions = eventMap.get(event.data.id) || [];
|
|
64
|
+
const latestVersion = eventVersions[0]?.data.version || event.data.version;
|
|
65
|
+
const versions = eventVersions.map((e) => e.data.version);
|
|
66
|
+
|
|
67
|
+
// Find Producers (Services that send this event)
|
|
68
|
+
const producers = allServices
|
|
69
|
+
.filter((service) =>
|
|
70
|
+
service.data.sends?.some((item) => {
|
|
71
|
+
if (item.id !== event.data.id) return false;
|
|
72
|
+
if (item.version === 'latest' || item.version === undefined) return event.data.version === latestVersion;
|
|
73
|
+
return satisfies(event.data.version, item.version);
|
|
74
|
+
})
|
|
75
|
+
)
|
|
76
|
+
.map((service) => {
|
|
77
|
+
if (!hydrateServices) return { id: service.data.id, version: service.data.version };
|
|
78
|
+
return service;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Find Consumers (Services that receive this event)
|
|
82
|
+
const consumers = allServices
|
|
83
|
+
.filter((service) =>
|
|
84
|
+
service.data.receives?.some((item) => {
|
|
85
|
+
if (item.id !== event.data.id) return false;
|
|
86
|
+
if (item.version === 'latest' || item.version === undefined) return event.data.version === latestVersion;
|
|
87
|
+
return satisfies(event.data.version, item.version);
|
|
88
|
+
})
|
|
89
|
+
)
|
|
90
|
+
.map((service) => {
|
|
91
|
+
if (!hydrateServices) return { id: service.data.id, version: service.data.version };
|
|
92
|
+
return service;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Find Channels
|
|
96
|
+
const messageChannels = event.data.channels || [];
|
|
97
|
+
// This is O(N*M) where N is event channels and M is all channels.
|
|
98
|
+
// Typically M is small, but we could optimize if needed.
|
|
99
|
+
// Given the logic is simply ID match, we can use a Set or Map if needed, but array filter is likely fine for now unless M is huge.
|
|
100
|
+
const channelsForEvent = allChannels.filter((c) => messageChannels.some((channel) => c.data.id === channel.id));
|
|
101
|
+
|
|
102
|
+
const folderName = await getResourceFolderName(process.env.PROJECT_DIR ?? '', event.data.id, event.data.version.toString());
|
|
103
|
+
const eventFolderName = folderName ?? event.id.replace(`-${event.data.version}`, '');
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
...event,
|
|
107
|
+
data: {
|
|
108
|
+
...event.data,
|
|
109
|
+
messageChannels: channelsForEvent,
|
|
110
|
+
producers: producers as any, // Cast for hydration flexibility
|
|
111
|
+
consumers: consumers as any,
|
|
112
|
+
versions,
|
|
113
|
+
latestVersion,
|
|
114
|
+
},
|
|
115
|
+
catalog: {
|
|
116
|
+
path: path.join(event.collection, event.id.replace('/index.mdx', '')),
|
|
117
|
+
absoluteFilePath: path.join(PROJECT_DIR, event.collection, event.id.replace('/index.mdx', '/index.md')),
|
|
118
|
+
astroContentFilePath: path.join(process.cwd(), 'src', 'content', event.collection, event.id),
|
|
119
|
+
filePath: path.join(process.cwd(), 'src', 'catalog-files', event.collection, event.id.replace('/index.mdx', '')),
|
|
120
|
+
publicPath: path.join('/generated', event.collection, eventFolderName),
|
|
121
|
+
type: 'event',
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// order them by the name of the event
|
|
128
|
+
processedEvents.sort((a, b) => {
|
|
129
|
+
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
memoryCache[cacheKey] = processedEvents;
|
|
133
|
+
// console.timeEnd('✅ New getEvents');
|
|
134
|
+
|
|
135
|
+
return processedEvents;
|
|
136
|
+
};
|