@eventcatalog/sdk 2.14.3 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3,6 +3,22 @@ import { join as join18 } from "path";
3
3
 
4
4
  // src/dsl/utils.ts
5
5
  import { globSync } from "glob";
6
+ import { satisfies, validRange } from "semver";
7
+ function msgVersionMatches(pointerVersion, messageVersion) {
8
+ if (!pointerVersion) return true;
9
+ if (!messageVersion) return false;
10
+ if (pointerVersion === messageVersion) return true;
11
+ try {
12
+ if (validRange(pointerVersion)) {
13
+ if (satisfies(messageVersion, pointerVersion)) return true;
14
+ }
15
+ if (validRange(messageVersion)) {
16
+ if (satisfies(pointerVersion, messageVersion)) return true;
17
+ }
18
+ } catch {
19
+ }
20
+ return false;
21
+ }
6
22
  function serializeBaseFields(resource, indent = " ") {
7
23
  const lines = [];
8
24
  if (resource.version) {
@@ -91,10 +107,12 @@ ${body}
91
107
  }
92
108
 
93
109
  // src/dsl/service.ts
110
+ import { valid as semverValid } from "semver";
94
111
  async function serviceToDSL(resource, options, getMessageFn) {
95
112
  const { catalogDir, hydrate = false, _seen = /* @__PURE__ */ new Set() } = options;
96
113
  const msgIndex = options._msgIndex || buildMessageTypeIndex(catalogDir);
97
114
  const parts = [];
115
+ const resolvedVersions = /* @__PURE__ */ new Map();
98
116
  if (hydrate && getMessageFn) {
99
117
  const allMessages = [...resource.sends || [], ...resource.receives || []];
100
118
  for (const msg of allMessages) {
@@ -106,18 +124,30 @@ async function serviceToDSL(resource, options, getMessageFn) {
106
124
  const msgResource = await getMessageFn(msg.id, msg.version);
107
125
  if (msgResource) {
108
126
  parts.push(messageToDSL(msgResource, msgType));
127
+ if (msg.version && !semverValid(msg.version) && msgResource.version) {
128
+ resolvedVersions.set(`${msg.id}@${msg.version}`, msgResource.version);
129
+ }
109
130
  }
110
131
  }
111
132
  }
133
+ const resolvePointers = (pointers) => pointers.map((p) => {
134
+ if (p.version && !semverValid(p.version)) {
135
+ const resolved = resolvedVersions.get(`${p.id}@${p.version}`);
136
+ if (resolved) return { ...p, version: resolved };
137
+ }
138
+ return p;
139
+ });
140
+ const sends = resource.sends ? resolvePointers(resource.sends) : void 0;
141
+ const receives = resource.receives ? resolvePointers(resource.receives) : void 0;
112
142
  const lines = [];
113
143
  const baseFields = serializeBaseFields(resource);
114
144
  if (baseFields) lines.push(baseFields);
115
- if (resource.sends && resource.sends.length > 0) {
116
- const sendsStr = serializeMessagePointers(resource.sends, "sends", msgIndex);
145
+ if (sends && sends.length > 0) {
146
+ const sendsStr = serializeMessagePointers(sends, "sends", msgIndex);
117
147
  if (sendsStr) lines.push(sendsStr);
118
148
  }
119
- if (resource.receives && resource.receives.length > 0) {
120
- const recvStr = serializeMessagePointers(resource.receives, "receives", msgIndex);
149
+ if (receives && receives.length > 0) {
150
+ const recvStr = serializeMessagePointers(receives, "receives", msgIndex);
121
151
  if (recvStr) lines.push(recvStr);
122
152
  }
123
153
  if (resource.writesTo && resource.writesTo.length > 0) {
@@ -161,6 +191,13 @@ function channelToDSL(resource) {
161
191
  if (resource.summary) {
162
192
  lines.push(` summary "${resource.summary.trim()}"`);
163
193
  }
194
+ if (resource.routes && resource.routes.length > 0) {
195
+ for (const route of resource.routes) {
196
+ let ref = route.id;
197
+ if (route.version) ref += `@${route.version}`;
198
+ lines.push(` route ${ref}`);
199
+ }
200
+ }
164
201
  if (!lines.length) {
165
202
  return `channel ${resource.id}`;
166
203
  }
@@ -324,6 +361,38 @@ async function domainToDSL(resource, options, resolvers) {
324
361
  return parts.join("\n\n");
325
362
  }
326
363
 
364
+ // src/dsl/container.ts
365
+ function containerToDSL(resource) {
366
+ const lines = [];
367
+ const baseFields = serializeBaseFields(resource);
368
+ if (baseFields) lines.push(baseFields);
369
+ if (resource.container_type) {
370
+ lines.push(` container-type ${resource.container_type}`);
371
+ }
372
+ if (resource.technology) {
373
+ lines.push(` technology "${resource.technology}"`);
374
+ }
375
+ if (resource.authoritative === true) {
376
+ lines.push(` authoritative true`);
377
+ }
378
+ if (resource.access_mode) {
379
+ lines.push(` access-mode ${resource.access_mode}`);
380
+ }
381
+ if (resource.classification) {
382
+ lines.push(` classification ${resource.classification}`);
383
+ }
384
+ if (resource.residency) {
385
+ lines.push(` residency "${resource.residency}"`);
386
+ }
387
+ if (resource.retention) {
388
+ lines.push(` retention "${resource.retention}"`);
389
+ }
390
+ const body = lines.join("\n");
391
+ return `container ${resource.id} {
392
+ ${body}
393
+ }`;
394
+ }
395
+
327
396
  // src/dsl/index.ts
328
397
  function getMessage(resolvers, msgIndex) {
329
398
  return async (id, version) => {
@@ -339,22 +408,55 @@ function getMessage(resolvers, msgIndex) {
339
408
  }
340
409
  };
341
410
  }
411
+ async function hydrateChannel(channelId, channelVersion, resolvers, seen, parts) {
412
+ const key = `channel:${channelId}@${channelVersion || "latest"}`;
413
+ if (seen.has(key)) return;
414
+ seen.add(key);
415
+ const channel = await resolvers.getChannel(channelId, channelVersion);
416
+ if (!channel) return;
417
+ if (channel.routes && channel.routes.length > 0) {
418
+ for (const route of channel.routes) {
419
+ await hydrateChannel(route.id, route.version, resolvers, seen, parts);
420
+ }
421
+ }
422
+ const allChannels = await resolvers.getChannels({ latestOnly: false }) || [];
423
+ const targetVersion = channelVersion || channel.version;
424
+ for (const upstream of allChannels) {
425
+ if (!upstream.routes) continue;
426
+ const routesToThis = upstream.routes.some((route) => {
427
+ if (route.id !== channelId) return false;
428
+ if (!route.version) {
429
+ return !channelVersion;
430
+ }
431
+ return msgVersionMatches(route.version, targetVersion);
432
+ });
433
+ if (routesToThis) {
434
+ await hydrateChannel(upstream.id, upstream.version, resolvers, seen, parts);
435
+ }
436
+ }
437
+ parts.push(channelToDSL(channel));
438
+ }
342
439
  async function hydrateChannels(resource, resolvers, seen, parts) {
343
440
  const allMessages = [...resource.sends || [], ...resource.receives || []];
344
441
  for (const msg of allMessages) {
345
442
  const channels = "to" in msg ? msg.to : "from" in msg ? msg.from : void 0;
346
443
  if (!channels) continue;
347
444
  for (const ch of channels) {
348
- const key = `channel:${ch.id}@${ch.version || "latest"}`;
349
- if (seen.has(key)) continue;
350
- seen.add(key);
351
- const channel = await resolvers.getChannel(ch.id, ch.version);
352
- if (channel) {
353
- parts.push(channelToDSL(channel));
354
- }
445
+ await hydrateChannel(ch.id, ch.version, resolvers, seen, parts);
355
446
  }
356
447
  }
357
448
  }
449
+ async function hydrateContainers(resource, resolvers, seen, parts) {
450
+ const allContainers = [...resource.writesTo || [], ...resource.readsFrom || []];
451
+ for (const ref of allContainers) {
452
+ const key = `container:${ref.id}@${ref.version || "latest"}`;
453
+ if (seen.has(key)) continue;
454
+ seen.add(key);
455
+ const container = await resolvers.getContainer(ref.id, ref.version);
456
+ if (!container) continue;
457
+ parts.push(containerToDSL(container));
458
+ }
459
+ }
358
460
  async function hydrateOwners2(owners, resolvers, seen, parts) {
359
461
  if (!owners) return;
360
462
  for (const ownerId of owners) {
@@ -372,6 +474,67 @@ async function hydrateOwners2(owners, resolvers, seen, parts) {
372
474
  }
373
475
  }
374
476
  }
477
+ async function hydrateMessageServices(messageId, messageVersion, resolvers, seen, parts, catalogDir, msgIndex) {
478
+ const services = await resolvers.getServices({ latestOnly: false }) || [];
479
+ for (const service of services) {
480
+ const key = `service:${service.id}@${service.version || "latest"}`;
481
+ if (seen.has(key)) continue;
482
+ const referencesMessage = [...service.sends || [], ...service.receives || []].some(
483
+ (msg) => msg.id === messageId && msgVersionMatches(msg.version, messageVersion)
484
+ );
485
+ if (referencesMessage) {
486
+ seen.add(key);
487
+ const matchMsg = (msg) => msg.id === messageId && msgVersionMatches(msg.version, messageVersion);
488
+ const resolvePointerVersion = (msg) => {
489
+ if (msg.id === messageId && msg.version && msg.version !== messageVersion && messageVersion) {
490
+ return { ...msg, version: messageVersion };
491
+ }
492
+ return msg;
493
+ };
494
+ const filtered = {
495
+ ...service,
496
+ sends: service.sends?.filter(matchMsg).map(resolvePointerVersion),
497
+ receives: service.receives?.filter(matchMsg).map(resolvePointerVersion)
498
+ };
499
+ await hydrateChannels(filtered, resolvers, seen, parts);
500
+ parts.push(await serviceToDSL(filtered, { catalogDir, hydrate: false, _seen: new Set(seen), _msgIndex: msgIndex }));
501
+ }
502
+ }
503
+ }
504
+ async function hydrateRelatedServices(messages, direction, resolvers, seen, parts, catalogDir, msgIndex) {
505
+ if (!messages.length) return;
506
+ const referencesHydratedMessage = (msg) => messages.some((input) => msg.id === input.id && msgVersionMatches(msg.version, input.version));
507
+ const services = await resolvers.getServices({ latestOnly: false }) || [];
508
+ for (const service of services) {
509
+ const key = `service:${service.id}@${service.version || "latest"}`;
510
+ if (seen.has(key)) continue;
511
+ if (direction === "sends") {
512
+ const matchedPointers = (service.sends || []).filter(referencesHydratedMessage);
513
+ if (matchedPointers.length > 0) {
514
+ seen.add(key);
515
+ const filtered = {
516
+ ...service,
517
+ sends: matchedPointers,
518
+ receives: void 0
519
+ };
520
+ await hydrateChannels(filtered, resolvers, seen, parts);
521
+ parts.push(await serviceToDSL(filtered, { catalogDir, hydrate: false, _seen: new Set(seen), _msgIndex: msgIndex }));
522
+ }
523
+ } else {
524
+ const matchedPointers = (service.receives || []).filter(referencesHydratedMessage);
525
+ if (matchedPointers.length > 0) {
526
+ seen.add(key);
527
+ const filtered = {
528
+ ...service,
529
+ sends: void 0,
530
+ receives: matchedPointers
531
+ };
532
+ await hydrateChannels(filtered, resolvers, seen, parts);
533
+ parts.push(await serviceToDSL(filtered, { catalogDir, hydrate: false, _seen: new Set(seen), _msgIndex: msgIndex }));
534
+ }
535
+ }
536
+ }
537
+ }
375
538
  var toDSL = (catalogDir, resolvers) => async (resource, options) => {
376
539
  const resources = Array.isArray(resource) ? resource : [resource];
377
540
  const seen = /* @__PURE__ */ new Set();
@@ -387,6 +550,7 @@ var toDSL = (catalogDir, resolvers) => async (resource, options) => {
387
550
  case "query":
388
551
  if (options.hydrate) {
389
552
  await hydrateOwners2(res.owners, resolvers, seen, parts);
553
+ await hydrateMessageServices(res.id, res.version, resolvers, seen, parts, catalogDir, msgIndex);
390
554
  }
391
555
  parts.push(messageToDSL(res, options.type));
392
556
  break;
@@ -394,6 +558,7 @@ var toDSL = (catalogDir, resolvers) => async (resource, options) => {
394
558
  if (options.hydrate) {
395
559
  await hydrateOwners2(res.owners, resolvers, seen, parts);
396
560
  await hydrateChannels(res, resolvers, seen, parts);
561
+ await hydrateContainers(res, resolvers, seen, parts);
397
562
  }
398
563
  parts.push(
399
564
  await serviceToDSL(
@@ -402,6 +567,11 @@ var toDSL = (catalogDir, resolvers) => async (resource, options) => {
402
567
  getMessage(resolvers, msgIndex)
403
568
  )
404
569
  );
570
+ if (options.hydrate) {
571
+ const svc = res;
572
+ await hydrateRelatedServices(svc.sends || [], "receives", resolvers, seen, parts, catalogDir, msgIndex);
573
+ await hydrateRelatedServices(svc.receives || [], "sends", resolvers, seen, parts, catalogDir, msgIndex);
574
+ }
405
575
  break;
406
576
  case "domain":
407
577
  if (options.hydrate) {
@@ -421,6 +591,22 @@ var toDSL = (catalogDir, resolvers) => async (resource, options) => {
421
591
  }
422
592
  )
423
593
  );
594
+ if (options.hydrate) {
595
+ const domain = res;
596
+ const allSends = [];
597
+ const allReceives = [];
598
+ if (domain.services?.length) {
599
+ for (const svcRef of domain.services) {
600
+ const svc = await resolvers.getService(svcRef.id, svcRef.version);
601
+ if (svc) {
602
+ allSends.push(...svc.sends || []);
603
+ allReceives.push(...svc.receives || []);
604
+ }
605
+ }
606
+ }
607
+ await hydrateRelatedServices(allSends, "receives", resolvers, seen, parts, catalogDir, msgIndex);
608
+ await hydrateRelatedServices(allReceives, "sends", resolvers, seen, parts, catalogDir, msgIndex);
609
+ }
424
610
  break;
425
611
  }
426
612
  }
@@ -437,7 +623,7 @@ import fsSync from "fs";
437
623
  import { copy } from "fs-extra";
438
624
  import { join, dirname, normalize, sep as pathSeparator, resolve, relative } from "path";
439
625
  import matter from "gray-matter";
440
- import { satisfies, validRange } from "semver";
626
+ import { satisfies as satisfies2, validRange as validRange2 } from "semver";
441
627
  var _fileIndexCache = null;
442
628
  var _fileIndexCatalogDir = null;
443
629
  var _matterCache = null;
@@ -569,11 +755,11 @@ var findFileById = async (catalogDir, id, version) => {
569
755
  }
570
756
  const exactMatch = entries.find((e) => e.version === version);
571
757
  if (exactMatch) return exactMatch.path;
572
- const semverRange = validRange(version);
758
+ const semverRange = validRange2(version);
573
759
  if (semverRange) {
574
760
  const match = entries.find((e) => {
575
761
  try {
576
- return satisfies(e.version, semverRange);
762
+ return satisfies2(e.version, semverRange);
577
763
  } catch {
578
764
  return false;
579
765
  }
@@ -659,7 +845,7 @@ import { dirname as dirname2, join as join2 } from "path";
659
845
  import matter2 from "gray-matter";
660
846
  import fs from "fs/promises";
661
847
  import fsSync2 from "fs";
662
- import { satisfies as satisfies2 } from "semver";
848
+ import { satisfies as satisfies3 } from "semver";
663
849
  import { lock, unlock } from "proper-lockfile";
664
850
  import { basename as basename2 } from "path";
665
851
  import path from "path";
@@ -725,7 +911,7 @@ var writeResource = async (catalogDir, resource, options = {
725
911
  if (options.versionExistingContent && !exists) {
726
912
  const currentResource = await getResource(catalogDir, resource.id);
727
913
  if (currentResource) {
728
- if (satisfies2(resource.version, `>${currentResource.version}`)) {
914
+ if (satisfies3(resource.version, `>${currentResource.version}`)) {
729
915
  await versionResource(catalogDir, resource.id);
730
916
  } else {
731
917
  throw new Error(`New version ${resource.version} is not greater than current version ${currentResource.version}`);
@@ -1399,7 +1585,7 @@ var addMessageToChannel = (directory, collection) => async (id, _message, versio
1399
1585
  // src/messages.ts
1400
1586
  import { dirname as dirname5 } from "path";
1401
1587
  import matter4 from "gray-matter";
1402
- import { satisfies as satisfies3, validRange as validRange2 } from "semver";
1588
+ import { satisfies as satisfies4, validRange as validRange3 } from "semver";
1403
1589
  var getMessageBySchemaPath = (directory) => async (path6, options) => {
1404
1590
  const pathToMessage = dirname5(path6);
1405
1591
  try {
@@ -1438,9 +1624,9 @@ var getProducersAndConsumersForMessage = (directory) => async (id, version, opti
1438
1624
  for (const service of services) {
1439
1625
  const servicePublishesMessage = service.sends?.some((_message) => {
1440
1626
  if (_message.version) {
1441
- const isServiceUsingSemverRange = validRange2(_message.version);
1627
+ const isServiceUsingSemverRange = validRange3(_message.version);
1442
1628
  if (isServiceUsingSemverRange) {
1443
- return _message.id === message.id && satisfies3(message.version, _message.version);
1629
+ return _message.id === message.id && satisfies4(message.version, _message.version);
1444
1630
  } else {
1445
1631
  return _message.id === message.id && message.version === _message.version;
1446
1632
  }
@@ -1452,9 +1638,9 @@ var getProducersAndConsumersForMessage = (directory) => async (id, version, opti
1452
1638
  });
1453
1639
  const serviceSubscribesToMessage = service.receives?.some((_message) => {
1454
1640
  if (_message.version) {
1455
- const isServiceUsingSemverRange = validRange2(_message.version);
1641
+ const isServiceUsingSemverRange = validRange3(_message.version);
1456
1642
  if (isServiceUsingSemverRange) {
1457
- return _message.id === message.id && satisfies3(message.version, _message.version);
1643
+ return _message.id === message.id && satisfies4(message.version, _message.version);
1458
1644
  } else {
1459
1645
  return _message.id === message.id && message.version === _message.version;
1460
1646
  }
@@ -2982,8 +3168,11 @@ var src_default = (path6) => {
2982
3168
  getCommand: getCommand(join18(path6)),
2983
3169
  getQuery: getQuery(join18(path6)),
2984
3170
  getService: getService(join18(path6)),
3171
+ getServices: getServices(join18(path6)),
2985
3172
  getDomain: getDomain(join18(path6, "domains")),
2986
3173
  getChannel: getChannel(join18(path6)),
3174
+ getChannels: getChannels(join18(path6)),
3175
+ getContainer: getDataStore(join18(path6)),
2987
3176
  getTeam: getTeam(join18(path6, "teams")),
2988
3177
  getUser: getUser(join18(path6, "users"))
2989
3178
  })