@eventcatalog/core 3.36.2 → 3.36.4

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 (34) 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-H6TGUW5O.js → chunk-6JY6QF7D.js} +1 -1
  6. package/dist/{chunk-L723FWAT.js → chunk-7WJEUZFM.js} +3 -3
  7. package/dist/{chunk-IO4U4MPC.js → chunk-HF27CRFY.js} +1 -1
  8. package/dist/{chunk-R5ZDI2JO.js → chunk-NV7DNZ3X.js} +1 -1
  9. package/dist/{chunk-SEAN3UND.js → chunk-XTJ636IF.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/docs/api/09-flow-api.md +38 -0
  13. package/dist/docs/api/11-data-api.md +6 -1
  14. package/dist/docs/development/guides/flows/01-introduction.md +1 -1
  15. package/dist/docs/development/guides/flows/03-flow-nodes.md +58 -4
  16. package/dist/eventcatalog.cjs +1 -1
  17. package/dist/eventcatalog.js +10 -10
  18. package/dist/generate.cjs +1 -1
  19. package/dist/generate.js +3 -3
  20. package/dist/utils/cli-logger.cjs +1 -1
  21. package/dist/utils/cli-logger.js +2 -2
  22. package/eventcatalog/src/components/MDX/Flow/Flow.astro +10 -6
  23. package/eventcatalog/src/content.config.ts +24 -1
  24. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +8 -3
  25. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +41 -12
  26. package/eventcatalog/src/stores/sidebar-store/builders/container.ts +10 -1
  27. package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +10 -1
  28. package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +38 -0
  29. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +1 -0
  30. package/eventcatalog/src/stores/sidebar-store/state.ts +85 -2
  31. package/eventcatalog/src/utils/collections/flows.ts +29 -1
  32. package/eventcatalog/src/utils/markdown.ts +8 -3
  33. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +46 -1
  34. package/package.json +4 -4
@@ -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.36.2";
40
+ var version = "3.36.4";
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-IO4U4MPC.js";
4
- import "../chunk-R5ZDI2JO.js";
3
+ } from "../chunk-HF27CRFY.js";
4
+ import "../chunk-NV7DNZ3X.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.36.2";
114
+ var version = "3.36.4";
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-L723FWAT.js";
4
- import "../chunk-IO4U4MPC.js";
3
+ } from "../chunk-7WJEUZFM.js";
5
4
  import "../chunk-4UVFXLPI.js";
6
- import "../chunk-R5ZDI2JO.js";
5
+ import "../chunk-HF27CRFY.js";
6
+ import "../chunk-NV7DNZ3X.js";
7
7
  import "../chunk-5T63CXKU.js";
8
8
  export {
9
9
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-SEAN3UND.js";
3
+ } from "./chunk-XTJ636IF.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,10 +1,10 @@
1
- import {
2
- raiseEvent
3
- } from "./chunk-IO4U4MPC.js";
4
1
  import {
5
2
  countResources,
6
3
  serializeCounts
7
4
  } from "./chunk-4UVFXLPI.js";
5
+ import {
6
+ raiseEvent
7
+ } from "./chunk-HF27CRFY.js";
8
8
  import {
9
9
  getEventCatalogConfigFile,
10
10
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-R5ZDI2JO.js";
3
+ } from "./chunk-NV7DNZ3X.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "3.36.2";
2
+ var version = "3.36.4";
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-R5ZDI2JO.js";
3
+ } from "./chunk-NV7DNZ3X.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "3.36.2";
28
+ var version = "3.36.4";
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-R5ZDI2JO.js";
3
+ } from "./chunk-NV7DNZ3X.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -261,7 +261,45 @@ Flows allow you to create [service nodes](/docs/services). Services link to your
261
261
 
262
262
  _[See example of Message node in a workflow](https://demo.eventcatalog.dev/visualiser/flows/CancelSubscription/0.0.1)._
263
263
 
264
+ #### Container Nodes
264
265
 
266
+ <AddedIn version="3.36.3" />
267
+
268
+ Flows allow you to create [container (data store) nodes](/docs/development/guides/data/introduction). Containers link to your defined data stores in EventCatalog. The container's sidebar will automatically show a "Flows" section linking back to any flow that references it.
269
+
270
+ ```md title="Example"
271
+ ---
272
+ steps:
273
+ - id: "orders_db"
274
+ title: "Orders DB"
275
+ container:
276
+ id: "orders-db"
277
+ version: "1.0.0"
278
+ next_step:
279
+ id: "next_step"
280
+ label: "Persist order records"
281
+ ---
282
+ ```
283
+
284
+ #### Data Product Nodes
285
+
286
+ <AddedIn version="3.36.3" />
287
+
288
+ Flows allow you to create [data product nodes](/docs/development/guides/data-products/introduction). Data products link to your defined data products in EventCatalog. The data product's sidebar will automatically show a "Flows" section linking back to any flow that references it.
289
+
290
+ ```md title="Example"
291
+ ---
292
+ steps:
293
+ - id: "order_analytics"
294
+ title: "Order Analytics"
295
+ dataProduct:
296
+ id: "order-analytics"
297
+ version: "1.0.0"
298
+ next_step:
299
+ id: "next_step"
300
+ label: "Prepare fulfillment KPIs"
301
+ ---
302
+ ```
265
303
 
266
304
  ## Optional fields {#optional-fields}
267
305
 
@@ -235,7 +235,12 @@ Options:
235
235
  | `changelog` | `object` | No | An object with a `visible` property to show/hide the changelog button |
236
236
  | `owners` | `object` | No | An object with a `visible` property to show/hide the owners section |
237
237
  | `attachments` | `object` | No | An object with a `visible` property to show/hide the attachments section |
238
- | `repository` | `object` | No | An object with a `visible` property to show/hide the repository section |
238
+ | `repository` | `object` | No | An object with a `visible` property to show/hide the repository section |
239
+ | `flows` | `object` | No | An object with a `visible` property to show/hide the flows section |
240
+
241
+ **`flows`** <AddedIn version="3.36.3" />
242
+
243
+ Shows which flows reference this data store as a step. Flows are surfaced automatically when a [flow step](/docs/development/guides/flows/flow-nodes) uses the `container` node type to reference this resource.
239
244
 
240
245
  ### `attachments` {#attachments}
241
246
 
@@ -12,7 +12,7 @@ import AddedIn from '@site/src/components/MDX/AddedIn';
12
12
 
13
13
  <AddedIn version="2.5.0" />
14
14
 
15
- Flows are a way to document business workflows in your organization. You can reuse your documented resources (e.g services, messages, data stores) in your flows.
15
+ Flows are a way to document business workflows in your organization. You can reuse your documented resources (e.g services, messages, data stores, data products) in your flows.
16
16
 
17
17
  An example of a flow would be when a user makes a payment to an e-commence system, this interaction triggers many parts of the architecture (services, external services, commands, queries and events):
18
18
 
@@ -13,9 +13,7 @@ import AddedIn from '@site/src/components/MDX/AddedIn';
13
13
 
14
14
  Flow nodes are the building blocks of flows. They are used to represent the different steps in a flow.
15
15
 
16
- With flow nodes you can reference your services, events, commands and queries, external systems, users (actors) or even create your own custom nodes.
17
-
18
- EventCatalog (> 2.34.2) you can also reference flows as a node type.
16
+ With flow nodes you can reference your services, events, commands and queries, external systems, users (actors), data stores (containers), data products, or create your own custom nodes.
19
17
 
20
18
  ## Common step properties
21
19
 
@@ -31,7 +29,7 @@ Every flow step (regardless of node type) supports these properties:
31
29
  | `next_steps` | [Step reference](#connecting-steps)[] | No | Multiple next steps for branching (cannot be used with `next_step`) |
32
30
 
33
31
  :::tip Type exclusivity rule
34
- Each step can only use **one** node type property. You cannot combine `message`, `service`, `flow`, `actor`, `custom`, or `externalSystem` on the same step.
32
+ Each step can only use **one** node type property. You cannot combine `message`, `service`, `flow`, `container`, `dataProduct`, `actor`, `custom`, or `externalSystem` on the same step.
35
33
  :::
36
34
 
37
35
  ## Connecting steps {#connecting-steps}
@@ -67,6 +65,8 @@ next_steps:
67
65
  - [message](#message) — Represents an event, command or query resource in EventCatalog
68
66
  - [service](#service) — Represents a service resource in EventCatalog
69
67
  - [flow](#flow) — Represents a flow in EventCatalog (added in EventCatalog 2.34.2)
68
+ - [container](#container) — Represents a data store (container) resource in EventCatalog
69
+ - [dataProduct](#dataproduct) — Represents a data product resource in EventCatalog
70
70
  - [custom](#custom) — A custom node type with configurable title, summary, icon, properties and more
71
71
 
72
72
 
@@ -202,6 +202,60 @@ Click a flow node in the visualiser to expand the referenced flow's steps inline
202
202
 
203
203
  ---
204
204
 
205
+ ### container
206
+
207
+ <AddedIn version="3.36.3" />
208
+
209
+ Represents and refers to a data store (container) resource in EventCatalog. When a flow references a container, the container's sidebar automatically shows a "Flows" section linking back to the referencing flow.
210
+
211
+ #### Container properties
212
+
213
+ | Property | Type | Required | Description |
214
+ |----------|------|----------|-------------|
215
+ | `id` | `string` | **Yes** | The id of the container in your catalog |
216
+ | `version` | `string` | No | The version to reference (defaults to `latest`) |
217
+
218
+ ```yml
219
+ steps:
220
+ - id: "orders_db"
221
+ title: "Orders DB"
222
+ container:
223
+ id: "orders-db"
224
+ version: "1.0.0"
225
+ next_step:
226
+ id: "next_step"
227
+ label: "Persist order records"
228
+ ```
229
+
230
+ ---
231
+
232
+ ### dataProduct
233
+
234
+ <AddedIn version="3.36.3" />
235
+
236
+ Represents and refers to a data product resource in EventCatalog. When a flow references a data product, the data product's sidebar automatically shows a "Flows" section linking back to the referencing flow.
237
+
238
+ #### Data product properties
239
+
240
+ | Property | Type | Required | Description |
241
+ |----------|------|----------|-------------|
242
+ | `id` | `string` | **Yes** | The id of the data product in your catalog |
243
+ | `version` | `string` | No | The version to reference (defaults to `latest`) |
244
+
245
+ ```yml
246
+ steps:
247
+ - id: "order_analytics"
248
+ title: "Order Analytics"
249
+ dataProduct:
250
+ id: "order-analytics"
251
+ version: "1.0.0"
252
+ next_step:
253
+ id: "next_step"
254
+ label: "Prepare fulfillment KPIs"
255
+ ```
256
+
257
+ ---
258
+
205
259
  ### custom
206
260
 
207
261
  <AddedIn version="2.30.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.36.2";
117
+ var version = "3.36.4";
118
118
 
119
119
  // src/constants.ts
120
120
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
- runMigrations
3
- } from "./chunk-XUAF2H54.js";
4
- import "./chunk-CA4U2JP7.js";
2
+ log_build_default
3
+ } from "./chunk-7WJEUZFM.js";
4
+ import "./chunk-4UVFXLPI.js";
5
5
  import {
6
6
  resolve_catalog_dependencies_default
7
7
  } from "./chunk-WAJIJEI3.js";
@@ -12,10 +12,10 @@ import {
12
12
  watch
13
13
  } from "./chunk-K3ZVEX2Y.js";
14
14
  import {
15
- log_build_default
16
- } from "./chunk-L723FWAT.js";
17
- import "./chunk-IO4U4MPC.js";
18
- import "./chunk-4UVFXLPI.js";
15
+ runMigrations
16
+ } from "./chunk-XUAF2H54.js";
17
+ import "./chunk-CA4U2JP7.js";
18
+ import "./chunk-HF27CRFY.js";
19
19
  import {
20
20
  catalogToAstro
21
21
  } from "./chunk-YDXB3BD2.js";
@@ -28,13 +28,13 @@ import {
28
28
  } from "./chunk-ULZYHF3V.js";
29
29
  import {
30
30
  generate
31
- } from "./chunk-H6TGUW5O.js";
31
+ } from "./chunk-6JY6QF7D.js";
32
32
  import {
33
33
  logger
34
- } from "./chunk-SEAN3UND.js";
34
+ } from "./chunk-XTJ636IF.js";
35
35
  import {
36
36
  VERSION
37
- } from "./chunk-R5ZDI2JO.js";
37
+ } from "./chunk-NV7DNZ3X.js";
38
38
  import {
39
39
  getEventCatalogConfigFile,
40
40
  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.36.2";
81
+ var version = "3.36.4";
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-H6TGUW5O.js";
4
- import "./chunk-SEAN3UND.js";
5
- import "./chunk-R5ZDI2JO.js";
3
+ } from "./chunk-6JY6QF7D.js";
4
+ import "./chunk-XTJ636IF.js";
5
+ import "./chunk-NV7DNZ3X.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.36.2";
39
+ var version = "3.36.4";
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-SEAN3UND.js";
4
- import "../chunk-R5ZDI2JO.js";
3
+ } from "../chunk-XTJ636IF.js";
4
+ import "../chunk-NV7DNZ3X.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -6,10 +6,15 @@ import AstroNodeGraph from '../NodeGraph/AstroNodeGraph';
6
6
  import { getVersionFromCollection } from '@utils/collections/versions';
7
7
  import { isVisualiserEnabled, isEventCatalogChatEnabled, isDevMode } from '@utils/feature';
8
8
  import { loadSavedLayout, applyLayoutToNodes, buildResourceKey } from '@utils/node-graphs/layout-persistence';
9
+ import { randomUUID } from 'node:crypto';
10
+ import { parseMdxBooleanProp } from '@utils/markdown';
9
11
 
10
12
  const isChatEnabled = isEventCatalogChatEnabled();
11
13
 
12
- const { id, version = 'latest', maxHeight, includeKey = true, mode = 'simple', walkthrough = true, search = true } = Astro.props;
14
+ const { id, version = 'latest', maxHeight, mode = 'simple' } = Astro.props;
15
+ const includeKey = parseMdxBooleanProp(Astro.props.legend ?? Astro.props.includeKey, true);
16
+ const search = parseMdxBooleanProp(Astro.props.search, false);
17
+ const walkthrough = parseMdxBooleanProp(Astro.props.walkthrough, false);
13
18
 
14
19
  // Find the flow for the given id and version
15
20
  const flows = await getFlows();
@@ -28,6 +33,7 @@ const { nodes, edges } = await getNodesAndEdges({
28
33
  const resourceKey = buildResourceKey('flows', id, flow.data.version);
29
34
  const savedLayout = await loadSavedLayout(resourceKey);
30
35
  const nodesWithLayout = applyLayoutToNodes(nodes, savedLayout);
36
+ const portalId = `${id}-${flow.data.version}-flow-${randomUUID()}-portal`;
31
37
  ---
32
38
 
33
39
  {
@@ -45,7 +51,7 @@ const nodesWithLayout = applyLayoutToNodes(nodes, savedLayout);
45
51
 
46
52
  <div
47
53
  class="h-[30em] my-6 mb-12 w-full relative border border-[rgb(var(--ec-page-border))] rounded-md"
48
- id={`${id}-portal`}
54
+ id={portalId}
49
55
  style={{
50
56
  maxHeight: maxHeight ? `${maxHeight}em` : `30em`,
51
57
  }}
@@ -57,12 +63,10 @@ const nodesWithLayout = applyLayoutToNodes(nodes, savedLayout);
57
63
  id={id}
58
64
  nodes={nodesWithLayout}
59
65
  edges={edges}
60
- hrefLabel={'View in visualizer'}
61
- href={isVisualiserEnabled() ? `/visualiser/flows/${id}/${version}` : undefined}
62
- linkTo={'visualiser'}
66
+ mode={mode}
63
67
  includeKey={includeKey}
64
- footerLabel=`Flow diagram - ${flow.data.name} - v(${flow.data.version})`
65
68
  client:only="react"
69
+ portalId={portalId}
66
70
  showFlowWalkthrough={walkthrough}
67
71
  showSearch={search}
68
72
  isChatEnabled={isChatEnabled}
@@ -266,6 +266,8 @@ const flows = defineCollection({
266
266
  message: pointer.optional(),
267
267
  service: pointer.optional(),
268
268
  flow: pointer.optional(),
269
+ container: pointer.optional(),
270
+ dataProduct: pointer.optional(),
269
271
 
270
272
  actor: z
271
273
  .object({
@@ -308,7 +310,15 @@ const flows = defineCollection({
308
310
  if (data.next_step && data.next_steps) return false;
309
311
 
310
312
  // Either one or non types can be present
311
- const typesUsed = [data.message, data.service, data.flow, data.actor, data.custom].filter((v) => v).length;
313
+ const typesUsed = [
314
+ data.message,
315
+ data.service,
316
+ data.flow,
317
+ data.container,
318
+ data.dataProduct,
319
+ data.actor,
320
+ data.custom,
321
+ ].filter((v) => v).length;
312
322
  return typesUsed === 0 || typesUsed === 1;
313
323
  })
314
324
  ),
@@ -425,6 +435,18 @@ const dataProducts = defineCollection({
425
435
  .object({
426
436
  inputs: z.array(pointer).optional(),
427
437
  outputs: z.array(dataProductOutputPointer).optional(),
438
+ detailsPanel: z
439
+ .object({
440
+ domains: detailPanelPropertySchema.optional(),
441
+ inputs: detailPanelPropertySchema.optional(),
442
+ outputs: detailPanelPropertySchema.optional(),
443
+ versions: detailPanelPropertySchema.optional(),
444
+ repository: detailPanelPropertySchema.optional(),
445
+ owners: detailPanelPropertySchema.optional(),
446
+ changelog: detailPanelPropertySchema.optional(),
447
+ flows: detailPanelPropertySchema.optional(),
448
+ })
449
+ .optional(),
428
450
  })
429
451
  .extend(baseSchema.shape),
430
452
  });
@@ -517,6 +539,7 @@ const containers = defineCollection({
517
539
  changelog: detailPanelPropertySchema.optional(),
518
540
  attachments: detailPanelPropertySchema.optional(),
519
541
  services: detailPanelPropertySchema.optional(),
542
+ flows: detailPanelPropertySchema.optional(),
520
543
  })
521
544
  .optional(),
522
545
  services: z.array(reference('services')).optional(),
@@ -9,7 +9,7 @@ import mdxComponents from '@components/MDX/components';
9
9
  import { getOwner } from '@utils/collections/owners';
10
10
  import { buildUrl, buildEditUrlForResource } from '@utils/url-builder';
11
11
  import { resourceToCollectionMap } from '@utils/collections/util';
12
- import { getMDXComponentsByName } from '@utils/markdown';
12
+ import { getMDXComponentsByName, parseMdxBooleanProp } from '@utils/markdown';
13
13
  import { getAdjacentPages, getNavigationItems } from '@enterprise/custom-documentation/utils/custom-docs';
14
14
  import CustomDocsNav from '@enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro';
15
15
  import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
@@ -22,7 +22,10 @@ const doc = props.data;
22
22
  const { Content, headings } = await render(props as any);
23
23
  const currentSlug = props.id;
24
24
 
25
- const nodeGraphs = getMDXComponentsByName(props.body, 'NodeGraph') || [];
25
+ const nodeGraphs =
26
+ getMDXComponentsByName(props.body, 'NodeGraph')?.filter((nodeGraph: any) => {
27
+ return nodeGraph.id && nodeGraph.version && nodeGraph.type;
28
+ }) || [];
26
29
 
27
30
  const { prev, next } = await getAdjacentPages(currentSlug);
28
31
 
@@ -152,8 +155,10 @@ const editUrl =
152
155
  version={nodeGraph.version}
153
156
  collection={collection}
154
157
  title={nodeGraph.title}
155
- mode="simple"
158
+ mode={nodeGraph.mode || 'simple'}
156
159
  linksToVisualiser={true}
160
+ showSearch={parseMdxBooleanProp(nodeGraph.search, true)}
161
+ showLegend={parseMdxBooleanProp(nodeGraph.legend, true)}
157
162
  href={
158
163
  isVisualiserEnabled()
159
164
  ? {
@@ -43,7 +43,7 @@ import {
43
43
  isRSSEnabled,
44
44
  isExportPDFEnabled,
45
45
  } from '@utils/feature';
46
- import { getMDXComponentsByName } from '@utils/markdown';
46
+ import { getMDXComponentsByName, parseMdxBooleanProp } from '@utils/markdown';
47
47
 
48
48
  import type { CollectionTypes } from '@types';
49
49
 
@@ -265,10 +265,40 @@ const generatePromptForResource = (props: any) => {
265
265
  };
266
266
 
267
267
  // Handle node graphs in the markdown
268
- let nodeGraphs = getMDXComponentsByName(props.body || '', 'NodeGraph') || [];
268
+ const currentPageNodeGraph = {
269
+ id: props.data.id,
270
+ version: props.data.version,
271
+ type: collectionToResourceMap[props.collection as keyof typeof collectionToResourceMap],
272
+ };
273
+
274
+ let nodeGraphs =
275
+ getMDXComponentsByName(props.body || '', 'NodeGraph')?.map((nodeGraph: any) => {
276
+ const graph = nodeGraph.id === undefined ? { ...currentPageNodeGraph, ...nodeGraph } : nodeGraph;
277
+
278
+ return {
279
+ ...graph,
280
+ search: parseMdxBooleanProp(nodeGraph.search, true),
281
+ legend: parseMdxBooleanProp(nodeGraph.legend, true),
282
+ };
283
+ }) || [];
284
+ const flowEmbeds = getMDXComponentsByName(props.body || '', 'Flow') || [];
269
285
 
270
286
  // Get props for the node graph (when no id is passed, we assume its the current page)
271
- const nodeGraphPropsForPage = nodeGraphs.find((nodeGraph: any) => nodeGraph.id === undefined) || ({} as any);
287
+ const hasCurrentFlowEmbed =
288
+ props.collection === 'flows' &&
289
+ flowEmbeds.some((flowEmbed: any) => {
290
+ const flowId = flowEmbed.id;
291
+ const flowVersion = flowEmbed.version || 'latest';
292
+
293
+ return flowId === props.data.id && (flowVersion === 'latest' || flowVersion === props.data.version);
294
+ });
295
+ const hasCurrentPageNodeGraph = nodeGraphs.some((nodeGraph: any) => {
296
+ return (
297
+ nodeGraph.id === currentPageNodeGraph.id &&
298
+ nodeGraph.version === currentPageNodeGraph.version &&
299
+ nodeGraph.type === currentPageNodeGraph.type
300
+ );
301
+ });
272
302
 
273
303
  const shouldRenderVersionList =
274
304
  shouldRenderSideBarSection(props, 'versions') && props.data.versions && props.data.versions.length > 1;
@@ -287,15 +317,14 @@ const httpMethodStyle = httpOperation?.method
287
317
  ? httpMethodColors[httpOperation.method.toUpperCase()] || { background: '#6b7280', color: '#ffffff' }
288
318
  : undefined;
289
319
 
290
- // This will render the graph for this page
291
- nodeGraphs.push({
292
- id: props.data.id,
293
- version: props.data.version,
294
- type: collectionToResourceMap[props.collection as keyof typeof collectionToResourceMap],
295
- ...nodeGraphPropsForPage,
296
- search: nodeGraphPropsForPage?.search ? nodeGraphPropsForPage.search === 'true' : true,
297
- legend: nodeGraphPropsForPage?.legend ? nodeGraphPropsForPage.legend === 'true' : true,
298
- });
320
+ // This will render the graph for this page. Flow pages can already render their graph explicitly via <Flow />.
321
+ if (!hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
322
+ nodeGraphs.push({
323
+ ...currentPageNodeGraph,
324
+ search: true,
325
+ legend: true,
326
+ });
327
+ }
299
328
  ---
300
329
 
301
330
  <VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
@@ -16,7 +16,8 @@ import { iconFieldsForResource } from '@utils/icon';
16
16
  export const buildContainerNode = (
17
17
  container: CollectionEntry<'containers'>,
18
18
  owners: any[],
19
- context: ResourceGroupContext
19
+ context: ResourceGroupContext,
20
+ flowRefs: string[] = []
20
21
  ): NavNode => {
21
22
  const servicesWritingToContainer = container.data.servicesThatWriteToContainer || [];
22
23
  const servicesReadingFromContainer = container.data.servicesThatReadFromContainer || [];
@@ -36,6 +37,7 @@ export const buildContainerNode = (
36
37
  ...dataProductsReadingFromContainer.map((dp: any) => `data-product:${dp.data.id}:${dp.data.version}`),
37
38
  ];
38
39
  const renderReads = allReads.length > 0 && shouldRenderSideBarSection(container, 'services');
40
+ const renderFlows = flowRefs.length > 0 && shouldRenderSideBarSection(container, 'flows');
39
41
 
40
42
  const renderVisualiser = isVisualiserEnabled();
41
43
 
@@ -108,6 +110,13 @@ export const buildContainerNode = (
108
110
  icon: 'ArrowDownToLine',
109
111
  pages: allReads,
110
112
  },
113
+ renderFlows && {
114
+ type: 'group',
115
+ title: 'Flows',
116
+ icon: 'Waypoints',
117
+ pages: flowRefs,
118
+ visible: flowRefs.length > 0,
119
+ },
111
120
  renderOwners && buildOwnersSection(owners),
112
121
  renderRepository && buildRepositorySection(container.data.repository as { url: string; language: string }),
113
122
  hasAttachments && buildAttachmentsSection(container.data.attachments as any[]),
@@ -60,13 +60,15 @@ const resolvePointerToRef = (pointer: { id: string; version?: string }, context:
60
60
  export const buildDataProductNode = (
61
61
  dataProduct: CollectionEntry<'data-products'>,
62
62
  owners: any[],
63
- context: DataProductContext
63
+ context: DataProductContext,
64
+ flowRefs: string[] = []
64
65
  ): NavNode => {
65
66
  const inputs = dataProduct.data.inputs || [];
66
67
  const outputs = dataProduct.data.outputs || [];
67
68
 
68
69
  const renderVisualiser = isVisualiserEnabled();
69
70
  const renderOwners = owners.length > 0 && shouldRenderSideBarSection(dataProduct, 'owners');
71
+ const renderFlows = flowRefs.length > 0 && shouldRenderSideBarSection(dataProduct, 'flows');
70
72
  const docsSection = buildResourceDocsSection(
71
73
  'data-products',
72
74
  dataProduct.data.id,
@@ -139,6 +141,13 @@ export const buildDataProductNode = (
139
141
  icon: 'FileCheck',
140
142
  pages: dataContracts,
141
143
  },
144
+ renderFlows && {
145
+ type: 'group',
146
+ title: 'Flows',
147
+ icon: 'Waypoints',
148
+ pages: flowRefs,
149
+ visible: flowRefs.length > 0,
150
+ },
142
151
  renderOwners && buildOwnersSection(owners),
143
152
  ].filter(Boolean) as ChildRef[],
144
153
  };
@@ -56,6 +56,8 @@ export const buildFlowNode = (flow: CollectionEntry<'flows'>, context: ResourceG
56
56
  const queryMap = createVersionedMap(context.queries);
57
57
  const serviceMap = createVersionedMap(context.services);
58
58
  const flowMap = createVersionedMap(context.flows);
59
+ const containerMap = createVersionedMap(context.containers);
60
+ const dataProductMap = createVersionedMap(context.dataProducts);
59
61
  const messageRefs = uniqueRefs(
60
62
  steps.map((step) => resolveMessageStep(step, { eventMap, commandMap, queryMap })).filter(Boolean) as string[]
61
63
  );
@@ -71,6 +73,30 @@ export const buildFlowNode = (flow: CollectionEntry<'flows'>, context: ResourceG
71
73
  .filter(Boolean)
72
74
  .map((referencedFlow) => `flow:${referencedFlow!.data.id}:${referencedFlow!.data.version}`)
73
75
  );
76
+ const containerRefs = uniqueRefs(
77
+ steps
78
+ .map((step: any) => {
79
+ const hydratedContainer = Array.isArray(step.container) ? step.container[0] : undefined;
80
+ if (hydratedContainer?.collection && hydratedContainer?.data) return hydratedContainer;
81
+
82
+ const pointer = Array.isArray(step.container) ? undefined : step.container;
83
+ return pointer ? resolvePointer(containerMap, pointer) : undefined;
84
+ })
85
+ .filter(Boolean)
86
+ .map((container) => `container:${container!.data.id}:${container!.data.version}`)
87
+ );
88
+ const dataProductRefs = uniqueRefs(
89
+ steps
90
+ .map((step: any) => {
91
+ const hydratedDataProduct = Array.isArray(step.dataProduct) ? step.dataProduct[0] : undefined;
92
+ if (hydratedDataProduct?.collection && hydratedDataProduct?.data) return hydratedDataProduct;
93
+
94
+ const pointer = Array.isArray(step.dataProduct) ? undefined : step.dataProduct;
95
+ return pointer ? resolvePointer(dataProductMap, pointer) : undefined;
96
+ })
97
+ .filter(Boolean)
98
+ .map((dataProduct) => `data-product:${dataProduct!.data.id}:${dataProduct!.data.version}`)
99
+ );
74
100
 
75
101
  return {
76
102
  type: 'item',
@@ -120,6 +146,18 @@ export const buildFlowNode = (flow: CollectionEntry<'flows'>, context: ResourceG
120
146
  icon: 'Waypoints',
121
147
  pages: flowRefs,
122
148
  },
149
+ containerRefs.length > 0 && {
150
+ type: 'group',
151
+ title: 'Data Stores',
152
+ icon: 'Database',
153
+ pages: containerRefs,
154
+ },
155
+ dataProductRefs.length > 0 && {
156
+ type: 'group',
157
+ title: 'Data Products',
158
+ icon: 'Package',
159
+ pages: dataProductRefs,
160
+ },
123
161
  ].filter(Boolean) as ChildRef[],
124
162
  };
125
163
  };
@@ -61,6 +61,7 @@ export type ResourceGroupContext = {
61
61
  queries: CollectionEntry<'queries'>[];
62
62
  flows: CollectionEntry<'flows'>[];
63
63
  containers: CollectionEntry<'containers'>[];
64
+ dataProducts: CollectionEntry<'data-products'>[];
64
65
  diagrams: CollectionEntry<'diagrams'>[];
65
66
  resourceDocs: ResourceDocEntry[];
66
67
  resourceDocCategories: ResourceDocCategoryEntry[];
@@ -35,6 +35,8 @@ let memoryCache: NavigationData | null = null;
35
35
 
36
36
  type MessageEntry = CollectionEntry<'events' | 'commands' | 'queries'>;
37
37
  type ServiceEntry = CollectionEntry<'services'>;
38
+ type ContainerEntry = CollectionEntry<'containers'>;
39
+ type DataProductEntry = CollectionEntry<'data-products'>;
38
40
 
39
41
  const getMessageNodeKey = (message: MessageEntry) =>
40
42
  `${pluralizeMessageType(message)}:${message.data.id}:${message.data.version}`;
@@ -119,6 +121,78 @@ const buildFlowReferencesByService = ({
119
121
  return flowRefsByService;
120
122
  };
121
123
 
124
+ const buildFlowReferencesByContainer = ({
125
+ flows,
126
+ containers,
127
+ }: {
128
+ flows: CollectionEntry<'flows'>[];
129
+ containers: CollectionEntry<'containers'>[];
130
+ }) => {
131
+ const containerMap = createVersionedMap(containers);
132
+ const flowRefsByContainer = new Map<string, string[]>();
133
+
134
+ const addFlowRef = (container: ContainerEntry, flow: CollectionEntry<'flows'>) => {
135
+ const containerKey = `container:${container.data.id}:${container.data.version}`;
136
+ const flowKey = `flow:${flow.data.id}:${flow.data.version}`;
137
+ flowRefsByContainer.set(containerKey, uniqueRefs([...(flowRefsByContainer.get(containerKey) || []), flowKey]));
138
+ };
139
+
140
+ for (const flow of flows) {
141
+ for (const step of flow.data.steps || []) {
142
+ if (!step.container) continue;
143
+
144
+ const hydratedContainer = Array.isArray(step.container) ? step.container[0] : undefined;
145
+ if (hydratedContainer?.collection && hydratedContainer?.data) {
146
+ addFlowRef(hydratedContainer as ContainerEntry, flow);
147
+ continue;
148
+ }
149
+
150
+ if (Array.isArray(step.container)) continue;
151
+
152
+ const container = findInMap(containerMap, step.container.id, step.container.version);
153
+ if (container) addFlowRef(container as ContainerEntry, flow);
154
+ }
155
+ }
156
+
157
+ return flowRefsByContainer;
158
+ };
159
+
160
+ const buildFlowReferencesByDataProduct = ({
161
+ flows,
162
+ dataProducts,
163
+ }: {
164
+ flows: CollectionEntry<'flows'>[];
165
+ dataProducts: CollectionEntry<'data-products'>[];
166
+ }) => {
167
+ const dataProductMap = createVersionedMap(dataProducts);
168
+ const flowRefsByDataProduct = new Map<string, string[]>();
169
+
170
+ const addFlowRef = (dataProduct: DataProductEntry, flow: CollectionEntry<'flows'>) => {
171
+ const dataProductKey = `data-product:${dataProduct.data.id}:${dataProduct.data.version}`;
172
+ const flowKey = `flow:${flow.data.id}:${flow.data.version}`;
173
+ flowRefsByDataProduct.set(dataProductKey, uniqueRefs([...(flowRefsByDataProduct.get(dataProductKey) || []), flowKey]));
174
+ };
175
+
176
+ for (const flow of flows) {
177
+ for (const step of flow.data.steps || []) {
178
+ if (!step.dataProduct) continue;
179
+
180
+ const hydratedDataProduct = Array.isArray(step.dataProduct) ? step.dataProduct[0] : undefined;
181
+ if (hydratedDataProduct?.collection && hydratedDataProduct?.data) {
182
+ addFlowRef(hydratedDataProduct as DataProductEntry, flow);
183
+ continue;
184
+ }
185
+
186
+ if (Array.isArray(step.dataProduct)) continue;
187
+
188
+ const dataProduct = findInMap(dataProductMap, step.dataProduct.id, step.dataProduct.version);
189
+ if (dataProduct) addFlowRef(dataProduct as DataProductEntry, flow);
190
+ }
191
+ }
192
+
193
+ return flowRefsByDataProduct;
194
+ };
195
+
122
196
  /**
123
197
  * Get the navigation data for the sidebar
124
198
  */
@@ -326,10 +400,12 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
326
400
  {} as Record<string, NavNode | string>
327
401
  );
328
402
 
403
+ const flowRefsByContainer = buildFlowReferencesByContainer({ flows, containers });
404
+
329
405
  const containerNodes = containerWithOwners.reduce(
330
406
  (acc, { container, owners }) => {
331
407
  const versionedKey = `container:${container.data.id}:${container.data.version}`;
332
- acc[versionedKey] = buildContainerNode(container, owners, context);
408
+ acc[versionedKey] = buildContainerNode(container, owners, context, flowRefsByContainer.get(versionedKey) || []);
333
409
  if (container.data.latestVersion === container.data.version) {
334
410
  // Store reference to versioned key instead of duplicating the full node
335
411
  acc[`container:${container.data.id}`] = versionedKey;
@@ -358,10 +434,17 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
358
434
  resourceDocCategories,
359
435
  };
360
436
 
437
+ const flowRefsByDataProduct = buildFlowReferencesByDataProduct({ flows, dataProducts });
438
+
361
439
  const dataProductNodes = dataProductWithOwners.reduce(
362
440
  (acc, { dataProduct, owners }) => {
363
441
  const versionedKey = `data-product:${dataProduct.data.id}:${dataProduct.data.version}`;
364
- acc[versionedKey] = buildDataProductNode(dataProduct, owners, dataProductContext);
442
+ acc[versionedKey] = buildDataProductNode(
443
+ dataProduct,
444
+ owners,
445
+ dataProductContext,
446
+ flowRefsByDataProduct.get(versionedKey) || []
447
+ );
365
448
  if (dataProduct.data.latestVersion === dataProduct.data.version) {
366
449
  acc[`data-product:${dataProduct.data.id}`] = versionedKey;
367
450
  }
@@ -24,11 +24,13 @@ export const getFlows = async ({ getAllVersions = true }: Props = {}): Promise<F
24
24
  }
25
25
 
26
26
  // 1. Fetch collections in parallel
27
- const [allFlows, allEvents, allCommands, allQueries] = await Promise.all([
27
+ const [allFlows, allEvents, allCommands, allQueries, allContainers, allDataProducts] = await Promise.all([
28
28
  getCollection('flows'),
29
29
  getCollection('events'),
30
30
  getCollection('commands'),
31
31
  getCollection('queries'),
32
+ getCollection('containers'),
33
+ getCollection('data-products'),
32
34
  ]);
33
35
 
34
36
  const allMessages = [...allEvents, ...allCommands, ...allQueries];
@@ -36,6 +38,8 @@ export const getFlows = async ({ getAllVersions = true }: Props = {}): Promise<F
36
38
  // 2. Build optimized maps
37
39
  const flowMap = createVersionedMap(allFlows);
38
40
  const messageMap = createVersionedMap(allMessages);
41
+ const containerMap = createVersionedMap(allContainers);
42
+ const dataProductMap = createVersionedMap(allDataProducts);
39
43
 
40
44
  // 3. Filter flows
41
45
  const targetFlows = allFlows.filter((flow) => {
@@ -54,6 +58,30 @@ export const getFlows = async ({ getAllVersions = true }: Props = {}): Promise<F
54
58
  const steps = flow.data.steps || [];
55
59
 
56
60
  const hydrateSteps = steps.map((step) => {
61
+ if (step.container) {
62
+ const pointer = step.container;
63
+ if (!pointer) return { ...step, type: 'node' };
64
+ const container = findInMap(containerMap, pointer.id, pointer.version);
65
+
66
+ return {
67
+ ...step,
68
+ type: 'container',
69
+ container: container ? [container] : [],
70
+ };
71
+ }
72
+
73
+ if (step.dataProduct) {
74
+ const pointer = step.dataProduct;
75
+ if (!pointer) return { ...step, type: 'node' };
76
+ const dataProduct = findInMap(dataProductMap, pointer.id, pointer.version);
77
+
78
+ return {
79
+ ...step,
80
+ type: 'data-products',
81
+ dataProduct: dataProduct ? [dataProduct] : [],
82
+ };
83
+ }
84
+
57
85
  if (!step.message) return { ...step, type: 'node' }; // Preserve existing step data for non-messages
58
86
 
59
87
  const message = findInMap(messageMap, step.message.id, step.message.version);
@@ -2,15 +2,15 @@
2
2
  // rarely used, but useful for components that need to know how many times
3
3
  // the user wants to render a component in a markdown file
4
4
  export const getMDXComponentsByName = (document: string, componentName: string) => {
5
- // Define regex pattern to match <SchemaViewer ... />
6
- const pattern = new RegExp(`<${componentName}\\s+([^>]*)\\/>`, 'g');
5
+ // Define regex pattern to match self-closing MDX components with or without props.
6
+ const pattern = new RegExp(`<${componentName}(\\s+[^>]*)?\\s*\\/>`, 'g');
7
7
 
8
8
  // Find all matches of the pattern
9
9
  const matches = [...document.matchAll(pattern)];
10
10
 
11
11
  // Extract the properties of each SchemaViewer
12
12
  const components = matches.map((match) => {
13
- const propsString = match[1];
13
+ const propsString = match[1] || '';
14
14
  const props = {};
15
15
 
16
16
  // Use regex to extract key-value pairs from propsString
@@ -28,3 +28,8 @@ export const getMDXComponentsByName = (document: string, componentName: string)
28
28
 
29
29
  return components;
30
30
  };
31
+
32
+ export const parseMdxBooleanProp = (value: unknown, defaultValue: boolean) => {
33
+ if (value === undefined) return defaultValue;
34
+ return value === true || value === 'true';
35
+ };
@@ -26,6 +26,8 @@ interface Maps {
26
26
  messageMap: Map<string, any[]>;
27
27
  serviceMap: Map<string, any[]>;
28
28
  flowMap: Map<string, any[]>;
29
+ containerMap: Map<string, any[]>;
30
+ dataProductMap: Map<string, any[]>;
29
31
  }
30
32
 
31
33
  const getServiceNode = (step: any, serviceMap: Map<string, any[]>) => {
@@ -46,6 +48,26 @@ const getFlowNode = (step: any, flowMap: Map<string, any[]>) => {
46
48
  };
47
49
  };
48
50
 
51
+ const getContainerNode = (step: any, containerMap: Map<string, any[]>) => {
52
+ const pointer = step.container;
53
+ const container = findInMap(containerMap, pointer.id, pointer.version);
54
+ return {
55
+ ...step,
56
+ type: container ? 'data' : 'step',
57
+ container,
58
+ };
59
+ };
60
+
61
+ const getDataProductNode = (step: any, dataProductMap: Map<string, any[]>) => {
62
+ const pointer = step.dataProduct;
63
+ const dataProduct = findInMap(dataProductMap, pointer.id, pointer.version);
64
+ return {
65
+ ...step,
66
+ type: dataProduct ? 'data-products' : 'step',
67
+ dataProduct,
68
+ };
69
+ };
70
+
49
71
  const getMessageNode = (step: any, messageMap: Map<string, any[]>) => {
50
72
  const message = findInMap(messageMap, step.message.id, step.message.version);
51
73
  return {
@@ -97,6 +119,8 @@ const buildFlowGraphInternal = (
97
119
  const hydratedSteps = steps.map((step: any) => {
98
120
  if (step.service) return getServiceNode(step, maps.serviceMap);
99
121
  if (step.flow) return getFlowNode(step, maps.flowMap);
122
+ if (step.container) return getContainerNode(step, maps.containerMap);
123
+ if (step.dataProduct) return getDataProductNode(step, maps.dataProductMap);
100
124
  if (step.message) return getMessageNode(step, maps.messageMap);
101
125
  if (step.actor) return { ...step, type: 'actor', actor: step.actor };
102
126
  if (step.custom) return { ...step, type: 'custom', custom: step.custom };
@@ -159,6 +183,23 @@ const buildFlowGraphInternal = (
159
183
  version: step.message.data.version,
160
184
  });
161
185
  }
186
+ if (step.container?.data) {
187
+ node.data.data = { ...step.container.data };
188
+ node.data.container = { ...step.container, ...step.container.data };
189
+ node.data.contextMenu = buildContextMenuForResource({
190
+ collection: 'containers',
191
+ id: step.container.data.id,
192
+ version: step.container.data.version,
193
+ });
194
+ }
195
+ if (step.dataProduct?.data) {
196
+ node.data.dataProduct = { ...step.dataProduct, ...step.dataProduct.data };
197
+ node.data.contextMenu = buildContextMenuForResource({
198
+ collection: 'data-products',
199
+ id: step.dataProduct.data.id,
200
+ version: step.dataProduct.data.version,
201
+ });
202
+ }
162
203
  if (step.actor) {
163
204
  node.data.actor = { ...step.actor, ...step.actor.data };
164
205
  node.data = { ...node.data, ...step.actor };
@@ -214,12 +255,14 @@ const buildFlowGraphInternal = (
214
255
  export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simple', renderAllEdges = false }: Props) => {
215
256
  const graph = defaultFlow || createDagreGraph({ ranksep: 360, nodesep: 200 });
216
257
 
217
- const [flows, events, commands, queries, services] = await Promise.all([
258
+ const [flows, events, commands, queries, services, containers, dataProducts] = await Promise.all([
218
259
  getCollection('flows'),
219
260
  getCollection('events'),
220
261
  getCollection('commands'),
221
262
  getCollection('queries'),
222
263
  getCollection('services'),
264
+ getCollection('containers'),
265
+ getCollection('data-products'),
223
266
  ]);
224
267
 
225
268
  const flow = flows.find((flow) => flow.data.id === id && flow.data.version === version);
@@ -236,6 +279,8 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
236
279
  messageMap: createVersionedMap(messages),
237
280
  serviceMap: createVersionedMap(services),
238
281
  flowMap: createVersionedMap(flows),
282
+ containerMap: createVersionedMap(containers),
283
+ dataProductMap: createVersionedMap(dataProducts),
239
284
  };
240
285
 
241
286
  const subFlowCache = new Map<string, { nodes: any[]; edges: any[] }>();
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "license": "SEE LICENSE IN LICENSE",
9
9
  "type": "module",
10
- "version": "3.36.2",
10
+ "version": "3.36.4",
11
11
  "publishConfig": {
12
12
  "access": "public"
13
13
  },
@@ -106,9 +106,9 @@
106
106
  "update-notifier": "^7.3.1",
107
107
  "uuid": "^10.0.0",
108
108
  "zod": "^4.3.6",
109
- "@eventcatalog/sdk": "2.21.0",
110
- "@eventcatalog/linter": "1.0.22",
111
- "@eventcatalog/visualiser": "^3.20.0"
109
+ "@eventcatalog/linter": "1.0.23",
110
+ "@eventcatalog/visualiser": "^3.20.3",
111
+ "@eventcatalog/sdk": "2.21.1"
112
112
  },
113
113
  "devDependencies": {
114
114
  "@astrojs/check": "^0.9.9",