@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.
Files changed (123) hide show
  1. package/README.md +1 -1
  2. package/dist/analytics/analytics.cjs +1 -1
  3. package/dist/analytics/analytics.js +2 -2
  4. package/dist/analytics/log-build.cjs +1 -1
  5. package/dist/analytics/log-build.js +3 -3
  6. package/dist/{chunk-2TTD2MLE.js → chunk-JB4YT5JY.js} +1 -1
  7. package/dist/{chunk-BTS6L3KY.js → chunk-TQ4HZREX.js} +1 -1
  8. package/dist/{chunk-XB4SZX3I.js → chunk-X4W4YC3U.js} +1 -1
  9. package/dist/constants.cjs +1 -1
  10. package/dist/constants.js +1 -1
  11. package/dist/eventcatalog.cjs +1 -21
  12. package/dist/eventcatalog.config.d.cts +9 -0
  13. package/dist/eventcatalog.config.d.ts +9 -0
  14. package/dist/eventcatalog.js +3 -20
  15. package/eventcatalog/src/components/CopyAsMarkdown.tsx +19 -1
  16. package/eventcatalog/src/components/FavoriteButton.tsx +54 -0
  17. package/eventcatalog/src/components/Grids/DomainGrid.tsx +386 -362
  18. package/eventcatalog/src/components/Grids/MessageGrid.tsx +166 -523
  19. package/eventcatalog/src/components/Header.astro +48 -23
  20. package/eventcatalog/src/components/Lists/VersionList.astro +2 -2
  21. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +8 -2
  22. package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +37 -0
  23. package/eventcatalog/src/components/Search/Search.astro +48 -28
  24. package/eventcatalog/src/components/Search/SearchModal.tsx +393 -702
  25. package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +298 -0
  26. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/container.ts +66 -0
  27. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/domain.ts +101 -0
  28. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/flow.ts +29 -0
  29. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/message.ts +84 -0
  30. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/service.ts +147 -0
  31. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/shared.ts +146 -0
  32. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +1073 -0
  33. package/eventcatalog/src/components/SideNav/NestedSideBar/sidebar-builder.ts +365 -0
  34. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +90 -0
  35. package/eventcatalog/src/components/SideNav/SideNav.astro +18 -28
  36. package/eventcatalog/src/content.config.ts +2 -0
  37. package/eventcatalog/src/enterprise/eventcatalog-chat/pages/chat/index.astro +3 -3
  38. package/eventcatalog/src/layouts/DirectoryLayout.astro +2 -2
  39. package/eventcatalog/src/layouts/DiscoverLayout.astro +3 -3
  40. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +83 -64
  41. package/eventcatalog/src/layouts/VisualiserLayout.astro +3 -3
  42. package/eventcatalog/src/pages/_index.astro +530 -110
  43. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +64 -0
  44. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +29 -0
  45. package/eventcatalog/src/pages/directory/[type]/_index.data.ts +4 -4
  46. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -4
  47. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +3 -3
  48. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -5
  49. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +354 -186
  50. package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +1 -1
  51. package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +4 -4
  52. package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +1 -4
  53. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +3 -27
  54. package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +2 -2
  55. package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +2 -2
  56. package/eventcatalog/src/pages/nav-index.json.ts +30 -0
  57. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +77 -0
  58. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +90 -0
  59. package/eventcatalog/src/pages/schemas/{index.astro → explorer/index.astro} +3 -3
  60. package/eventcatalog/src/pages/studio.astro +3 -3
  61. package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +2 -2
  62. package/eventcatalog/src/stores/favorites-store.ts +83 -0
  63. package/eventcatalog/src/stores/sidebar-store.ts +8 -0
  64. package/eventcatalog/src/utils/collections/changelogs.ts +7 -4
  65. package/eventcatalog/src/utils/{channels.ts → collections/channels.ts} +81 -31
  66. package/eventcatalog/src/utils/collections/commands.ts +134 -0
  67. package/eventcatalog/src/utils/collections/containers.ts +44 -33
  68. package/eventcatalog/src/utils/collections/domains.ts +204 -62
  69. package/eventcatalog/src/utils/{entities.ts → collections/entities.ts} +44 -24
  70. package/eventcatalog/src/utils/collections/events.ts +136 -0
  71. package/eventcatalog/src/utils/collections/flows.ts +59 -25
  72. package/eventcatalog/src/utils/{messages.ts → collections/messages.ts} +13 -4
  73. package/eventcatalog/src/utils/{queries.ts → collections/queries.ts} +49 -28
  74. package/eventcatalog/src/utils/collections/services.ts +100 -68
  75. package/eventcatalog/src/utils/collections/teams.ts +94 -0
  76. package/eventcatalog/src/utils/collections/users.ts +122 -0
  77. package/eventcatalog/src/utils/collections/util.ts +57 -1
  78. package/eventcatalog/src/utils/feature.ts +2 -2
  79. package/eventcatalog/src/utils/{collections/file-diffs.ts → file-diffs.ts} +1 -1
  80. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +2 -0
  81. package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +16 -6
  82. package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +14 -10
  83. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +36 -64
  84. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +23 -19
  85. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +36 -49
  86. package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +22 -18
  87. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +4 -4
  88. package/eventcatalog/tailwind.config.mjs +14 -0
  89. package/eventcatalog/tsconfig.json +2 -1
  90. package/package.json +7 -4
  91. package/eventcatalog/public/logo_old.png +0 -0
  92. package/eventcatalog/src/components/DiscoverInsight.astro +0 -61
  93. package/eventcatalog/src/components/Grids/ServiceGrid.tsx +0 -540
  94. package/eventcatalog/src/components/Lists/CustomSideBarSectionList.astro +0 -55
  95. package/eventcatalog/src/components/Lists/ProtocolList.tsx +0 -74
  96. package/eventcatalog/src/components/Lists/RepositoryList.astro +0 -37
  97. package/eventcatalog/src/components/Lists/SpecificationsList.astro +0 -67
  98. package/eventcatalog/src/components/SideBars/ChannelSideBar.astro +0 -204
  99. package/eventcatalog/src/components/SideBars/ContainerSideBar.astro +0 -183
  100. package/eventcatalog/src/components/SideBars/DomainSideBar.astro +0 -277
  101. package/eventcatalog/src/components/SideBars/EntitySideBar.astro +0 -139
  102. package/eventcatalog/src/components/SideBars/FlowSideBar.astro +0 -132
  103. package/eventcatalog/src/components/SideBars/MessageSideBar.astro +0 -251
  104. package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +0 -298
  105. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +0 -46
  106. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +0 -78
  107. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/SpecificationList.tsx +0 -83
  108. package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +0 -1250
  109. package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +0 -91
  110. package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +0 -201
  111. package/eventcatalog/src/components/SideNav/TreeView/getTreeView.ts +0 -190
  112. package/eventcatalog/src/components/SideNav/TreeView/index.tsx +0 -94
  113. package/eventcatalog/src/components/TreeView/index.tsx +0 -328
  114. package/eventcatalog/src/components/TreeView/styles.module.css +0 -264
  115. package/eventcatalog/src/components/TreeView/useSlots.ts +0 -95
  116. package/eventcatalog/src/pages/architecture/[type]/index.astro +0 -14
  117. package/eventcatalog/src/pages/architecture/architecture.astro +0 -110
  118. package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +0 -14
  119. package/eventcatalog/src/utils/commands.ts +0 -112
  120. package/eventcatalog/src/utils/events.ts +0 -108
  121. package/eventcatalog/src/utils/generators/index.ts +0 -10
  122. package/eventcatalog/src/utils/teams.ts +0 -72
  123. package/eventcatalog/src/utils/users.ts +0 -72
@@ -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 cachedEntities: Record<string, Entity[]> = {
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 (cachedEntities[cacheKey].length > 0) {
31
- return cachedEntities[cacheKey];
29
+ if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0) {
30
+ // console.timeEnd('✅ New getEntities');
31
+ return memoryCache[cacheKey];
32
32
  }
33
33
 
34
- const entities = await getCollection('entities', (entity) => {
35
- return (getAllVersions || !entity.filePath?.includes('versioned')) && entity.data.hidden !== true;
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 services = await getCollection('services');
39
- const domains = await getCollection('domains');
51
+ const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
40
52
 
41
- cachedEntities[cacheKey] = await Promise.all(
42
- entities.map(async (entity) => {
43
- const { latestVersion, versions } = getVersionForCollectionItem(entity, entities);
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
- const servicesThatReferenceEntity = services.filter((service) =>
61
+ // Find Services that reference this entity
62
+ const servicesThatReferenceEntity = allServices.filter((service) =>
46
63
  service.data.entities?.some((item) => {
47
- if (item.id != entity.data.id) return false;
48
- if (item.version == 'latest' || item.version == undefined) return entity.data.version == latestVersion;
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
- const domainsThatReferenceEntity = domains.filter((domain) =>
70
+ // Find Domains that reference this entity
71
+ const domainsThatReferenceEntity = allDomains.filter((domain) =>
54
72
  domain.data.entities?.some((item) => {
55
- if (item.id != entity.data.id) return false;
56
- if (item.version == 'latest' || item.version == undefined) return entity.data.version == latestVersion;
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 event
91
- cachedEntities[cacheKey].sort((a, b) => {
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
- return cachedEntities[cacheKey];
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
+ };
@@ -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 cachedFlows: Record<string, Flow[]> = {
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 (cachedFlows[cacheKey].length > 0) {
24
- return cachedFlows[cacheKey];
23
+ if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
24
+ // console.timeEnd('✅ New getFlows');
25
+ return memoryCache[cacheKey];
25
26
  }
26
27
 
27
- // Get flows that are not versioned
28
- const flows = await getCollection('flows', (flow) => {
29
- return (getAllVersions || !flow.filePath?.includes('versioned')) && flow.data.hidden !== true;
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 events = await getCollection('events');
33
- const commands = await getCollection('commands');
35
+ const allMessages = [...allEvents, ...allCommands];
34
36
 
35
- const allMessages = [...events, ...commands];
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 { ...flow, data: { ...flow.data, type: 'node' } };
45
- const message = getItemsFromCollectionByIdAndSemverOrLatest(allMessages, step.message.id, step.message.version);
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
- cachedFlows[cacheKey].sort((a, b) => {
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
- return cachedFlows[cacheKey];
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 { getVersionForCollectionItem, satisfies } from './collections/util';
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 cachedQueries: Record<string, Query[]> = {
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
- const cacheKey = getAllVersions ? 'allVersions' : 'currentVersions';
28
+ // console.time(' New getQueries');
29
+ const cacheKey = `${getAllVersions ? 'allVersions' : 'currentVersions'}-${hydrateServices ? 'hydrated' : 'minimal'}`;
30
30
 
31
- if (cachedQueries[cacheKey].length > 0 && hydrateServices) {
32
- return cachedQueries[cacheKey];
31
+ if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
32
+ // console.timeEnd('✅ New getQueries');
33
+ return memoryCache[cacheKey];
33
34
  }
34
35
 
35
- const queries = await getCollection('queries', (query) => {
36
- return (getAllVersions || !query.filePath?.includes('versioned')) && query.data.hidden !== true;
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 services = await getCollection('services');
40
- const allChannels = await getCollection('channels');
53
+ const { getResourceFolderName } = utils(process.env.PROJECT_DIR ?? '');
41
54
 
42
- // @ts-ignore
43
- cachedQueries[cacheKey] = await Promise.all(
44
- queries.map(async (query) => {
45
- const { latestVersion, versions } = getVersionForCollectionItem(query, queries);
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
- const producers = services
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 != query.data.id) return false;
51
- if (item.version == 'latest' || item.version == undefined) return query.data.version == latestVersion;
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
- const consumers = services
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 != query.data.id) return false;
64
- if (item.version == 'latest' || item.version == undefined) return query.data.version == latestVersion;
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
- cachedQueries[cacheKey].sort((a, b) => {
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
- return cachedQueries[cacheKey];
125
+ memoryCache[cacheKey] = processedQueries;
126
+ // console.timeEnd('✅ New getQueries');
127
+
128
+ return processedQueries;
108
129
  };