@eventcatalog/core 3.15.6 → 3.16.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.15.6";
40
+ var version = "3.16.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-R3VWE46X.js";
4
- import "../chunk-EDUMKUXT.js";
3
+ } from "../chunk-VRSJESSG.js";
4
+ import "../chunk-J7UJSNZY.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -111,7 +111,7 @@ var import_axios = __toESM(require("axios"), 1);
111
111
  var import_os = __toESM(require("os"), 1);
112
112
 
113
113
  // package.json
114
- var version = "3.15.6";
114
+ var version = "3.16.0";
115
115
 
116
116
  // src/constants.ts
117
117
  var VERSION = version;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-KAXHYQAC.js";
4
- import "../chunk-R3VWE46X.js";
3
+ } from "../chunk-XIZ63AL2.js";
4
+ import "../chunk-VRSJESSG.js";
5
5
  import "../chunk-4UVFXLPI.js";
6
- import "../chunk-EDUMKUXT.js";
6
+ import "../chunk-J7UJSNZY.js";
7
7
  import "../chunk-5T63CXKU.js";
8
8
  export {
9
9
  log_build_default as default
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "3.15.6";
2
+ var version = "3.16.0";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-OUV7ZAEA.js";
3
+ } from "./chunk-VNI36JCS.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-EDUMKUXT.js";
3
+ } from "./chunk-J7UJSNZY.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
  VERSION
3
- } from "./chunk-EDUMKUXT.js";
3
+ } from "./chunk-J7UJSNZY.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-R3VWE46X.js";
3
+ } from "./chunk-VRSJESSG.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.15.6";
28
+ var version = "3.16.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-EDUMKUXT.js";
3
+ } from "./chunk-J7UJSNZY.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -114,7 +114,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
114
114
  var import_picocolors = __toESM(require("picocolors"), 1);
115
115
 
116
116
  // package.json
117
- var version = "3.15.6";
117
+ var version = "3.16.0";
118
118
 
119
119
  // src/constants.ts
120
120
  var VERSION = version;
@@ -1,18 +1,18 @@
1
+ import {
2
+ log_build_default
3
+ } from "./chunk-XIZ63AL2.js";
1
4
  import {
2
5
  resolve_catalog_dependencies_default
3
6
  } from "./chunk-WAJIJEI3.js";
4
7
  import {
5
8
  watch
6
9
  } from "./chunk-PLNJC7NZ.js";
7
- import {
8
- log_build_default
9
- } from "./chunk-KAXHYQAC.js";
10
- import "./chunk-R3VWE46X.js";
11
- import "./chunk-4UVFXLPI.js";
12
10
  import {
13
11
  runMigrations
14
12
  } from "./chunk-BH3JMNAV.js";
15
13
  import "./chunk-622JYJWG.js";
14
+ import "./chunk-VRSJESSG.js";
15
+ import "./chunk-4UVFXLPI.js";
16
16
  import {
17
17
  catalogToAstro
18
18
  } from "./chunk-YDXB3BD2.js";
@@ -22,13 +22,13 @@ import {
22
22
  } from "./chunk-3KXCGYET.js";
23
23
  import {
24
24
  generate
25
- } from "./chunk-45P7X2RA.js";
25
+ } from "./chunk-VGFOJWSL.js";
26
26
  import {
27
27
  logger
28
- } from "./chunk-OUV7ZAEA.js";
28
+ } from "./chunk-VNI36JCS.js";
29
29
  import {
30
30
  VERSION
31
- } from "./chunk-EDUMKUXT.js";
31
+ } from "./chunk-J7UJSNZY.js";
32
32
  import {
33
33
  getEventCatalogConfigFile,
34
34
  verifyRequiredFieldsAreInCatalogConfigFile
package/dist/generate.cjs CHANGED
@@ -78,7 +78,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
78
78
  var import_picocolors = __toESM(require("picocolors"), 1);
79
79
 
80
80
  // package.json
81
- var version = "3.15.6";
81
+ var version = "3.16.0";
82
82
 
83
83
  // src/constants.ts
84
84
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-45P7X2RA.js";
4
- import "./chunk-OUV7ZAEA.js";
5
- import "./chunk-EDUMKUXT.js";
3
+ } from "./chunk-VGFOJWSL.js";
4
+ import "./chunk-VNI36JCS.js";
5
+ import "./chunk-J7UJSNZY.js";
6
6
  import "./chunk-5T63CXKU.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.15.6";
39
+ var version = "3.16.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-OUV7ZAEA.js";
4
- import "../chunk-EDUMKUXT.js";
3
+ } from "../chunk-VNI36JCS.js";
4
+ import "../chunk-J7UJSNZY.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -3,7 +3,7 @@ import type { CollectionEntry } from 'astro:content';
3
3
  import semver from 'semver';
4
4
  import type { CollectionMessageTypes, CollectionTypes } from '@types';
5
5
  import { getDomains, getDomainsForService } from './domains';
6
- import { createVersionedMap, findInMap, processSpecifications } from '@utils/collections/util';
6
+ import { createVersionedMap, findInMap, versionMatches, processSpecifications } from '@utils/collections/util';
7
7
 
8
8
  export type Service = CollectionEntry<'services'>;
9
9
 
@@ -130,8 +130,8 @@ export const getProducersOfMessage = (services: Service[], message: CollectionEn
130
130
  // If version is 'latest', match any version
131
131
  if (send.version === 'latest') return idMatch;
132
132
 
133
- // Use semver to compare versions
134
- return idMatch && semver.satisfies(message.data.version, send.version);
133
+ // Use versionMatches to support semver ranges and x-patterns
134
+ return idMatch && versionMatches(message.data.version, send.version);
135
135
  });
136
136
  });
137
137
  };
@@ -141,14 +141,14 @@ export const getConsumersOfMessage = (services: Service[], message: CollectionEn
141
141
  return service.data.receives?.some((receive) => {
142
142
  const idMatch = receive.id === message.data.id;
143
143
 
144
- // If no version specified in send, treat as 'latest'
144
+ // If no version specified in receive, treat as 'latest'
145
145
  if (!receive.version) return idMatch;
146
146
 
147
147
  // If version is 'latest', match any version
148
148
  if (receive.version === 'latest') return idMatch;
149
149
 
150
- // Use semver to compare versions
151
- return idMatch && semver.satisfies(message.data.version, receive.version);
150
+ // Use versionMatches to support semver ranges and x-patterns
151
+ return idMatch && versionMatches(message.data.version, receive.version);
152
152
  });
153
153
  });
154
154
  };
@@ -298,3 +298,41 @@ export const findInMap = <T extends { data: { version?: string } }>(
298
298
 
299
299
  return undefined;
300
300
  };
301
+
302
+ /**
303
+ * Matches a specific version against a version range pattern.
304
+ * Supports exact versions, semver ranges, x-patterns, and 'latest'.
305
+ *
306
+ * @param version - The specific version to check (e.g., "1.2.3")
307
+ * @param rangePattern - The pattern to match against (e.g., "^1.0.0", "1.x", "latest")
308
+ * @returns true if version matches the rangePattern
309
+ */
310
+ export const versionMatches = (version: string, rangePattern: string): boolean => {
311
+ // Handle 'latest' keyword
312
+ if (rangePattern === 'latest') return true;
313
+
314
+ // Try exact match first
315
+ if (version === rangePattern) return true;
316
+
317
+ // Try semver range matching
318
+ try {
319
+ if (semver.validRange(rangePattern)) {
320
+ return semver.satisfies(version, rangePattern);
321
+ }
322
+ } catch (error) {
323
+ // Invalid semver, fall through
324
+ }
325
+
326
+ // Handle x-patterns like 1.x, 1.2.x
327
+ if (rangePattern.includes('.x')) {
328
+ const prefix = rangePattern.replace(/\.x/g, '');
329
+ // Check if version starts with the prefix and has a valid boundary
330
+ // (next character must be '.' or end of string)
331
+ if (version.startsWith(prefix)) {
332
+ const nextChar = version[prefix.length];
333
+ return nextChar === '.' || nextChar === undefined;
334
+ }
335
+ }
336
+
337
+ return false;
338
+ };
@@ -11,6 +11,7 @@ import {
11
11
  getColorFromString,
12
12
  getEdgeLabelForMessageAsSource,
13
13
  getEdgeLabelForServiceAsTarget,
14
+ versionMatches,
14
15
  } from './utils/utils';
15
16
  import { MarkerType, type Node, type Edge } from '@xyflow/react';
16
17
  import {
@@ -150,7 +151,9 @@ const getNodesAndEdges = async ({
150
151
  const serviceProducer = producer as CollectionEntry<'services'>;
151
152
 
152
153
  // Is the producer sending this message to a channel?
153
- const producerConfigurationForMessage = serviceProducer.data.sends?.find((send) => send.id === message.data.id);
154
+ const producerConfigurationForMessage = serviceProducer.data.sends?.find(
155
+ (send) => send.id === message.data.id && versionMatches(send.version, message.data.version)
156
+ );
154
157
  const producerChannelConfiguration = producerConfigurationForMessage?.to ?? [];
155
158
 
156
159
  const producerHasChannels = producerChannelConfiguration?.length > 0;
@@ -286,7 +289,9 @@ const getNodesAndEdges = async ({
286
289
  const serviceConsumer = consumer as CollectionEntry<'services'>;
287
290
 
288
291
  // Is the consumer receiving this message from a channel?
289
- const consumerConfigurationForMessage = serviceConsumer.data.receives?.find((receive) => receive.id === message.data.id);
292
+ const consumerConfigurationForMessage = serviceConsumer.data.receives?.find(
293
+ (receive) => receive.id === message.data.id && versionMatches(receive.version, message.data.version)
294
+ );
290
295
  const consumerChannelConfiguration = consumerConfigurationForMessage?.from ?? [];
291
296
 
292
297
  const consumerHasChannels = consumerChannelConfiguration.length > 0;
@@ -330,9 +335,17 @@ const getNodesAndEdges = async ({
330
335
  // Can any of the consumer channels be linked to any of the producer channels?
331
336
  // Only consider service producers for channel linking (data products don't have sends/receives)
332
337
  const producerChannels = serviceProducers
333
- .map((producer) => producer.data.sends?.find((send) => send.id === message.data.id)?.to ?? [])
338
+ .map((producer) => {
339
+ const config = producer.data.sends?.find(
340
+ (send) => send.id === message.data.id && versionMatches(send.version, message.data.version)
341
+ );
342
+ return config?.to ?? [];
343
+ })
334
344
  .flat();
335
- const consumerChannels = serviceConsumer.data.receives?.find((receive) => receive.id === message.data.id)?.from ?? [];
345
+ const consumerChannels =
346
+ serviceConsumer.data.receives?.find(
347
+ (receive) => receive.id === message.data.id && versionMatches(receive.version, message.data.version)
348
+ )?.from ?? [];
336
349
 
337
350
  for (const producerChannel of producerChannels) {
338
351
  const producerChannelValue = findInMap(
@@ -565,7 +578,9 @@ export const getNodesAndEdgesForConsumedMessage = ({
565
578
  })
566
579
  );
567
580
 
568
- const targetMessageConfiguration = target.data.receives?.find((receive) => receive.id === message.data.id);
581
+ const targetMessageConfiguration = target.data.receives?.find(
582
+ (receive) => receive.id === message.data.id && versionMatches(receive.version, message.data.version)
583
+ );
569
584
  const channelsFromMessageToTarget = targetMessageConfiguration?.from ?? [];
570
585
  const hydratedChannelsFromMessageToTarget = channelsFromMessageToTarget
571
586
  .map((channel) => findInMap(map, channel.id, channel.version))
@@ -690,7 +705,9 @@ export const getNodesAndEdgesForConsumedMessage = ({
690
705
  );
691
706
 
692
707
  // Check if the producer is sending the message to a channel
693
- const producerConfigurationForMessage = producer.data.sends?.find((send) => send.id === message.data.id);
708
+ const producerConfigurationForMessage = producer.data.sends?.find(
709
+ (send) => send.id === message.data.id && versionMatches(send.version, message.data.version)
710
+ );
694
711
  const producerChannelConfiguration = producerConfigurationForMessage?.to ?? [];
695
712
 
696
713
  const producerHasChannels = producerChannelConfiguration.length > 0;
@@ -919,7 +936,9 @@ export const getNodesAndEdgesForProducedMessage = ({
919
936
  })
920
937
  );
921
938
 
922
- const sourceMessageConfiguration = source.data.sends?.find((send) => send.id === message.data.id);
939
+ const sourceMessageConfiguration = source.data.sends?.find(
940
+ (send) => send.id === message.data.id && versionMatches(send.version, message.data.version)
941
+ );
923
942
  const channelsFromSourceToMessage = sourceMessageConfiguration?.to ?? [];
924
943
 
925
944
  const hydratedChannelsFromSourceToMessage = channelsFromSourceToMessage
@@ -1010,7 +1029,9 @@ export const getNodesAndEdgesForProducedMessage = ({
1010
1029
  );
1011
1030
 
1012
1031
  // Check if the consumer is consuming the message from a channel
1013
- const consumerConfigurationForMessage = consumer.data.receives?.find((receive) => receive.id === message.data.id);
1032
+ const consumerConfigurationForMessage = consumer.data.receives?.find(
1033
+ (receive) => receive.id === message.data.id && versionMatches(receive.version, message.data.version)
1034
+ );
1014
1035
  const consumerChannelConfiguration = consumerConfigurationForMessage?.from ?? [];
1015
1036
 
1016
1037
  const consumerHasChannels = consumerChannelConfiguration.length > 0;
@@ -8,6 +8,7 @@ import {
8
8
  createEdge,
9
9
  buildContextMenuForService,
10
10
  buildContextMenuForResource,
11
+ versionMatches,
11
12
  } from '@utils/node-graphs/utils/utils';
12
13
 
13
14
  import { findMatchingNodes, findInMap, createVersionedMap } from '@utils/collections/util';
@@ -124,7 +125,9 @@ export const getNodesAndEdges = async ({
124
125
  if (renderMessages) {
125
126
  // All the messages the service receives
126
127
  receives.forEach((receive) => {
127
- const targetChannels = receivesRaw.find((receiveRaw) => receiveRaw.id === receive.data.id)?.from;
128
+ const targetChannels = receivesRaw.find(
129
+ (receiveRaw) => receiveRaw.id === receive.data.id && versionMatches(receiveRaw.version, receive.data.version)
130
+ )?.from;
128
131
 
129
132
  const { nodes: consumedMessageNodes, edges: consumedMessageEdges } = getNodesAndEdgesForConsumedMessage({
130
133
  message: receive,
@@ -235,7 +238,9 @@ export const getNodesAndEdges = async ({
235
238
 
236
239
  if (renderMessages) {
237
240
  sends.forEach((send) => {
238
- const sourceChannels = sendsRaw.find((sendRaw) => sendRaw.id === send.data.id)?.to;
241
+ const sourceChannels = sendsRaw.find(
242
+ (sendRaw) => sendRaw.id === send.data.id && versionMatches(sendRaw.version, send.data.version)
243
+ )?.to;
239
244
 
240
245
  const { nodes: producedMessageNodes, edges: producedMessageEdges } = getNodesAndEdgesForProducedMessage({
241
246
  message: send,
@@ -2,8 +2,9 @@
2
2
 
3
3
  import { MarkerType, Position, type Edge, type Node } from '@xyflow/react';
4
4
  import dagre from 'dagre';
5
- import { getItemsFromCollectionByIdAndSemverOrLatest } from '@utils/collections/util';
5
+ import { getItemsFromCollectionByIdAndSemverOrLatest, versionMatches as versionMatchesUtil } from '@utils/collections/util';
6
6
  import { buildUrl } from '@utils/url-builder';
7
+
7
8
  interface BaseCollectionData {
8
9
  id: string;
9
10
  version: string;
@@ -18,6 +19,23 @@ interface MessageCollectionItem extends CollectionItem {
18
19
  collection: 'commands' | 'events' | 'queries';
19
20
  }
20
21
 
22
+ /**
23
+ * Determines if a service's accepted version pattern matches an actual message version.
24
+ *
25
+ * @param acceptedVersion - The version pattern a service declares (in sends/receives config)
26
+ * @param actualMessageVersion - The specific version of the actual catalogued message
27
+ * @returns true if the actual message version satisfies the accepted version pattern
28
+ */
29
+ export const versionMatches = (acceptedVersion: string | undefined, actualMessageVersion: string | undefined): boolean => {
30
+ if (!acceptedVersion || acceptedVersion === 'latest') return true;
31
+
32
+ if (!actualMessageVersion || actualMessageVersion === 'latest') {
33
+ return !acceptedVersion || acceptedVersion === 'latest';
34
+ }
35
+
36
+ return versionMatchesUtil(actualMessageVersion, acceptedVersion);
37
+ };
38
+
21
39
  export const generateIdForNode = (node: CollectionItem) => {
22
40
  return `${node.data.id}-${node.data.version}`;
23
41
  };
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.15.6",
9
+ "version": "3.16.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/visualiser": "^3.14.0",
105
104
  "@eventcatalog/sdk": "2.14.3",
106
- "@eventcatalog/linter": "1.0.7"
105
+ "@eventcatalog/linter": "1.0.7",
106
+ "@eventcatalog/visualiser": "^3.14.0"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@astrojs/check": "^0.9.6",