@eventcatalog/core 4.10.14 → 4.11.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 (136) 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-ONDFEA5R.js → chunk-DWC5GRFX.js} +1 -1
  6. package/dist/{chunk-LITOQH56.js → chunk-H3324DNT.js} +1 -1
  7. package/dist/{chunk-V2SKOQYF.js → chunk-SW7SJZIX.js} +1 -1
  8. package/dist/{chunk-HERAHLM2.js → chunk-W4LDIMUI.js} +1 -1
  9. package/dist/{chunk-LUW6RDA7.js → chunk-XJOKK5ZO.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/docs/api/02-config.md +6 -6
  13. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/02-configuration.md +18 -11
  14. package/dist/docs/development/components/components/13-mermaid-file-loader.md +12 -0
  15. package/dist/docs/development/components/diagram-syntax/06-mermaid.md +45 -6
  16. package/dist/docs/development/customization/05-resource-sidebar.md +1 -1
  17. package/dist/eventcatalog.cjs +1 -1
  18. package/dist/eventcatalog.js +5 -5
  19. package/dist/generate.cjs +1 -1
  20. package/dist/generate.js +3 -3
  21. package/dist/utils/cli-logger.cjs +1 -1
  22. package/dist/utils/cli-logger.js +2 -2
  23. package/eventcatalog/astro.config.mjs +2 -1
  24. package/eventcatalog/public/icons/languages/android.svg +1 -0
  25. package/eventcatalog/public/icons/languages/angular.svg +1 -0
  26. package/eventcatalog/public/icons/languages/apple.svg +1 -0
  27. package/eventcatalog/public/icons/languages/arduino.svg +1 -0
  28. package/eventcatalog/public/icons/languages/bash.svg +1 -0
  29. package/eventcatalog/public/icons/languages/bun.svg +1 -0
  30. package/eventcatalog/public/icons/languages/c.svg +1 -0
  31. package/eventcatalog/public/icons/languages/clojure.svg +1 -0
  32. package/eventcatalog/public/icons/languages/cpp.svg +1 -0
  33. package/eventcatalog/public/icons/languages/crystal.svg +1 -0
  34. package/eventcatalog/public/icons/languages/csharp.svg +1 -0
  35. package/eventcatalog/public/icons/languages/css.svg +1 -0
  36. package/eventcatalog/public/icons/languages/curl.svg +1 -0
  37. package/eventcatalog/public/icons/languages/dart.svg +1 -0
  38. package/eventcatalog/public/icons/languages/deno.svg +1 -0
  39. package/eventcatalog/public/icons/languages/docker.svg +1 -0
  40. package/eventcatalog/public/icons/languages/elm.svg +1 -0
  41. package/eventcatalog/public/icons/languages/erlang.svg +1 -0
  42. package/eventcatalog/public/icons/languages/flutter.svg +1 -0
  43. package/eventcatalog/public/icons/languages/fortran.svg +1 -0
  44. package/eventcatalog/public/icons/languages/fsharp.svg +1 -0
  45. package/eventcatalog/public/icons/languages/git.svg +1 -0
  46. package/eventcatalog/public/icons/languages/gradle.svg +1 -0
  47. package/eventcatalog/public/icons/languages/graphql.svg +1 -0
  48. package/eventcatalog/public/icons/languages/grpc.svg +1 -0
  49. package/eventcatalog/public/icons/languages/haskell.svg +1 -0
  50. package/eventcatalog/public/icons/languages/hasura.svg +1 -0
  51. package/eventcatalog/public/icons/languages/html.svg +1 -0
  52. package/eventcatalog/public/icons/languages/httpie.svg +1 -0
  53. package/eventcatalog/public/icons/languages/javascript.svg +1 -0
  54. package/eventcatalog/public/icons/languages/json-schema.svg +1 -0
  55. package/eventcatalog/public/icons/languages/json.svg +1 -0
  56. package/eventcatalog/public/icons/languages/julia.svg +1 -0
  57. package/eventcatalog/public/icons/languages/jupyter.svg +1 -0
  58. package/eventcatalog/public/icons/languages/kafka.svg +1 -0
  59. package/eventcatalog/public/icons/languages/kotlin.svg +1 -0
  60. package/eventcatalog/public/icons/languages/lua.svg +1 -0
  61. package/eventcatalog/public/icons/languages/markdown.svg +1 -0
  62. package/eventcatalog/public/icons/languages/maven.svg +1 -0
  63. package/eventcatalog/public/icons/languages/mongodb.svg +1 -0
  64. package/eventcatalog/public/icons/languages/mysql.svg +1 -0
  65. package/eventcatalog/public/icons/languages/nginx.svg +1 -0
  66. package/eventcatalog/public/icons/languages/nim.svg +1 -0
  67. package/eventcatalog/public/icons/languages/ocaml.svg +1 -0
  68. package/eventcatalog/public/icons/languages/perl.svg +1 -0
  69. package/eventcatalog/public/icons/languages/php.svg +1 -0
  70. package/eventcatalog/public/icons/languages/postgresql.svg +1 -0
  71. package/eventcatalog/public/icons/languages/prisma.svg +1 -0
  72. package/eventcatalog/public/icons/languages/purescript.svg +1 -0
  73. package/eventcatalog/public/icons/languages/python.svg +1 -0
  74. package/eventcatalog/public/icons/languages/r.svg +1 -0
  75. package/eventcatalog/public/icons/languages/react.svg +1 -0
  76. package/eventcatalog/public/icons/languages/reasonml.svg +1 -0
  77. package/eventcatalog/public/icons/languages/redis.svg +1 -0
  78. package/eventcatalog/public/icons/languages/ruby.svg +1 -0
  79. package/eventcatalog/public/icons/languages/rust.svg +1 -0
  80. package/eventcatalog/public/icons/languages/sass.svg +1 -0
  81. package/eventcatalog/public/icons/languages/scala.svg +1 -0
  82. package/eventcatalog/public/icons/languages/solidity.svg +1 -0
  83. package/eventcatalog/public/icons/languages/spring.svg +1 -0
  84. package/eventcatalog/public/icons/languages/sqlite.svg +1 -0
  85. package/eventcatalog/public/icons/languages/svelte.svg +1 -0
  86. package/eventcatalog/public/icons/languages/swagger.svg +1 -0
  87. package/eventcatalog/public/icons/languages/swift.svg +1 -0
  88. package/eventcatalog/public/icons/languages/tailwind.svg +1 -0
  89. package/eventcatalog/public/icons/languages/terraform.svg +1 -0
  90. package/eventcatalog/public/icons/languages/toml.svg +1 -0
  91. package/eventcatalog/public/icons/languages/typescript.svg +1 -0
  92. package/eventcatalog/public/icons/languages/unity.svg +1 -0
  93. package/eventcatalog/public/icons/languages/vim.svg +1 -0
  94. package/eventcatalog/public/icons/languages/vue.svg +1 -0
  95. package/eventcatalog/public/icons/languages/webassembly.svg +1 -0
  96. package/eventcatalog/public/icons/languages/yaml.svg +1 -0
  97. package/eventcatalog/public/icons/languages/zig.svg +1 -0
  98. package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.astro +12 -0
  99. package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.tsx +176 -0
  100. package/eventcatalog/src/components/MDX/CodeGroup/MarkdownCodeGroup.tsx +22 -0
  101. package/eventcatalog/src/components/MDX/CodeGroup/code-group-icons.ts +345 -0
  102. package/eventcatalog/src/components/MDX/CodeGroup/code-group.css +22 -0
  103. package/eventcatalog/src/components/MDX/CodeGroup/code-group.spec.tsx +89 -0
  104. package/eventcatalog/src/components/MDX/CodeGroup/parse-panels.ts +11 -0
  105. package/eventcatalog/src/components/MDX/Columns/Column.astro +10 -0
  106. package/eventcatalog/src/components/MDX/Columns/Columns.astro +14 -0
  107. package/eventcatalog/src/components/MDX/Columns/MarkdownColumns.tsx +37 -0
  108. package/eventcatalog/src/components/MDX/Columns/columns.spec.tsx +66 -0
  109. package/eventcatalog/src/components/MDX/Columns/layout.ts +16 -0
  110. package/eventcatalog/src/components/MDX/components.tsx +6 -0
  111. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +1 -1
  112. package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +151 -114
  113. package/eventcatalog/src/components/SchemaExplorer/JSONSchemaViewer.test.tsx +114 -0
  114. package/eventcatalog/src/components/SchemaExplorer/JSONSchemaViewer.tsx +28 -9
  115. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +510 -248
  116. package/eventcatalog/src/components/SchemaExplorer/SchemaFlows.tsx +76 -0
  117. package/eventcatalog/src/components/SchemaExplorer/SchemaGraph.tsx +47 -0
  118. package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +11 -0
  119. package/eventcatalog/src/components/SchemaExplorer/SchemaUsage.tsx +17 -0
  120. package/eventcatalog/src/components/SchemaExplorer/types.ts +48 -3
  121. package/eventcatalog/src/components/SchemaExplorer/utils.ts +28 -1
  122. package/eventcatalog/src/content.config.ts +28 -0
  123. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +38 -7
  124. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +144 -37
  125. package/eventcatalog/src/pages/schemas/explorer/index.astro +5 -0
  126. package/eventcatalog/src/remark-plugins/code-group.ts +39 -0
  127. package/eventcatalog/src/remark-plugins/markdown-code-group.ts +59 -0
  128. package/eventcatalog/src/remark-plugins/markdown-columns.ts +66 -0
  129. package/eventcatalog/src/utils/collections/examples.ts +133 -41
  130. package/eventcatalog/src/utils/collections/flows.ts +43 -0
  131. package/eventcatalog/src/utils/collections/glob-loader.ts +2 -2
  132. package/eventcatalog/src/utils/collections/messages.ts +2 -2
  133. package/eventcatalog/src/utils/collections/schemas.ts +15 -0
  134. package/eventcatalog/src/utils/schema-explorer.ts +73 -7
  135. package/eventcatalog/src/utils/schema-usage-graph.ts +92 -0
  136. package/package.json +8 -8
@@ -146,3 +146,46 @@ export const getFlowsNotInAnyResource = async (): Promise<Flow[]> => {
146
146
  });
147
147
  return flowsNotInAnyResource;
148
148
  };
149
+
150
+ /** A flow that includes a message in one of its steps, reduced to what the schema pages display. */
151
+ export interface FlowReference {
152
+ id: string;
153
+ version: string;
154
+ name?: string;
155
+ summary?: string;
156
+ }
157
+
158
+ /**
159
+ * Finds the flows whose steps send or receive each of the given messages. Step pointers are
160
+ * matched the same way flow diagrams resolve them (exact version, then semver range, then
161
+ * latest). Returns a map keyed by `${collection}:${id}:${version}` of the resolved message.
162
+ */
163
+ export const getFlowsForMessages = async (
164
+ messages: { collection: string; data: { id: string; version: string } }[]
165
+ ): Promise<Map<string, FlowReference[]>> => {
166
+ const flows = await getCollection('flows');
167
+ const messageMap = createVersionedMap(messages);
168
+ const flowsByMessage = new Map<string, FlowReference[]>();
169
+
170
+ for (const flow of flows) {
171
+ if (flow.data.hidden === true) continue;
172
+ const reference: FlowReference = {
173
+ id: flow.data.id,
174
+ version: flow.data.version,
175
+ ...(flow.data.name ? { name: flow.data.name } : {}),
176
+ ...(flow.data.summary ? { summary: flow.data.summary } : {}),
177
+ };
178
+ const seen = new Set<string>();
179
+ for (const step of flow.data.steps ?? []) {
180
+ if (!step.message) continue;
181
+ const message = findInMap(messageMap, step.message.id, step.message.version);
182
+ if (!message) continue;
183
+ const key = `${message.collection}:${message.data.id}:${message.data.version}`;
184
+ if (seen.has(key)) continue;
185
+ seen.add(key);
186
+ flowsByMessage.set(key, [...(flowsByMessage.get(key) ?? []), reference]);
187
+ }
188
+ }
189
+
190
+ return flowsByMessage;
191
+ };
@@ -1,4 +1,4 @@
1
- import { glob } from 'astro/loaders';
1
+ import { glob, type Loader } from 'astro/loaders';
2
2
  import picomatch from 'picomatch';
3
3
  import path from 'path';
4
4
  import { fileURLToPath } from 'url';
@@ -36,7 +36,7 @@ const matchesGlobPattern = (entry: string, patterns: string | string[]) => {
36
36
  return picomatch.isMatch(entry, positivePatterns) && !picomatch.isMatch(entry, negativePatterns);
37
37
  };
38
38
 
39
- export const globWithSafeWatcher = (options: GlobOptions) => {
39
+ export const globWithSafeWatcher = (options: GlobOptions): Loader => {
40
40
  const loader = glob(options);
41
41
 
42
42
  return {
@@ -49,7 +49,7 @@ export const hydrateProducersAndConsumers = ({
49
49
  const toResult = <T extends CollectionEntry<'agents'> | CollectionEntry<'services'> | CollectionEntry<'data-products'>>(
50
50
  resource: T
51
51
  ) => {
52
- if (!hydrate) return { id: resource.data.id, version: resource.data.version };
52
+ if (!hydrate) return { id: resource.data.id, version: resource.data.version, collection: resource.collection };
53
53
  return resource;
54
54
  };
55
55
 
@@ -193,7 +193,7 @@ export const lookupProducersAndConsumers = ({ message, index, hydrate = true }:
193
193
  const toResult = <T extends CollectionEntry<'agents'> | CollectionEntry<'services'> | CollectionEntry<'data-products'>>(
194
194
  resource: T
195
195
  ) => {
196
- if (!hydrate) return { id: resource.data.id, version: resource.data.version };
196
+ if (!hydrate) return { id: resource.data.id, version: resource.data.version, collection: resource.collection };
197
197
  return resource;
198
198
  };
199
199
 
@@ -39,6 +39,21 @@ export const getSchemaURL = (resource: CollectionEntry<PageTypes> | any) => {
39
39
  return path.join(publicPath, schemaFilePath ?? '');
40
40
  };
41
41
 
42
+ /** File extension EventCatalog uses for a schema format, for schemas that have no file name. */
43
+ export const getSchemaExtensionForFormat = (format?: string) => {
44
+ switch (format?.toLowerCase()) {
45
+ case 'jsonschema':
46
+ case 'json':
47
+ return 'json';
48
+ case 'avro':
49
+ return 'avsc';
50
+ case 'protobuf':
51
+ return 'proto';
52
+ default:
53
+ return format ?? '';
54
+ }
55
+ };
56
+
42
57
  export const getSchemaFormatFromURL = (url: string) => {
43
58
  const pathParts = url.split('.');
44
59
  const format = pathParts[pathParts.length - 1];
@@ -1,15 +1,19 @@
1
1
  import { createHash } from 'node:crypto';
2
- import type { SchemaItem, SchemaDetails, Producer, Consumer } from '@components/SchemaExplorer/types';
2
+ import type { SchemaItem, SchemaDetails, Producer, Consumer, MessageChannel } from '@components/SchemaExplorer/types';
3
3
  import { getEvents } from '@utils/collections/events';
4
4
  import { getCommands } from '@utils/collections/commands';
5
5
  import { getQueries } from '@utils/collections/queries';
6
6
  import { getServices, getSpecificationsForService } from '@utils/collections/services';
7
7
  import { getDomains, getSpecificationsForDomain } from '@utils/collections/domains';
8
8
  import { getDataProducts } from '@utils/collections/data-products';
9
+ import { getAgents } from '@utils/collections/agents';
10
+ import { getFlowsForMessages } from '@utils/collections/flows';
9
11
  import { getOwner } from '@utils/collections/owners';
10
12
  import { buildUrl } from '@utils/url-builder';
13
+ import { getSchemaExtensionForFormat } from '@utils/collections/schemas';
11
14
  import { resourceFileExists, readResourceFile } from '@utils/resource-files';
12
15
  import { getExamplesForResource } from '@utils/collections/examples';
16
+ import { attachFlowGraphs, getMessageUsageGraph } from '@utils/schema-usage-graph';
13
17
  import { getCollection } from 'astro:content';
14
18
  import path from 'path';
15
19
 
@@ -37,12 +41,51 @@ async function buildRegistry() {
37
41
 
38
42
  // Fetch all services
39
43
  const services = await getServices({ getAllVersions: true });
44
+ // Producers and consumers can be services, agents, or data products. Index all three so
45
+ // compact { id, version } references can be resolved to a resource for display.
46
+ const [agents, dataProductsForRelationships] = await Promise.all([
47
+ getAgents({ getAllVersions: true }),
48
+ getDataProducts({ getAllVersions: true }),
49
+ ]);
50
+ type RelationshipResource = (typeof services)[number] | (typeof agents)[number] | (typeof dataProductsForRelationships)[number];
51
+ const relationshipResources: RelationshipResource[] = [...services, ...agents, ...dataProductsForRelationships];
52
+ const resourcesByReference = new Map<string, RelationshipResource>();
53
+ const latestResourceByCollectionAndId = new Map<string, RelationshipResource>();
54
+ for (const resource of relationshipResources) {
55
+ const collectionAndId = `${resource.collection}:${resource.data.id}`;
56
+ resourcesByReference.set(`${collectionAndId}:${resource.data.version}`, resource);
57
+ if (!latestResourceByCollectionAndId.has(collectionAndId)) latestResourceByCollectionAndId.set(collectionAndId, resource);
58
+ }
59
+ const toSchemaRelationships = (references: unknown): Producer[] =>
60
+ ((references as { id: string; version: string; collection?: Producer['collection'] }[] | undefined) ?? []).map(
61
+ (reference) => {
62
+ const collection = reference.collection ?? 'services';
63
+ const collectionAndId = `${collection}:${reference.id}`;
64
+ const resource =
65
+ resourcesByReference.get(`${collectionAndId}:${reference.version}`) ??
66
+ latestResourceByCollectionAndId.get(collectionAndId);
67
+ return {
68
+ id: reference.id,
69
+ version: reference.version,
70
+ collection,
71
+ ...(resource?.data.name ? { name: resource.data.name } : {}),
72
+ ...(resource?.data.summary ? { summary: resource.data.summary } : {}),
73
+ };
74
+ }
75
+ );
76
+ const toMessageChannels = (channels: unknown): MessageChannel[] =>
77
+ ((channels as { data: { id: string; version: string; name?: string } }[] | undefined) ?? []).map((channel) => ({
78
+ id: channel.data.id,
79
+ version: channel.data.version,
80
+ ...(channel.data.name ? { name: channel.data.name } : {}),
81
+ }));
40
82
 
41
83
  // Combine all messages
42
84
  const allMessages = [...events, ...commands, ...queries];
43
85
  const messagesBySchemaReference = new Map(
44
86
  allMessages.map((message) => [`${message.collection}:${message.data.id}:${message.data.version}`, message])
45
87
  );
88
+ const flowsByMessage = await getFlowsForMessages(allMessages);
46
89
 
47
90
  // Read message schemas from the generated schemas collection.
48
91
  const messagesWithSchemas = await Promise.all(
@@ -51,11 +94,16 @@ async function buildRegistry() {
51
94
  `${schema.data.message.collectionName}:${schema.data.message.id}:${schema.data.message.version}`
52
95
  );
53
96
  const schemaPath = schema.data.file || schema.data.source.path || '';
54
- const schemaExtension = path.extname(schemaPath).slice(1) || schema.data.format;
97
+ const schemaExtension = path.extname(schemaPath).slice(1) || getSchemaExtensionForFormat(schema.data.format);
55
98
  // The collection types describe raw content references. With
56
- // hydrateServices: false, the loaders return compact { id, version } pairs.
57
- const producers = (message?.data.producers || []) as unknown as Producer[];
58
- const consumers = (message?.data.consumers || []) as unknown as Consumer[];
99
+ // hydrateServices: false, the loaders return compact { id, version } pairs,
100
+ // so look the service name and summary up for display.
101
+ const producers = toSchemaRelationships(message?.data.producers);
102
+ const consumers = toSchemaRelationships(message?.data.consumers);
103
+ const channels = toMessageChannels(message?.data.messageChannels);
104
+ const flows =
105
+ flowsByMessage.get(`${schema.data.message.collectionName}:${schema.data.message.id}:${schema.data.message.version}`) ??
106
+ [];
59
107
 
60
108
  return {
61
109
  collection: schema.data.message.collectionName,
@@ -70,22 +118,40 @@ async function buildRegistry() {
70
118
  // regardless of how many resources reference the message.
71
119
  producerName: producers[0]?.id,
72
120
  },
73
- loadDetails: () => {
121
+ loadDetails: async () => {
74
122
  let examples: SchemaDetails['examples'] = [];
123
+ let graph: SchemaDetails['graph'];
75
124
  if (message) {
76
125
  try {
77
126
  examples = getExamplesForResource(message);
78
127
  } catch (error) {
79
128
  console.error(`Error reading examples for ${message.data.id}:`, error);
80
129
  }
130
+ try {
131
+ graph = await getMessageUsageGraph({
132
+ collection: message.collection,
133
+ id: message.data.id,
134
+ version: message.data.version,
135
+ });
136
+ } catch (error) {
137
+ console.error(`Error building usage graph for ${message.data.id}:`, error);
138
+ }
81
139
  }
82
140
  return {
83
141
  schemaContent: schema.data.content || '',
84
142
  examples,
85
- data: { producers, consumers },
143
+ ...(graph ? { graph } : {}),
144
+ data: {
145
+ producers,
146
+ consumers,
147
+ flows: await attachFlowGraphs(flows, { id: schema.data.message.id, version: schema.data.message.version }),
148
+ channels,
149
+ },
86
150
  };
87
151
  },
88
152
  schemaExtension,
153
+ ...(schema.data.name ? { schemaName: schema.data.name } : {}),
154
+ ...(schema.data.ref ? { schemaRef: schema.data.ref, source: schema.data.source } : {}),
89
155
  };
90
156
  })
91
157
  );
@@ -0,0 +1,92 @@
1
+ import type { Edge, Node } from '@xyflow/react';
2
+ import config from '@config';
3
+ import {
4
+ getNodesAndEdgesForCommands,
5
+ getNodesAndEdgesForEvents,
6
+ getNodesAndEdgesForQueries,
7
+ } from '@utils/node-graphs/message-node-graph';
8
+ import { getNodesAndEdges as getNodesAndEdgesForFlow } from '@utils/node-graphs/flows-node-graph';
9
+ import { compactVisualiserGraph } from '@utils/node-graphs/compact-visualiser-graph';
10
+
11
+ export interface MessageUsageGraph {
12
+ nodes: Node[];
13
+ edges: Edge[];
14
+ }
15
+
16
+ const graphBuilders = {
17
+ events: getNodesAndEdgesForEvents,
18
+ commands: getNodesAndEdgesForCommands,
19
+ queries: getNodesAndEdgesForQueries,
20
+ } as const;
21
+
22
+ /**
23
+ * The same producer → message → consumer graph the message docs page renders, reduced to the
24
+ * fields the visualiser needs so it can be sent to the schema pages.
25
+ */
26
+ export const getMessageUsageGraph = async ({
27
+ collection,
28
+ id,
29
+ version,
30
+ }: {
31
+ collection: string;
32
+ id: string;
33
+ version: string;
34
+ }): Promise<MessageUsageGraph | undefined> => {
35
+ const build = graphBuilders[collection as keyof typeof graphBuilders];
36
+ if (!build) return undefined;
37
+ const { nodes, edges } = await build({
38
+ id,
39
+ version,
40
+ mode: 'simple',
41
+ channelRenderMode: config.visualiser?.channels?.renderMode === 'single' ? 'single' : 'flat',
42
+ });
43
+ return compactVisualiserGraph(nodes as Node[], edges as Edge[]);
44
+ };
45
+
46
+ /** Identifies the message a diagram is being viewed from, so its node can be highlighted. */
47
+ export interface FocusedMessage {
48
+ id: string;
49
+ version: string;
50
+ }
51
+
52
+ /**
53
+ * The flow diagram the flow docs page renders, compacted for the schema pages. Steps that
54
+ * send or receive the focused message get the visualiser's "Viewing" indicator.
55
+ */
56
+ export const getFlowGraph = async ({
57
+ id,
58
+ version,
59
+ focus,
60
+ }: {
61
+ id: string;
62
+ version: string;
63
+ focus?: FocusedMessage;
64
+ }): Promise<MessageUsageGraph> => {
65
+ const { nodes, edges } = await getNodesAndEdgesForFlow({ id, version, mode: 'simple' });
66
+ const focused = (nodes as Node[]).map((node) => {
67
+ const message = node.data?.message as { id?: string; version?: string } | undefined;
68
+ return focus && message?.id === focus.id && message?.version === focus.version
69
+ ? { ...node, data: { ...node.data, isFocused: true } }
70
+ : node;
71
+ });
72
+ return compactVisualiserGraph(focused, edges as Edge[]);
73
+ };
74
+
75
+ /**
76
+ * Adds each flow's diagram to the flow usages, highlighting the focused message's steps.
77
+ * A flow whose diagram fails to build is kept without one.
78
+ */
79
+ export const attachFlowGraphs = <T extends { id: string; version: string }>(
80
+ flows: T[],
81
+ focus?: FocusedMessage
82
+ ): Promise<(T & { graph?: MessageUsageGraph })[]> =>
83
+ Promise.all(
84
+ flows.map(async (flow) => {
85
+ try {
86
+ return { ...flow, graph: await getFlowGraph({ ...flow, focus }) };
87
+ } catch (error) {
88
+ console.error(`Error building flow graph for ${flow.id}:`, error);
89
+ return flow;
90
+ }
91
+ })
92
+ );
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "license": "SEE LICENSE IN LICENSE",
9
9
  "type": "module",
10
- "version": "4.10.14",
10
+ "version": "4.11.0",
11
11
  "publishConfig": {
12
12
  "access": "public"
13
13
  },
@@ -32,10 +32,10 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@ai-sdk/react": "^3.0.17",
35
- "@astrojs/markdown-remark": "^7.2.4",
36
- "@astrojs/mdx": "^7.0.8",
37
- "@astrojs/node": "^11.1.4",
38
- "@astrojs/react": "^6.0.4",
35
+ "@astrojs/markdown-remark": "^7.3.1",
36
+ "@astrojs/mdx": "^8.0.1",
37
+ "@astrojs/node": "^11.1.6",
38
+ "@astrojs/react": "^6.0.6",
39
39
  "@astrojs/rss": "^4.0.19",
40
40
  "@asyncapi/avro-schema-parser": "3.0.24",
41
41
  "@asyncapi/parser": "^3.6.0",
@@ -61,7 +61,7 @@
61
61
  "@tanstack/react-table": "^8.17.3",
62
62
  "@xyflow/react": "^12.3.6",
63
63
  "ai": "^6.0.17",
64
- "astro": "7.2.8",
64
+ "astro": "7.3.3",
65
65
  "astro-expressive-code": "^0.44.0",
66
66
  "astro-seo": "^0.8.4",
67
67
  "auth-astro": "^4.2.0",
@@ -119,9 +119,9 @@
119
119
  "update-notifier": "^7.3.1",
120
120
  "uuid": "^11.1.1",
121
121
  "zod": "^4.3.6",
122
- "@eventcatalog/sdk": "2.29.0",
122
+ "@eventcatalog/linter": "1.1.20",
123
123
  "@eventcatalog/visualiser": "^4.1.4",
124
- "@eventcatalog/linter": "1.1.19"
124
+ "@eventcatalog/sdk": "2.29.1"
125
125
  },
126
126
  "devDependencies": {
127
127
  "@astrojs/check": "^0.9.10",