@eventcatalog/core 3.13.0-beta.1 → 3.13.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.
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "3.13.0-beta.1";
40
+ var version = "3.13.0";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-NXATPLVB.js";
4
- import "../chunk-VXTATPGX.js";
3
+ } from "../chunk-6OL426GP.js";
4
+ import "../chunk-53JVQT34.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -106,7 +106,7 @@ var import_axios = __toESM(require("axios"), 1);
106
106
  var import_os = __toESM(require("os"), 1);
107
107
 
108
108
  // package.json
109
- var version = "3.13.0-beta.1";
109
+ var version = "3.13.0";
110
110
 
111
111
  // src/constants.ts
112
112
  var VERSION = version;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-V3GX7FC3.js";
4
- import "../chunk-NXATPLVB.js";
3
+ } from "../chunk-I3U7AKYR.js";
4
+ import "../chunk-6OL426GP.js";
5
5
  import "../chunk-4UVFXLPI.js";
6
- import "../chunk-VXTATPGX.js";
6
+ import "../chunk-53JVQT34.js";
7
7
  import "../chunk-UPONRQSN.js";
8
8
  export {
9
9
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-7RCUF3VG.js";
3
+ } from "./chunk-BX3YBDRJ.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "3.13.0-beta.1";
2
+ var version = "3.13.0";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-VXTATPGX.js";
3
+ } from "./chunk-53JVQT34.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-VXTATPGX.js";
3
+ } from "./chunk-53JVQT34.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-NXATPLVB.js";
3
+ } from "./chunk-6OL426GP.js";
4
4
  import {
5
5
  countResources,
6
6
  serializeCounts
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "3.13.0-beta.1";
28
+ var version = "3.13.0";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-VXTATPGX.js";
3
+ } from "./chunk-53JVQT34.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -109,7 +109,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
109
109
  var import_picocolors = __toESM(require("picocolors"), 1);
110
110
 
111
111
  // package.json
112
- var version = "3.13.0-beta.1";
112
+ var version = "3.13.0";
113
113
 
114
114
  // src/constants.ts
115
115
  var VERSION = version;
@@ -6,8 +6,8 @@ import {
6
6
  } from "./chunk-PLNJC7NZ.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-V3GX7FC3.js";
10
- import "./chunk-NXATPLVB.js";
9
+ } from "./chunk-I3U7AKYR.js";
10
+ import "./chunk-6OL426GP.js";
11
11
  import "./chunk-4UVFXLPI.js";
12
12
  import {
13
13
  runMigrations
@@ -22,13 +22,13 @@ import {
22
22
  } from "./chunk-5VBIXL6C.js";
23
23
  import {
24
24
  generate
25
- } from "./chunk-AY2OEUWV.js";
25
+ } from "./chunk-33AANWUG.js";
26
26
  import {
27
27
  logger
28
- } from "./chunk-7RCUF3VG.js";
28
+ } from "./chunk-BX3YBDRJ.js";
29
29
  import {
30
30
  VERSION
31
- } from "./chunk-VXTATPGX.js";
31
+ } from "./chunk-53JVQT34.js";
32
32
  import {
33
33
  verifyRequiredFieldsAreInCatalogConfigFile
34
34
  } from "./chunk-UPONRQSN.js";
package/dist/generate.cjs CHANGED
@@ -73,7 +73,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
73
73
  var import_picocolors = __toESM(require("picocolors"), 1);
74
74
 
75
75
  // package.json
76
- var version = "3.13.0-beta.1";
76
+ var version = "3.13.0";
77
77
 
78
78
  // src/constants.ts
79
79
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-AY2OEUWV.js";
4
- import "./chunk-7RCUF3VG.js";
5
- import "./chunk-VXTATPGX.js";
3
+ } from "./chunk-33AANWUG.js";
4
+ import "./chunk-BX3YBDRJ.js";
5
+ import "./chunk-53JVQT34.js";
6
6
  import "./chunk-UPONRQSN.js";
7
7
  export {
8
8
  generate
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(cli_logger_exports);
36
36
  var import_picocolors = __toESM(require("picocolors"), 1);
37
37
 
38
38
  // package.json
39
- var version = "3.13.0-beta.1";
39
+ var version = "3.13.0";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  logger
3
- } from "../chunk-7RCUF3VG.js";
4
- import "../chunk-VXTATPGX.js";
3
+ } from "../chunk-BX3YBDRJ.js";
4
+ import "../chunk-53JVQT34.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -89,7 +89,7 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
89
89
  </button>
90
90
  <div
91
91
  id="profile-dropdown"
92
- class="hidden absolute right-0 mt-2 w-48 bg-[rgb(var(--ec-dropdown-bg))] rounded-lg shadow-md py-1 z-50 border-2 border-[rgb(var(--ec-dropdown-border))] overflow-hidden"
92
+ class="ec-hidden absolute right-0 mt-2 w-48 bg-[rgb(var(--ec-dropdown-bg))] rounded-lg shadow-md py-1 z-50 border-2 border-[rgb(var(--ec-dropdown-border))] overflow-hidden"
93
93
  >
94
94
  <div class="px-4 py-2 text-sm text-[rgb(var(--ec-dropdown-text))] border-b border-[rgb(var(--ec-dropdown-border))]">
95
95
  <div class="font-semibold">{session.user?.name || 'User'}</div>
@@ -194,7 +194,7 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
194
194
  </div>
195
195
  </div>
196
196
 
197
- <div id="mobile-menu" class="md:hidden hidden mt-4">
197
+ <div id="mobile-menu" class="md:hidden ec-hidden mt-4">
198
198
  <ul class="flex flex-col space-y-8 my-4 mb-8">
199
199
  <!-- {
200
200
  navItems.map((item) => {
@@ -215,51 +215,65 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
215
215
  <!-- Spacer to prevent content from being hidden under the fixed header -->
216
216
 
217
217
  <script>
218
- const menuToggle = document.getElementById('menu-toggle');
219
- const mobileMenu = document.getElementById('mobile-menu');
220
218
  import { signOut } from 'auth-astro/client';
221
219
 
222
- if (menuToggle && mobileMenu) {
223
- menuToggle.addEventListener('click', () => {
224
- mobileMenu.classList.toggle('hidden');
225
- });
226
- }
220
+ function initializeHeader() {
221
+ const menuToggle = document.getElementById('menu-toggle');
222
+ const mobileMenu = document.getElementById('mobile-menu');
227
223
 
228
- // Profile dropdown functionality
229
- const profileButton = document.getElementById('profile-menu-button');
230
- const profileDropdown = document.getElementById('profile-dropdown');
224
+ if (menuToggle && mobileMenu) {
225
+ menuToggle.addEventListener('click', () => {
226
+ mobileMenu.classList.toggle('ec-hidden');
227
+ });
228
+ }
231
229
 
232
- if (profileButton && profileDropdown) {
233
- profileButton.addEventListener('click', (e) => {
234
- e.stopPropagation();
235
- profileDropdown.classList.toggle('hidden');
236
- profileButton.setAttribute('aria-expanded', !profileDropdown.classList.contains('hidden') ? 'true' : 'false');
237
- });
230
+ // Profile dropdown functionality
231
+ const profileButton = document.getElementById('profile-menu-button');
232
+ const profileDropdown = document.getElementById('profile-dropdown');
238
233
 
239
- // Close dropdown when clicking outside
240
- document.addEventListener('click', (e) => {
241
- if (!profileButton.contains(e.target as Node) && !profileDropdown.contains(e.target as Node)) {
242
- profileDropdown.classList.add('hidden');
243
- profileButton.setAttribute('aria-expanded', 'false');
244
- }
245
- });
234
+ if (profileButton && profileDropdown) {
235
+ profileButton.addEventListener('click', (e) => {
236
+ e.stopPropagation();
237
+ profileDropdown.classList.toggle('ec-hidden');
238
+ profileButton.setAttribute('aria-expanded', !profileDropdown.classList.contains('ec-hidden') ? 'true' : 'false');
239
+ });
246
240
 
247
- // Close dropdown on escape key
248
- document.addEventListener('keydown', (e) => {
249
- if (e.key === 'Escape' && !profileDropdown.classList.contains('hidden')) {
250
- profileDropdown.classList.add('hidden');
251
- profileButton.setAttribute('aria-expanded', 'false');
252
- profileButton.focus();
253
- }
254
- });
241
+ // Close dropdown when clicking outside
242
+ document.addEventListener('click', (e) => {
243
+ if (!profileButton.contains(e.target as Node) && !profileDropdown.contains(e.target as Node)) {
244
+ profileDropdown.classList.add('ec-hidden');
245
+ profileButton.setAttribute('aria-expanded', 'false');
246
+ }
247
+ });
248
+
249
+ // Close dropdown on escape key
250
+ document.addEventListener('keydown', (e) => {
251
+ if (e.key === 'Escape' && !profileDropdown.classList.contains('ec-hidden')) {
252
+ profileDropdown.classList.add('ec-hidden');
253
+ profileButton.setAttribute('aria-expanded', 'false');
254
+ profileButton.focus();
255
+ }
256
+ });
255
257
 
256
- document.getElementById('signout-btn')?.addEventListener('click', async () => {
257
- await signOut();
258
- });
258
+ document.getElementById('signout-btn')?.addEventListener('click', async () => {
259
+ await signOut();
260
+ });
261
+ }
259
262
  }
263
+
264
+ // Initialize on first load
265
+ initializeHeader();
266
+
267
+ // Re-initialize after Astro view transitions (needed because of transition:persist on header)
268
+ document.addEventListener('astro:page-load', initializeHeader);
260
269
  </script>
261
270
 
262
271
  <style>
272
+ /* Custom class for toggling dropdowns/menus */
273
+ .ec-hidden {
274
+ display: none !important;
275
+ }
276
+
263
277
  @media (max-width: 768px) {
264
278
  nav {
265
279
  transition: all 0.3s ease-out;
@@ -271,7 +285,7 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
271
285
  overflow: hidden;
272
286
  }
273
287
 
274
- #mobile-menu:not(.hidden) {
288
+ #mobile-menu:not(.ec-hidden) {
275
289
  max-height: 500px; /* Adjust this value as needed */
276
290
  }
277
291
  }
@@ -1,7 +1,7 @@
1
1
  import { getCollection } from 'astro:content';
2
2
  import type { CollectionEntry } from 'astro:content';
3
3
  import { createVersionedMap } from './util';
4
- import { hydrateProducersAndConsumers } from './messages';
4
+ import { buildProducerConsumerIndex, lookupProducersAndConsumers } from './messages';
5
5
 
6
6
  const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
7
7
 
@@ -35,6 +35,18 @@ export const getCommands = async ({ getAllVersions = true, hydrateServices = tru
35
35
 
36
36
  // 2. Build optimized maps
37
37
  const commandMap = createVersionedMap(allCommands);
38
+ const pcIndex = buildProducerConsumerIndex(allServices, allDataProducts);
39
+
40
+ // Build channel lookup map: channelId → channel entries
41
+ const channelById = new Map<string, typeof allChannels>();
42
+ for (const ch of allChannels) {
43
+ let list = channelById.get(ch.data.id);
44
+ if (!list) {
45
+ list = [];
46
+ channelById.set(ch.data.id, list);
47
+ }
48
+ list.push(ch);
49
+ }
38
50
 
39
51
  // 3. Filter commands
40
52
  const targetCommands = allCommands.filter((command) => {
@@ -51,24 +63,23 @@ export const getCommands = async ({ getAllVersions = true, hydrateServices = tru
51
63
  const latestVersion = commandVersions[0]?.data.version || command.data.version;
52
64
  const versions = commandVersions.map((e) => e.data.version);
53
65
 
54
- // Find producers and consumers (services + data products)
55
- const { producers, consumers } = hydrateProducersAndConsumers({
66
+ // Find producers and consumers via reverse index
67
+ const { producers, consumers } = lookupProducersAndConsumers({
56
68
  message: { data: { ...command.data, latestVersion } },
57
- services: allServices,
58
- dataProducts: allDataProducts,
69
+ index: pcIndex,
59
70
  hydrate: hydrateServices,
60
71
  });
61
72
 
62
- // Find Channels
73
+ // Find Channels via map lookup
63
74
  const messageChannels = command.data.channels || [];
64
- const channelsForCommand = allChannels.filter((c) => messageChannels.some((channel) => c.data.id === channel.id));
75
+ const channelsForCommand = messageChannels.flatMap((channel) => channelById.get(channel.id) || []);
65
76
 
66
77
  return {
67
78
  ...command,
68
79
  data: {
69
80
  ...command.data,
70
81
  messageChannels: channelsForCommand,
71
- producers: producers as any, // Cast for hydration flexibility
82
+ producers: producers as any,
72
83
  consumers: consumers as any,
73
84
  versions,
74
85
  latestVersion,
@@ -1,7 +1,7 @@
1
1
  import { getCollection } from 'astro:content';
2
2
  import type { CollectionEntry } from 'astro:content';
3
3
  import { createVersionedMap } from './util';
4
- import { hydrateProducersAndConsumers } from './messages';
4
+ import { buildProducerConsumerIndex, lookupProducersAndConsumers } from './messages';
5
5
 
6
6
  const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
7
7
 
@@ -35,9 +35,18 @@ export const getEvents = async ({ getAllVersions = true, hydrateServices = true
35
35
 
36
36
  // 2. Build optimized maps
37
37
  const eventMap = createVersionedMap(allEvents);
38
- // We don't map services/channels by ID because we need to iterate them to find relationships (reverse lookup)
39
- // or use them for hydration.
40
- // Actually, for hydration we CAN use a map if we know the IDs, but here we scan services to find producers/consumers.
38
+ const pcIndex = buildProducerConsumerIndex(allServices, allDataProducts);
39
+
40
+ // Build channel lookup map: channelId channel entries
41
+ const channelById = new Map<string, typeof allChannels>();
42
+ for (const ch of allChannels) {
43
+ let list = channelById.get(ch.data.id);
44
+ if (!list) {
45
+ list = [];
46
+ channelById.set(ch.data.id, list);
47
+ }
48
+ list.push(ch);
49
+ }
41
50
 
42
51
  // 3. Filter events
43
52
  const targetEvents = allEvents.filter((event) => {
@@ -54,27 +63,23 @@ export const getEvents = async ({ getAllVersions = true, hydrateServices = true
54
63
  const latestVersion = eventVersions[0]?.data.version || event.data.version;
55
64
  const versions = eventVersions.map((e) => e.data.version);
56
65
 
57
- // Find producers and consumers (services + data products)
58
- const { producers, consumers } = hydrateProducersAndConsumers({
66
+ // Find producers and consumers via reverse index
67
+ const { producers, consumers } = lookupProducersAndConsumers({
59
68
  message: { data: { ...event.data, latestVersion } },
60
- services: allServices,
61
- dataProducts: allDataProducts,
69
+ index: pcIndex,
62
70
  hydrate: hydrateServices,
63
71
  });
64
72
 
65
- // Find Channels
73
+ // Find Channels via map lookup
66
74
  const messageChannels = event.data.channels || [];
67
- // This is O(N*M) where N is event channels and M is all channels.
68
- // Typically M is small, but we could optimize if needed.
69
- // 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.
70
- const channelsForEvent = allChannels.filter((c) => messageChannels.some((channel) => c.data.id === channel.id));
75
+ const channelsForEvent = messageChannels.flatMap((channel) => channelById.get(channel.id) || []);
71
76
 
72
77
  return {
73
78
  ...event,
74
79
  data: {
75
80
  ...event.data,
76
81
  messageChannels: channelsForEvent,
77
- producers: producers as any, // Cast for hydration flexibility
82
+ producers: producers as any,
78
83
  consumers: consumers as any,
79
84
  versions,
80
85
  latestVersion,
@@ -75,6 +75,108 @@ export const hydrateProducersAndConsumers = ({
75
75
  };
76
76
  };
77
77
 
78
+ // --- Reverse Index for O(1) producer/consumer lookups ---
79
+
80
+ interface IndexEntry {
81
+ resource: CollectionEntry<'services'> | CollectionEntry<'data-products'>;
82
+ pointerVersion?: string;
83
+ }
84
+
85
+ export interface ProducerConsumerIndex {
86
+ producers: Map<string, IndexEntry[]>;
87
+ consumers: Map<string, IndexEntry[]>;
88
+ }
89
+
90
+ /**
91
+ * Builds a reverse index from message ID → services/data-products that send/receive it.
92
+ * Call once before the enrichment loop, then use lookupProducersAndConsumers per message.
93
+ */
94
+ export const buildProducerConsumerIndex = (
95
+ services: CollectionEntry<'services'>[],
96
+ dataProducts: CollectionEntry<'data-products'>[]
97
+ ): ProducerConsumerIndex => {
98
+ const producers = new Map<string, IndexEntry[]>();
99
+ const consumers = new Map<string, IndexEntry[]>();
100
+
101
+ const addEntry = (map: Map<string, IndexEntry[]>, messageId: string, entry: IndexEntry) => {
102
+ let list = map.get(messageId);
103
+ if (!list) {
104
+ list = [];
105
+ map.set(messageId, list);
106
+ }
107
+ list.push(entry);
108
+ };
109
+
110
+ for (const service of services || []) {
111
+ if (service.data.sends) {
112
+ for (const p of service.data.sends) {
113
+ addEntry(producers, p.id, { resource: service, pointerVersion: p.version });
114
+ }
115
+ }
116
+ if (service.data.receives) {
117
+ for (const p of service.data.receives) {
118
+ addEntry(consumers, p.id, { resource: service, pointerVersion: p.version });
119
+ }
120
+ }
121
+ }
122
+
123
+ for (const dp of dataProducts || []) {
124
+ if (dp.data.outputs) {
125
+ for (const p of dp.data.outputs) {
126
+ addEntry(producers, p.id, { resource: dp, pointerVersion: p.version });
127
+ }
128
+ }
129
+ if (dp.data.inputs) {
130
+ for (const p of dp.data.inputs) {
131
+ addEntry(consumers, p.id, { resource: dp, pointerVersion: p.version });
132
+ }
133
+ }
134
+ }
135
+
136
+ return { producers, consumers };
137
+ };
138
+
139
+ interface LookupProps {
140
+ message: {
141
+ data: {
142
+ id: string;
143
+ version: string;
144
+ latestVersion?: string;
145
+ };
146
+ };
147
+ index: ProducerConsumerIndex;
148
+ hydrate?: boolean;
149
+ }
150
+
151
+ /**
152
+ * Looks up producers and consumers for a message using the pre-built reverse index.
153
+ * Only runs version matching on the candidate set instead of all services.
154
+ */
155
+ export const lookupProducersAndConsumers = ({ message, index, hydrate = true }: LookupProps) => {
156
+ const { id: messageId, version: messageVersion, latestVersion = messageVersion } = message.data;
157
+
158
+ const matchesVersion = (pointerVersion: string | undefined) => {
159
+ if (pointerVersion === 'latest' || pointerVersion === undefined) {
160
+ return messageVersion === latestVersion;
161
+ }
162
+ return satisfies(messageVersion, pointerVersion);
163
+ };
164
+
165
+ const toResult = <T extends CollectionEntry<'services'> | CollectionEntry<'data-products'>>(resource: T) => {
166
+ if (!hydrate) return { id: resource.data.id, version: resource.data.version };
167
+ return resource;
168
+ };
169
+
170
+ const candidateProducers = index.producers.get(messageId) || [];
171
+ const candidateConsumers = index.consumers.get(messageId) || [];
172
+
173
+ const producers = candidateProducers.filter((e) => matchesVersion(e.pointerVersion)).map((e) => toResult(e.resource));
174
+
175
+ const consumers = candidateConsumers.filter((e) => matchesVersion(e.pointerVersion)).map((e) => toResult(e.resource));
176
+
177
+ return { producers, consumers };
178
+ };
179
+
78
180
  type Messages = {
79
181
  commands: CollectionEntry<'commands'>[];
80
182
  events: CollectionEntry<'events'>[];
@@ -1,7 +1,7 @@
1
1
  import { getCollection } from 'astro:content';
2
2
  import type { CollectionEntry } from 'astro:content';
3
3
  import { createVersionedMap } from './util';
4
- import { hydrateProducersAndConsumers } from './messages';
4
+ import { buildProducerConsumerIndex, lookupProducersAndConsumers } from './messages';
5
5
 
6
6
  const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
7
7
 
@@ -34,6 +34,18 @@ export const getQueries = async ({ getAllVersions = true, hydrateServices = true
34
34
 
35
35
  // 2. Build optimized maps
36
36
  const queryMap = createVersionedMap(allQueries);
37
+ const pcIndex = buildProducerConsumerIndex(allServices, allDataProducts);
38
+
39
+ // Build channel lookup map: channelId → channel entries
40
+ const channelById = new Map<string, typeof allChannels>();
41
+ for (const ch of allChannels) {
42
+ let list = channelById.get(ch.data.id);
43
+ if (!list) {
44
+ list = [];
45
+ channelById.set(ch.data.id, list);
46
+ }
47
+ list.push(ch);
48
+ }
37
49
 
38
50
  // 3. Filter queries
39
51
  const targetQueries = allQueries.filter((query) => {
@@ -50,24 +62,23 @@ export const getQueries = async ({ getAllVersions = true, hydrateServices = true
50
62
  const latestVersion = queryVersions[0]?.data.version || query.data.version;
51
63
  const versions = queryVersions.map((e) => e.data.version);
52
64
 
53
- // Find producers and consumers (services + data products)
54
- const { producers, consumers } = hydrateProducersAndConsumers({
65
+ // Find producers and consumers via reverse index
66
+ const { producers, consumers } = lookupProducersAndConsumers({
55
67
  message: { data: { ...query.data, latestVersion } },
56
- services: allServices,
57
- dataProducts: allDataProducts,
68
+ index: pcIndex,
58
69
  hydrate: hydrateServices,
59
70
  });
60
71
 
61
- // Find Channels
72
+ // Find Channels via map lookup
62
73
  const messageChannels = query.data.channels || [];
63
- const channelsForQuery = allChannels.filter((c) => messageChannels.some((channel) => c.data.id === channel.id));
74
+ const channelsForQuery = messageChannels.flatMap((channel) => channelById.get(channel.id) || []);
64
75
 
65
76
  return {
66
77
  ...query,
67
78
  data: {
68
79
  ...query.data,
69
80
  messageChannels: channelsForQuery,
70
- producers: producers as any, // Cast for hydration flexibility
81
+ producers: producers as any,
71
82
  consumers: consumers as any,
72
83
  versions,
73
84
  latestVersion,
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.13.0-beta.1",
9
+ "version": "3.13.0",
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
@@ -101,9 +101,9 @@
101
101
  "update-notifier": "^7.3.1",
102
102
  "uuid": "^10.0.0",
103
103
  "zod": "^3.25.0",
104
- "@eventcatalog/sdk": "2.13.2",
105
- "@eventcatalog/visualiser": "^3.12.9-beta.1",
106
- "@eventcatalog/linter": "1.0.3"
104
+ "@eventcatalog/linter": "1.0.3",
105
+ "@eventcatalog/visualiser": "^3.13.0",
106
+ "@eventcatalog/sdk": "2.13.2"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@astrojs/check": "^0.9.6",