@eventcatalog/core 3.7.1 → 3.8.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 (67) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-44EDP7IH.js → chunk-4EJDLNIX.js} +1 -1
  6. package/dist/{chunk-MIHGWXCX.js → chunk-EG36OTR7.js} +1 -1
  7. package/dist/{chunk-BVJJ3COQ.js → chunk-GITARDPK.js} +1 -1
  8. package/dist/{chunk-PV5ER42D.js → chunk-IEEU454Z.js} +1 -1
  9. package/dist/{chunk-B6NBNZGS.js → chunk-ZIG6J4R2.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +13 -1
  19. package/eventcatalog/src/components/Grids/DomainGrid.tsx +109 -6
  20. package/eventcatalog/src/components/Grids/utils.tsx +10 -1
  21. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +2 -0
  22. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.tsx +4 -0
  23. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/DataProduct.tsx +132 -0
  24. package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +29 -2
  25. package/eventcatalog/src/components/SchemaExplorer/types.ts +5 -1
  26. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +3 -0
  27. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +1 -0
  28. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +23 -1
  29. package/eventcatalog/src/components/Tables/Discover/columns.tsx +62 -0
  30. package/eventcatalog/src/content.config.ts +34 -0
  31. package/eventcatalog/src/enterprise/ai/chat-api.ts +26 -0
  32. package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +1 -1
  33. package/eventcatalog/src/enterprise/tools/catalog-tools.ts +169 -2
  34. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -1
  35. package/eventcatalog/src/pages/discover/[type]/index.astro +57 -1
  36. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
  37. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +5 -1
  38. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +27 -3
  39. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +74 -25
  40. package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +107 -1
  41. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +10 -1
  42. package/eventcatalog/src/stores/sidebar-store/builders/container.ts +23 -16
  43. package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +130 -0
  44. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +51 -0
  45. package/eventcatalog/src/stores/sidebar-store/state.ts +68 -13
  46. package/eventcatalog/src/styles/theme.css +4 -0
  47. package/eventcatalog/src/styles/themes/forest.css +4 -0
  48. package/eventcatalog/src/styles/themes/ocean.css +4 -0
  49. package/eventcatalog/src/styles/themes/sapphire.css +4 -0
  50. package/eventcatalog/src/styles/themes/sunset.css +4 -0
  51. package/eventcatalog/src/types/index.ts +4 -2
  52. package/eventcatalog/src/utils/collections/commands.ts +11 -29
  53. package/eventcatalog/src/utils/collections/containers.ts +25 -1
  54. package/eventcatalog/src/utils/collections/data-products.ts +85 -0
  55. package/eventcatalog/src/utils/collections/domains.ts +33 -11
  56. package/eventcatalog/src/utils/collections/events.ts +11 -29
  57. package/eventcatalog/src/utils/collections/icons.ts +5 -0
  58. package/eventcatalog/src/utils/collections/messages.ts +68 -0
  59. package/eventcatalog/src/utils/collections/queries.ts +11 -29
  60. package/eventcatalog/src/utils/collections/services.ts +2 -26
  61. package/eventcatalog/src/utils/collections/util.ts +75 -2
  62. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +91 -3
  63. package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +225 -0
  64. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +28 -2
  65. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +74 -20
  66. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
  67. package/package.json +2 -2
@@ -0,0 +1,225 @@
1
+ import { getCollection, type CollectionEntry } from 'astro:content';
2
+ import dagre from 'dagre';
3
+ import {
4
+ createDagreGraph,
5
+ generateIdForNode,
6
+ generatedIdForEdge,
7
+ calculatedNodes,
8
+ createEdge,
9
+ getColorFromString,
10
+ } from '@utils/node-graphs/utils/utils';
11
+
12
+ import { findInMap, createVersionedMap, mergeMaps, collectionToResourceMap } from '@utils/collections/util';
13
+ import { MarkerType } from '@xyflow/react';
14
+ import { getMessages, isCollectionAMessage } from '@utils/collections/messages';
15
+ import { getProducersOfMessage } from '@utils/collections/services';
16
+ import type { CollectionMessageTypes } from '@types';
17
+ import { getNodesAndEdgesForProducedMessage } from './message-node-graph';
18
+
19
+ type DagreGraph = any;
20
+
21
+ interface Props {
22
+ id: string;
23
+ version: string;
24
+ defaultFlow?: DagreGraph;
25
+ mode?: 'simple' | 'full';
26
+ }
27
+
28
+ const getNodePropertyFromCollectionType = (type: string) => {
29
+ if (isCollectionAMessage(type)) return 'message';
30
+ if (type === 'containers') return 'data';
31
+ return collectionToResourceMap[type as keyof typeof collectionToResourceMap];
32
+ };
33
+
34
+ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simple' }: Props) => {
35
+ const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
36
+ let nodes = [] as any,
37
+ edges = [] as any;
38
+
39
+ const [dataProducts, containers, services, events, queries, commands, channels] = await Promise.all([
40
+ getCollection('data-products'),
41
+ getCollection('containers'),
42
+ getCollection('services'),
43
+ getCollection('events'),
44
+ getCollection('queries'),
45
+ getCollection('commands'),
46
+ getCollection('channels'),
47
+ ]);
48
+
49
+ const dataProduct = dataProducts.find((dp) => dp.data.id === id && dp.data.version === version);
50
+
51
+ // Nothing found...
52
+ if (!dataProduct) {
53
+ return {
54
+ nodes: [],
55
+ edges: [],
56
+ };
57
+ }
58
+
59
+ // Build maps for O(1) lookups
60
+ const messages = [...events, ...commands, ...queries];
61
+
62
+ const messageMap = createVersionedMap(messages);
63
+ const containerMap = createVersionedMap(containers);
64
+ const serviceMap = createVersionedMap(services);
65
+ const channelMap = createVersionedMap(channels);
66
+
67
+ const inputsRaw = dataProduct?.data.inputs || [];
68
+ const outputsRaw = dataProduct?.data.outputs || [];
69
+
70
+ const resourceMap = mergeMaps<
71
+ | CollectionEntry<CollectionMessageTypes>
72
+ | CollectionEntry<'services'>
73
+ | CollectionEntry<'containers'>
74
+ | CollectionEntry<'channels'>
75
+ >(messageMap, serviceMap, containerMap, channelMap);
76
+
77
+ // Process inputs - messages, containers, services, channels (etc)
78
+ inputsRaw.forEach((inputConfig) => {
79
+ let inputResource = findInMap(resourceMap, inputConfig.id, inputConfig.version) as
80
+ | CollectionEntry<CollectionMessageTypes>
81
+ | CollectionEntry<'services'>
82
+ | CollectionEntry<'containers'>
83
+ | CollectionEntry<'channels'>;
84
+
85
+ const existingNode = nodes.find((n: any) => n.id === generateIdForNode(inputResource));
86
+
87
+ if (!existingNode) {
88
+ const nodeDataKey = getNodePropertyFromCollectionType(inputResource?.collection);
89
+
90
+ nodes.push({
91
+ id: generateIdForNode(inputResource),
92
+ sourcePosition: 'right',
93
+ targetPosition: 'left',
94
+ data: { mode, [nodeDataKey]: { ...inputResource?.data } },
95
+ type: (inputResource?.collection as any) === 'containers' ? 'data' : inputResource?.collection,
96
+ });
97
+ }
98
+
99
+ // If collection is a message we render the producers of the message
100
+ if (isCollectionAMessage(inputResource?.collection)) {
101
+ const producersOfMessage = getProducersOfMessage(
102
+ services as CollectionEntry<'services'>[],
103
+ inputResource as CollectionEntry<CollectionMessageTypes>
104
+ ) as CollectionEntry<'services'>[];
105
+ for (const producer of producersOfMessage) {
106
+ const { nodes: producerNodes, edges: producerEdges } = getNodesAndEdgesForProducedMessage({
107
+ message: inputResource as CollectionEntry<CollectionMessageTypes>,
108
+ // We dont render any other services that consume this event for now
109
+ services: [],
110
+ // We dont render channels on this view for now...
111
+ channels: [],
112
+ currentNodes: nodes,
113
+ currentEdges: edges,
114
+ source: producer,
115
+ mode,
116
+ });
117
+
118
+ nodes.push(...producerNodes);
119
+ edges.push(...producerEdges);
120
+ }
121
+ }
122
+
123
+ // Add edge from resource to data product
124
+ edges.push(
125
+ createEdge({
126
+ id: generatedIdForEdge(inputResource, dataProduct),
127
+ source: generateIdForNode(inputResource),
128
+ target: generateIdForNode(dataProduct),
129
+ label: 'input',
130
+ type: 'animated',
131
+ data: {
132
+ customColor: getColorFromString(inputResource.data.id),
133
+ rootSourceAndTarget: { source: inputResource, target: dataProduct },
134
+ },
135
+ markerEnd: {
136
+ type: MarkerType.ArrowClosed,
137
+ color: '#666',
138
+ width: 40,
139
+ height: 40,
140
+ },
141
+ })
142
+ );
143
+ });
144
+
145
+ // The data product itself
146
+ nodes.push({
147
+ id: generateIdForNode(dataProduct),
148
+ sourcePosition: 'right',
149
+ targetPosition: 'left',
150
+ data: { mode, dataProduct: { ...dataProduct.data } },
151
+ type: 'data-products',
152
+ });
153
+
154
+ // Process outputs - messages, services, containers, channels that the data product produces
155
+ outputsRaw.forEach((outputConfig) => {
156
+ // Find the output resource (can be message, service, container, or channel)
157
+ const outputResource = findInMap(resourceMap, outputConfig.id, outputConfig.version) as
158
+ | CollectionEntry<CollectionMessageTypes>
159
+ | CollectionEntry<'services'>
160
+ | CollectionEntry<'containers'>
161
+ | CollectionEntry<'channels'>;
162
+
163
+ if (!outputResource) return;
164
+
165
+ // Add the node if it doesn't exist
166
+ const existingNode = nodes.find((n: any) => n.id === generateIdForNode(outputResource));
167
+ if (!existingNode) {
168
+ const nodeDataKey = getNodePropertyFromCollectionType(outputResource?.collection);
169
+
170
+ nodes.push({
171
+ id: generateIdForNode(outputResource),
172
+ sourcePosition: 'right',
173
+ targetPosition: 'left',
174
+ data: { mode, [nodeDataKey]: { ...outputResource?.data } },
175
+ type: (outputResource?.collection as any) === 'containers' ? 'data' : outputResource?.collection,
176
+ });
177
+ }
178
+
179
+ // Add edge from data product to the output resource
180
+ edges.push(
181
+ createEdge({
182
+ id: generatedIdForEdge(dataProduct, outputResource),
183
+ source: generateIdForNode(dataProduct),
184
+ target: generateIdForNode(outputResource),
185
+ label: 'output',
186
+ type: 'animated',
187
+ data: {
188
+ customColor: getColorFromString(outputResource.data.id),
189
+ rootSourceAndTarget: { source: dataProduct, target: outputResource },
190
+ },
191
+ markerEnd: {
192
+ type: MarkerType.ArrowClosed,
193
+ color: '#666',
194
+ width: 40,
195
+ height: 40,
196
+ },
197
+ })
198
+ );
199
+ });
200
+
201
+ nodes.forEach((node: any) => {
202
+ flow.setNode(node.id, { width: 150, height: 100 });
203
+ });
204
+
205
+ edges.forEach((edge: any) => {
206
+ flow.setEdge(edge.source, edge.target);
207
+ });
208
+
209
+ // Render the diagram in memory getting the X and Y
210
+ dagre.layout(flow);
211
+
212
+ // Find any duplicated edges, and merge them into one edge
213
+ const uniqueEdges = edges.reduce((acc: any[], edge: any) => {
214
+ const existingEdge = acc.find((e: any) => e.id === edge.id);
215
+ if (!existingEdge) {
216
+ acc.push(edge);
217
+ }
218
+ return acc;
219
+ }, []);
220
+
221
+ return {
222
+ nodes: calculatedNodes(flow, nodes),
223
+ edges: uniqueEdges,
224
+ };
225
+ };
@@ -8,6 +8,7 @@ import {
8
8
  createEdge,
9
9
  } from '@utils/node-graphs/utils/utils';
10
10
  import { getNodesAndEdges as getServicesNodeAndEdges } from './services-node-graph';
11
+ import { getNodesAndEdges as getDataProductsNodeAndEdges } from './data-products-node-graph';
11
12
  import merge from 'lodash.merge';
12
13
  import { createVersionedMap, findInMap } from '@utils/collections/util';
13
14
  import type { Node } from '@xyflow/react';
@@ -199,7 +200,11 @@ export const getNodesAndEdges = async ({
199
200
  edges = new Map();
200
201
 
201
202
  // 1. Parallel Fetching
202
- const [domains, services] = await Promise.all([getCollection('domains'), getCollection('services')]);
203
+ const [domains, services, dataProducts] = await Promise.all([
204
+ getCollection('domains'),
205
+ getCollection('services'),
206
+ getCollection('data-products'),
207
+ ]);
203
208
 
204
209
  const domain = domains.find((service) => service.data.id === id && service.data.version === version);
205
210
 
@@ -214,9 +219,11 @@ export const getNodesAndEdges = async ({
214
219
  // 2. Build optimized maps
215
220
  const serviceMap = createVersionedMap(services);
216
221
  const domainMap = createVersionedMap(domains);
222
+ const dataProductMap = createVersionedMap(dataProducts);
217
223
 
218
224
  const rawServices = domain?.data.services || [];
219
225
  const rawSubDomains = domain?.data.domains || [];
226
+ const rawDataProducts = (domain?.data as any)['data-products'] || [];
220
227
 
221
228
  // Optimized hydration
222
229
  const domainServicesWithVersion = rawServices
@@ -229,7 +236,12 @@ export const getNodesAndEdges = async ({
229
236
  .filter((d): d is any => !!d)
230
237
  .map((svc) => ({ id: svc.data.id, version: svc.data.version }));
231
238
 
232
- // Get all the nodes for everyhing
239
+ const domainDataProductsWithVersion = rawDataProducts
240
+ .map((dataProduct: any) => findInMap(dataProductMap, dataProduct.id, dataProduct.version))
241
+ .filter((dp: any): dp is any => !!dp)
242
+ .map((dp: any) => ({ id: dp.data.id, version: dp.data.version }));
243
+
244
+ // Get all the nodes for everything
233
245
 
234
246
  for (const service of domainServicesWithVersion) {
235
247
  const { nodes: serviceNodes, edges: serviceEdges } = await getServicesNodeAndEdges({
@@ -255,6 +267,20 @@ export const getNodesAndEdges = async ({
255
267
  serviceEdges.forEach((e) => edges.set(e.id, e));
256
268
  }
257
269
 
270
+ for (const dataProduct of domainDataProductsWithVersion) {
271
+ const { nodes: dataProductNodes, edges: dataProductEdges } = await getDataProductsNodeAndEdges({
272
+ id: dataProduct.id,
273
+ version: dataProduct.version,
274
+ defaultFlow: flow,
275
+ mode,
276
+ });
277
+ dataProductNodes.forEach((n: any) => {
278
+ nodes.set(n.id, nodes.has(n.id) ? merge(nodes.get(n.id), n) : n);
279
+ });
280
+ // @ts-ignore
281
+ dataProductEdges.forEach((e) => edges.set(e.id, e));
282
+ }
283
+
258
284
  for (const subDomain of domainSubDomainsWithVersion) {
259
285
  const { nodes: subDomainNodes, edges: subDomainEdges } = await getNodesAndEdges({
260
286
  id: subDomain.id,
@@ -84,25 +84,55 @@ const getNodesAndEdges = async ({
84
84
  type: message.collection,
85
85
  });
86
86
 
87
- const producers = (message.data.producers as CollectionEntry<'services'>[]) || [];
88
- const consumers = (message.data.consumers as CollectionEntry<'services'>[]) || [];
87
+ const producers = (message.data.producers as (CollectionEntry<'services'> | CollectionEntry<'data-products'>)[]) || [];
88
+ const consumers = (message.data.consumers as (CollectionEntry<'services'> | CollectionEntry<'data-products'>)[]) || [];
89
89
 
90
- // Track nodes that are both sent and received
91
- const bothSentAndReceived = findMatchingNodes(producers, consumers);
90
+ // Track nodes that are both sent and received (only for services)
91
+ const serviceProducers = producers.filter((p) => p.collection === 'services') as CollectionEntry<'services'>[];
92
+ const serviceConsumers = consumers.filter((c) => c.collection === 'services') as CollectionEntry<'services'>[];
93
+ const bothSentAndReceived = findMatchingNodes(serviceProducers, serviceConsumers);
92
94
 
93
95
  for (const producer of producers) {
94
- // Create the producer node
96
+ const isDataProduct = producer.collection === 'data-products';
97
+
98
+ // Create the producer node with appropriate data structure
95
99
  nodes.push({
96
100
  id: generateIdForNode(producer),
97
- type: producer?.collection,
101
+ type: isDataProduct ? 'data-products' : producer?.collection,
98
102
  sourcePosition: 'right',
99
103
  targetPosition: 'left',
100
- data: { mode, service: { ...producer.data } },
104
+ data: isDataProduct ? { mode, dataProduct: { ...producer.data } } : { mode, service: { ...producer.data } },
101
105
  position: { x: 250, y: 0 },
102
106
  });
103
107
 
108
+ // Data products don't have channel configuration, so connect directly to the message
109
+ if (isDataProduct) {
110
+ const rootSourceAndTarget = {
111
+ source: { id: generateIdForNode(producer), collection: producer.collection },
112
+ target: { id: generateIdForNode(message), collection: message.collection },
113
+ };
114
+
115
+ edges.push({
116
+ id: generatedIdForEdge(producer, message),
117
+ source: generateIdForNode(producer),
118
+ target: generateIdForNode(message),
119
+ label: 'produces',
120
+ data: { customColor: getColorFromString(message.data.id), rootSourceAndTarget },
121
+ animated: false,
122
+ markerEnd: {
123
+ type: MarkerType.ArrowClosed,
124
+ width: 40,
125
+ height: 40,
126
+ },
127
+ });
128
+ continue;
129
+ }
130
+
131
+ // Service-specific channel handling
132
+ const serviceProducer = producer as CollectionEntry<'services'>;
133
+
104
134
  // Is the producer sending this message to a channel?
105
- const producerConfigurationForMessage = producer.data.sends?.find((send) => send.id === message.data.id);
135
+ const producerConfigurationForMessage = serviceProducer.data.sends?.find((send) => send.id === message.data.id);
106
136
  const producerChannelConfiguration = producerConfigurationForMessage?.to ?? [];
107
137
 
108
138
  const producerHasChannels = producerChannelConfiguration?.length > 0;
@@ -184,18 +214,44 @@ const getNodesAndEdges = async ({
184
214
 
185
215
  // The messages the service sends
186
216
  for (const consumer of consumers) {
187
- // Render the consumer node
217
+ const isDataProduct = consumer.collection === 'data-products';
218
+
219
+ // Render the consumer node with appropriate data structure
188
220
  nodes.push({
189
221
  id: generateIdForNode(consumer),
190
222
  sourcePosition: 'right',
191
223
  targetPosition: 'left',
192
- data: { title: consumer?.data.id, mode, service: { ...consumer.data } },
224
+ data: isDataProduct
225
+ ? { title: consumer?.data.id, mode, dataProduct: { ...consumer.data } }
226
+ : { title: consumer?.data.id, mode, service: { ...consumer.data } },
193
227
  position: { x: 0, y: 0 },
194
- type: consumer?.collection,
228
+ type: isDataProduct ? 'data-products' : consumer?.collection,
195
229
  });
196
230
 
231
+ // Data products don't have channel configuration, so connect directly from the message
232
+ if (isDataProduct) {
233
+ const rootSourceAndTarget = {
234
+ source: { id: generateIdForNode(message), collection: message.collection },
235
+ target: { id: generateIdForNode(consumer), collection: consumer.collection },
236
+ };
237
+
238
+ edges.push(
239
+ createEdge({
240
+ id: generatedIdForEdge(message, consumer),
241
+ source: generateIdForNode(message),
242
+ target: generateIdForNode(consumer),
243
+ label: 'consumed by',
244
+ data: { customColor: getColorFromString(message.data.id), rootSourceAndTarget },
245
+ })
246
+ );
247
+ continue;
248
+ }
249
+
250
+ // Service-specific channel handling
251
+ const serviceConsumer = consumer as CollectionEntry<'services'>;
252
+
197
253
  // Is the consumer receiving this message from a channel?
198
- const consumerConfigurationForMessage = consumer.data.receives?.find((receive) => receive.id === message.data.id);
254
+ const consumerConfigurationForMessage = serviceConsumer.data.receives?.find((receive) => receive.id === message.data.id);
199
255
  const consumerChannelConfiguration = consumerConfigurationForMessage?.from ?? [];
200
256
 
201
257
  const consumerHasChannels = consumerChannelConfiguration.length > 0;
@@ -237,10 +293,11 @@ const getNodesAndEdges = async ({
237
293
  }
238
294
 
239
295
  // Can any of the consumer channels be linked to any of the producer channels?
240
- const producerChannels = producers
296
+ // Only consider service producers for channel linking (data products don't have sends/receives)
297
+ const producerChannels = serviceProducers
241
298
  .map((producer) => producer.data.sends?.find((send) => send.id === message.data.id)?.to ?? [])
242
299
  .flat();
243
- const consumerChannels = consumer.data.receives?.find((receive) => receive.id === message.data.id)?.from ?? [];
300
+ const consumerChannels = serviceConsumer.data.receives?.find((receive) => receive.id === message.data.id)?.from ?? [];
244
301
 
245
302
  for (const producerChannel of producerChannels) {
246
303
  const producerChannelValue = findInMap(
@@ -376,8 +433,7 @@ export const getNodesAndEdgesForQueries = async ({
376
433
  mode = 'simple',
377
434
  channelRenderMode = 'flat',
378
435
  }: Props) => {
379
- const queries = await getQueries();
380
- const channels = await getChannels();
436
+ const [queries, channels] = await Promise.all([getQueries(), getChannels()]);
381
437
  return getNodesAndEdges({ id, version, defaultFlow, mode, channelRenderMode, collection: queries, channels });
382
438
  };
383
439
 
@@ -388,8 +444,7 @@ export const getNodesAndEdgesForCommands = async ({
388
444
  mode = 'simple',
389
445
  channelRenderMode = 'flat',
390
446
  }: Props) => {
391
- const commands = await getCommands();
392
- const channels = await getChannels();
447
+ const [commands, channels] = await Promise.all([getCommands(), getChannels()]);
393
448
  return getNodesAndEdges({ id, version, defaultFlow, mode, channelRenderMode, collection: commands, channels });
394
449
  };
395
450
 
@@ -400,8 +455,7 @@ export const getNodesAndEdgesForEvents = async ({
400
455
  mode = 'simple',
401
456
  channelRenderMode = 'flat',
402
457
  }: Props) => {
403
- const events = await getEvents();
404
- const channels = await getChannels();
458
+ const [events, channels] = await Promise.all([getEvents(), getChannels()]);
405
459
  return getNodesAndEdges({ id, version, defaultFlow, mode, channelRenderMode, collection: events, channels });
406
460
  };
407
461
 
@@ -9,6 +9,7 @@ import { getEntities } from '@utils/collections/entities';
9
9
  import { getContainers } from '@utils/collections/containers';
10
10
  import { getDiagrams } from '@utils/collections/diagrams';
11
11
  import type { CollectionEntry } from 'astro:content';
12
+ import { getDataProducts } from '@utils/collections/data-products';
12
13
 
13
14
  export const pageDataLoader: Record<PageTypes, () => Promise<CollectionEntry<CollectionTypes>[]>> = {
14
15
  events: getEvents,
@@ -21,4 +22,5 @@ export const pageDataLoader: Record<PageTypes, () => Promise<CollectionEntry<Col
21
22
  entities: getEntities,
22
23
  containers: getContainers,
23
24
  diagrams: getDiagrams,
25
+ 'data-products': getDataProducts,
24
26
  };
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/event-catalog/eventcatalog.git"
7
7
  },
8
8
  "type": "module",
9
- "version": "3.7.1",
9
+ "version": "3.8.0",
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
@@ -34,7 +34,7 @@
34
34
  "@eventcatalog/generator-ai": "^1.1.0",
35
35
  "@eventcatalog/license": "^0.0.7",
36
36
  "@eventcatalog/linter": "^0.0.2",
37
- "@eventcatalog/sdk": "^2.10.0",
37
+ "@eventcatalog/sdk": "^2.11.0",
38
38
  "@eventcatalog/visualizer": "^0.0.6",
39
39
  "@fontsource/inter": "^5.2.5",
40
40
  "@headlessui/react": "^2.0.3",