@eventcatalog/core 4.10.2 → 4.10.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 (29) 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-SB2TMVVX.js → chunk-2SLBVVUZ.js} +1 -1
  6. package/dist/{chunk-C73V4K3S.js → chunk-322TAIDG.js} +1 -1
  7. package/dist/{chunk-E5JJSOMA.js → chunk-6S2ZIVEV.js} +1 -1
  8. package/dist/{chunk-MGK66RUH.js → chunk-S3J4N5ZP.js} +1 -1
  9. package/dist/{chunk-NOD5BM45.js → chunk-T5XTOY52.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/auth.config.ts +5 -0
  19. package/eventcatalog/src/components/MDX/ArchitectureGraph/ArchitectureGraph.astro +5 -5
  20. package/eventcatalog/src/components/MDX/ArchitectureGraph/ArchitectureGraphPortal.tsx +8 -7
  21. package/eventcatalog/src/components/MDX/ArchitectureGraph/AstroArchitectureGraph.tsx +8 -5
  22. package/eventcatalog/src/components/MDX/components.tsx +1 -12
  23. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +1 -2
  24. package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +23 -1
  25. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -2
  26. package/eventcatalog/src/pages/index.astro +1 -2
  27. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +10 -16
  28. package/eventcatalog/src/utils/mermaid-zoom.ts +38 -6
  29. package/package.json +3 -3
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(analytics_exports);
36
36
  var import_os = __toESM(require("os"), 1);
37
37
 
38
38
  // package.json
39
- var version = "4.10.2";
39
+ var version = "4.10.4";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-E5JJSOMA.js";
4
- import "../chunk-C73V4K3S.js";
3
+ } from "../chunk-6S2ZIVEV.js";
4
+ import "../chunk-322TAIDG.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -140,7 +140,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
140
140
  var import_os = __toESM(require("os"), 1);
141
141
 
142
142
  // package.json
143
- var version = "4.10.2";
143
+ var version = "4.10.4";
144
144
 
145
145
  // src/constants.ts
146
146
  var VERSION = version;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-SB2TMVVX.js";
4
- import "../chunk-E5JJSOMA.js";
3
+ } from "../chunk-2SLBVVUZ.js";
4
+ import "../chunk-6S2ZIVEV.js";
5
5
  import "../chunk-K2XIENVT.js";
6
- import "../chunk-C73V4K3S.js";
6
+ import "../chunk-322TAIDG.js";
7
7
  import "../chunk-6QENHZZP.js";
8
8
  export {
9
9
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-E5JJSOMA.js";
3
+ } from "./chunk-6S2ZIVEV.js";
4
4
  import {
5
5
  countResources,
6
6
  serializeCounts
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "4.10.2";
2
+ var version = "4.10.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-C73V4K3S.js";
3
+ } from "./chunk-322TAIDG.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import os from "os";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-NOD5BM45.js";
3
+ } from "./chunk-T5XTOY52.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-C73V4K3S.js";
3
+ } from "./chunk-322TAIDG.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 = "4.10.2";
28
+ var version = "4.10.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-C73V4K3S.js";
3
+ } from "./chunk-322TAIDG.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -144,7 +144,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
144
144
  var import_picocolors = __toESM(require("picocolors"), 1);
145
145
 
146
146
  // package.json
147
- var version = "4.10.2";
147
+ var version = "4.10.4";
148
148
 
149
149
  // src/constants.ts
150
150
  var VERSION = version;
@@ -4,8 +4,8 @@ import {
4
4
  import "./chunk-CA4U2JP7.js";
5
5
  import {
6
6
  log_build_default
7
- } from "./chunk-SB2TMVVX.js";
8
- import "./chunk-E5JJSOMA.js";
7
+ } from "./chunk-2SLBVVUZ.js";
8
+ import "./chunk-6S2ZIVEV.js";
9
9
  import "./chunk-K2XIENVT.js";
10
10
  import {
11
11
  FederationConflictError,
@@ -31,10 +31,10 @@ import {
31
31
  } from "./chunk-B7HCX5HM.js";
32
32
  import {
33
33
  generate
34
- } from "./chunk-MGK66RUH.js";
34
+ } from "./chunk-S3J4N5ZP.js";
35
35
  import {
36
36
  logger
37
- } from "./chunk-NOD5BM45.js";
37
+ } from "./chunk-T5XTOY52.js";
38
38
  import {
39
39
  resolve_catalog_dependencies_default
40
40
  } from "./chunk-LHR4G2UO.js";
@@ -54,7 +54,7 @@ import {
54
54
  import "./chunk-W5JQON7Z.js";
55
55
  import {
56
56
  VERSION
57
- } from "./chunk-C73V4K3S.js";
57
+ } from "./chunk-322TAIDG.js";
58
58
  import {
59
59
  linkCoreNodeModules,
60
60
  resolveInstalledCoreNodeModules
package/dist/generate.cjs CHANGED
@@ -108,7 +108,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
108
108
  var import_picocolors = __toESM(require("picocolors"), 1);
109
109
 
110
110
  // package.json
111
- var version = "4.10.2";
111
+ var version = "4.10.4";
112
112
 
113
113
  // src/constants.ts
114
114
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-MGK66RUH.js";
4
- import "./chunk-NOD5BM45.js";
5
- import "./chunk-C73V4K3S.js";
3
+ } from "./chunk-S3J4N5ZP.js";
4
+ import "./chunk-T5XTOY52.js";
5
+ import "./chunk-322TAIDG.js";
6
6
  import "./chunk-6QENHZZP.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 = "4.10.2";
39
+ var version = "4.10.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-NOD5BM45.js";
4
- import "../chunk-C73V4K3S.js";
3
+ } from "../chunk-T5XTOY52.js";
4
+ import "../chunk-322TAIDG.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -22,8 +22,13 @@ const getAuthProviders = async () => {
22
22
  // GitHub provider
23
23
  if (authConfig.providers?.github) {
24
24
  const githubConfig = authConfig.providers.github;
25
+ // GitHub sends an RFC 9207 `iss` parameter on OAuth callbacks. Pin the issuer so
26
+ // validation works even when the resolved @auth/core copy predates the upstream
27
+ // default (auth-astro's peer range can hoist an older @auth/core in user projects).
28
+ const githubBaseUrl = githubConfig?.enterprise?.baseUrl ?? 'https://github.com';
25
29
  providers.push(
26
30
  GitHub({
31
+ issuer: `${githubBaseUrl}/login/oauth`,
27
32
  ...githubConfig,
28
33
  })
29
34
  );
@@ -15,9 +15,9 @@ interface Props {
15
15
  showLegend?: boolean;
16
16
  /** Off by default — embedded graphs pin a lens rather than offer the picker */
17
17
  showLensPicker?: boolean;
18
- // Override the DOM portal the graph mounts into. Defaults to
19
- // `${id}-architecture-graph-portal` (or `catalog-architecture-graph-portal`).
20
- portalId?: string;
18
+ // Position of this embed among the page's <ArchitectureGraph/> tags pairs
19
+ // the island with its placeholder div by document order.
20
+ occurrenceIndex?: number;
21
21
  href?: {
22
22
  label: string;
23
23
  url: string;
@@ -32,7 +32,7 @@ const {
32
32
  showSearch = true,
33
33
  showLegend = true,
34
34
  showLensPicker = false,
35
- portalId,
35
+ occurrenceIndex = 0,
36
36
  href,
37
37
  } = Astro.props;
38
38
 
@@ -47,7 +47,7 @@ const focusKey =
47
47
 
48
48
  <AstroArchitectureGraph
49
49
  client:only="react"
50
- portalId={portalId ?? `${id ?? 'catalog'}-architecture-graph-portal`}
50
+ occurrenceIndex={occurrenceIndex}
51
51
  nodes={wire.nodes}
52
52
  links={wire.links}
53
53
  linkLabels={wire.linkLabels}
@@ -1,17 +1,18 @@
1
- // The portal id pairs each scanner-rendered island with its MDX placeholder.
2
- // The occurrence index keeps multiple no-id embeds on one page from colliding
3
- // (the first occurrence keeps the unsuffixed id).
4
- export const architectureGraphPortalId = (id: string | undefined, occurrenceIndex: number) =>
5
- `${id ?? 'catalog'}-architecture-graph-portal${occurrenceIndex > 0 ? `-${occurrenceIndex}` : ''}`;
1
+ // Placeholders are matched to their islands positionally (nth placeholder in
2
+ // document order nth <ArchitectureGraph/> tag in the host page's body scan).
3
+ // The pairing must not rely on a render-time counter in the element id — Astro
4
+ // can invoke MDX component functions more than once per tag (renderer probing),
5
+ // which drifts such a counter out of sync with the body scan.
6
+ export const ARCHITECTURE_GRAPH_PORTAL_SELECTOR = '[data-architecture-graph-portal]';
6
7
 
7
8
  // Empty placeholder rendered by the MDX component map. The real graph is
8
9
  // rendered by ArchitectureGraph.astro (which builds the data server-side) and
9
- // portals itself into this div by id — same pattern as NodeGraphPortal.
10
+ // portals itself into this div — same pattern as NodeGraphPortal.
10
11
  const ArchitectureGraphPortal = (props: any) => {
11
12
  return (
12
13
  <div
13
14
  className="not-prose h-[30em] my-6 mb-12 w-full relative border! border-[rgb(var(--ec-page-border))]! rounded-md overflow-hidden"
14
- id={architectureGraphPortalId(props.id, props.occurrenceIndex ?? 0)}
15
+ data-architecture-graph-portal={props.id ?? 'catalog'}
15
16
  style={{
16
17
  maxHeight: props.maxHeight ? `${props.maxHeight}em` : `30em`,
17
18
  }}
@@ -1,11 +1,13 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
  import CatalogForceGraph from '@components/CatalogGraph/CatalogForceGraph';
4
+ import { ARCHITECTURE_GRAPH_PORTAL_SELECTOR } from '@components/MDX/ArchitectureGraph/ArchitectureGraphPortal';
4
5
  import type { CatalogGraphWireLink, CatalogGraphWireNode } from '@utils/node-graphs/catalog-force-graph';
5
6
 
6
7
  interface Props {
7
- /** DOM id of the placeholder div ArchitectureGraphPortal rendered into the MDX content */
8
- portalId: string;
8
+ /** Position of this island among the page's <ArchitectureGraph/> embeds it
9
+ * mounts into the placeholder div at the same position in document order */
10
+ occurrenceIndex?: number;
9
11
  nodes: CatalogGraphWireNode[];
10
12
  links: CatalogGraphWireLink[];
11
13
  linkLabels: string[];
@@ -24,12 +26,13 @@ interface Props {
24
26
  // The island mounts outside the MDX content, finds the placeholder div the MDX
25
27
  // component map emitted, and portals the graph into it — same pattern as the
26
28
  // visualiser's NodeGraph.
27
- const AstroArchitectureGraph = ({ portalId, href, hrefLabel, ...graphProps }: Props) => {
29
+ const AstroArchitectureGraph = ({ occurrenceIndex = 0, href, hrefLabel, ...graphProps }: Props) => {
28
30
  const [container, setContainer] = useState<HTMLElement | null>(null);
29
31
 
30
32
  useEffect(() => {
31
- setContainer(document.getElementById(portalId));
32
- }, [portalId]);
33
+ const portals = document.querySelectorAll<HTMLElement>(ARCHITECTURE_GRAPH_PORTAL_SELECTOR);
34
+ setContainer(portals[occurrenceIndex] ?? null);
35
+ }, [occurrenceIndex]);
33
36
 
34
37
  if (!container) return null;
35
38
 
@@ -51,10 +51,6 @@ const getEntityMapCollection = (props: any, mdxProp: any) => {
51
51
  };
52
52
 
53
53
  const components = (props: any) => {
54
- // Occurrence counter so multiple <ArchitectureGraph/> tags on one page each get
55
- // their own portal — MDX renders in document order, matching the body scan order
56
- // the host pages use to render the islands.
57
- let architectureGraphOccurrence = 0;
58
54
  return {
59
55
  Attachments: (mdxProp: any) => jsx(Attachments, { ...props, ...mdxProp }),
60
56
  CustomProperties: (mdxProp: any) => jsx(CustomProperties, { ...props, ...mdxProp }),
@@ -74,14 +70,7 @@ const components = (props: any) => {
74
70
  ADRTable: (mdxProp: any) => jsx(ADRTable, { ...props, ...mdxProp }),
75
71
  EntityPropertiesTable: (mdxProp: any) => jsx(EntityPropertiesTable, { ...props, ...mdxProp }),
76
72
  NodeGraph: (mdxProp: any) => jsx(NodeGraphPortal, { ...props.data, ...mdxProp, props, mdxProp }),
77
- ArchitectureGraph: (mdxProp: any) =>
78
- jsx(ArchitectureGraphPortal, {
79
- ...props.data,
80
- ...mdxProp,
81
- occurrenceIndex: architectureGraphOccurrence++,
82
- props,
83
- mdxProp,
84
- }),
73
+ ArchitectureGraph: (mdxProp: any) => jsx(ArchitectureGraphPortal, { ...props.data, ...mdxProp, props, mdxProp }),
85
74
  ComponentDiagram: (mdxProp: any) => jsx(NodeGraphPortal, { ...props.data, ...mdxProp, props, mdxProp }),
86
75
  ContextDiagram: (mdxProp: any) => jsx(ContextDiagramPortal, { ...props.data, ...mdxProp, props, mdxProp }),
87
76
  SystemContextMap: (mdxProp: any) => jsx(SystemContextMapPortal, { ...mdxProp }),
@@ -15,7 +15,6 @@ import { getAdjacentPages, getNavigationItems } from '@enterprise/custom-documen
15
15
  import CustomDocsNav from '@enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro';
16
16
  import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
17
17
  import ArchitectureGraph from '@components/MDX/ArchitectureGraph/ArchitectureGraph.astro';
18
- import { architectureGraphPortalId } from '@components/MDX/ArchitectureGraph/ArchitectureGraphPortal';
19
18
  import CopyAsMarkdown from '@components/CopyAsMarkdown';
20
19
 
21
20
  import {
@@ -202,7 +201,7 @@ const editUrl =
202
201
  showSearch={graph.search}
203
202
  showLegend={graph.legend}
204
203
  showLensPicker={graph.lensPicker}
205
- portalId={architectureGraphPortalId(graph.id ?? (doc as any).id, occurrenceIndex)}
204
+ occurrenceIndex={occurrenceIndex}
206
205
  href={
207
206
  isArchitectureGraphEnabled()
208
207
  ? {
@@ -567,9 +567,31 @@ const diagramId = props.data.id;
567
567
  const graphs = document.getElementsByClassName('mermaid');
568
568
  if (graphs.length === 0) return;
569
569
 
570
- const { default: mermaid } = await import('https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs');
570
+ const { default: mermaid } = await import('https://cdn.jsdelivr.net/npm/mermaid@11.16.1/dist/mermaid.esm.min.mjs');
571
571
  const isDarkMode = document.documentElement.getAttribute('data-theme') === 'dark';
572
572
 
573
+ const iconPacks = window.eventcatalog?.mermaid?.iconPacks || [];
574
+ if (iconPacks.length > 0) {
575
+ mermaid.registerIconPacks(
576
+ iconPacks.map((name) => ({
577
+ name,
578
+ loader: () =>
579
+ fetch(`https://cdn.jsdelivr.net/npm/@iconify-json/${name}@1/icons.json`)
580
+ .then((res) => {
581
+ if (!res.ok) {
582
+ console.error(`[EventCatalog] Failed to load icon pack "${name}" from CDN (HTTP ${res.status})`);
583
+ return null;
584
+ }
585
+ return res.json();
586
+ })
587
+ .catch((err) => {
588
+ console.error(`[EventCatalog] Error loading icon pack "${name}":`, err);
589
+ return null;
590
+ }),
591
+ }))
592
+ );
593
+ }
594
+
573
595
  mermaid.initialize({
574
596
  maxTextSize: window.eventcatalog?.mermaid?.maxTextSize || 100000,
575
597
  startOnLoad: false,
@@ -11,7 +11,6 @@ import Footer from '@layouts/Footer.astro';
11
11
  import components from '@components/MDX/components';
12
12
  import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
13
13
  import ArchitectureGraph from '@components/MDX/ArchitectureGraph/ArchitectureGraph.astro';
14
- import { architectureGraphPortalId } from '@components/MDX/ArchitectureGraph/ArchitectureGraphPortal';
15
14
  import SchemaViewer from '@components/MDX/SchemaViewer/SchemaViewerRoot.astro';
16
15
  import Admonition from '@components/MDX/Admonition';
17
16
  import VersionList from '@components/Lists/VersionList.astro';
@@ -681,7 +680,7 @@ if (!isAdrPage && !hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
681
680
  showSearch={graph.search}
682
681
  showLegend={graph.legend}
683
682
  showLensPicker={graph.lensPicker}
684
- portalId={architectureGraphPortalId(graph.id, occurrenceIndex)}
683
+ occurrenceIndex={occurrenceIndex}
685
684
  href={
686
685
  isArchitectureGraphEnabled()
687
686
  ? {
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
3
3
  import { getMDXComponentsByName, parseMdxBooleanProp } from '@utils/markdown';
4
- import { architectureGraphPortalId } from '@components/MDX/ArchitectureGraph/ArchitectureGraphPortal';
5
4
  import { resourceToCollectionMap } from '@utils/collections/util';
6
5
  import { buildUrl } from '@utils/url-builder';
7
6
  import { isCustomLandingPageEnabled, isVisualiserEnabled, isArchitectureGraphEnabled } from '@utils/feature';
@@ -125,7 +124,7 @@ if (config.landingPage) {
125
124
  showSearch={parseMdxBooleanProp(graph.search, true)}
126
125
  showLegend={parseMdxBooleanProp(graph.legend, true)}
127
126
  showLensPicker={parseMdxBooleanProp(graph.lensPicker, false)}
128
- portalId={architectureGraphPortalId(graph.id, occurrenceIndex)}
127
+ occurrenceIndex={occurrenceIndex}
129
128
  href={
130
129
  isArchitectureGraphEnabled()
131
130
  ? {
@@ -1,26 +1,21 @@
1
1
  import { HybridPage } from '@utils/page-loaders/hybrid-page';
2
2
  import { isAuthEnabled, isVisualiserEnabled } from '@utils/feature';
3
3
  import { getDomains } from '@utils/collections/domains';
4
- import { getSystems } from '@utils/collections/systems';
5
4
 
6
5
  /**
7
6
  * A domain gets a System Diagram when it has systems and at least one of those
8
7
  * systems takes part in a context graph — i.e. it declares relationships or actors. A
9
8
  * domain whose systems have neither has nothing to show, so we don't generate a page.
9
+ * `getDomains` hydrates `data.systems` into full system entries, so read each
10
+ * system's data directly — this must stay in sync with the sidebar's
11
+ * `hasSystemContext` guard so we never link to a page that wasn't generated.
10
12
  */
11
- const domainHasSystemContext = (
12
- domain: Awaited<ReturnType<typeof getDomains>>[number],
13
- systemMap: Map<string, { data: { relationships?: unknown[]; actors?: unknown[] } }>
14
- ) => {
15
- const systemRefs = (domain.data.systems || []) as { id: string }[];
16
- if (systemRefs.length === 0) return false;
13
+ const domainHasSystemContext = (domain: Awaited<ReturnType<typeof getDomains>>[number]) => {
14
+ const systems = (domain.data.systems || []) as any[];
17
15
 
18
- return systemRefs.some((ref) => {
19
- const system = systemMap.get(ref.id);
20
- if (!system) return false;
21
- const relationships = (system.data.relationships || []) as unknown[];
22
- const actors = (system.data.actors || []) as unknown[];
23
- return relationships.length > 0 || actors.length > 0;
16
+ return systems.some((system) => {
17
+ const data = system?.data ?? system;
18
+ return ((data?.relationships as unknown[]) || []).length > 0 || ((data?.actors as unknown[]) || []).length > 0;
24
19
  });
25
20
  };
26
21
 
@@ -30,11 +25,10 @@ export class Page extends HybridPage {
30
25
  return [];
31
26
  }
32
27
 
33
- const [domains, systems] = await Promise.all([getDomains({ getAllVersions: false }), getSystems()]);
34
- const systemMap = new Map(systems.map((system) => [system.data.id, system]));
28
+ const domains = await getDomains({ getAllVersions: false });
35
29
 
36
30
  return domains
37
- .filter((domain) => domainHasSystemContext(domain, systemMap))
31
+ .filter((domain) => domainHasSystemContext(domain))
38
32
  .map((domain) => ({
39
33
  params: {
40
34
  id: domain.data.id,
@@ -14,6 +14,9 @@ const zoomInstances = new Map<string, any>();
14
14
  const resizeObservers = new Map<string, ResizeObserver>();
15
15
  const fullscreenHandlers = new Map<string, () => void>();
16
16
 
17
+ // Track registered icon pack names to avoid re-registering on subsequent renders
18
+ const registeredIconPacks = new Set<string>();
19
+
17
20
  // Abort flag for cancelling in-progress renders during cleanup
18
21
  let renderingAborted = false;
19
22
 
@@ -550,6 +553,35 @@ export async function initMermaidZoom(
550
553
  }
551
554
  }
552
555
 
556
+ /**
557
+ * Builds the mermaid `registerIconPacks` descriptor array for a list of Iconify pack names.
558
+ *
559
+ * - `logos` is resolved from the bundled `@iconify-json/logos` package (no network request).
560
+ * - Every other name is fetched lazily from jsDelivr so only the packs that are actually used
561
+ * in a diagram trigger a network request.
562
+ */
563
+ export function buildIconPackDescriptors(iconPacks: string[]): Array<{ name: string; loader: () => Promise<any> }> {
564
+ return iconPacks.map((name) => ({
565
+ name,
566
+ loader:
567
+ name === 'logos'
568
+ ? () => import('@iconify-json/logos').then((m) => m.icons)
569
+ : () =>
570
+ fetch(`https://cdn.jsdelivr.net/npm/@iconify-json/${name}@1/icons.json`)
571
+ .then((res) => {
572
+ if (!res.ok) {
573
+ console.error(`[EventCatalog] Failed to load icon pack "${name}" from CDN (HTTP ${res.status})`);
574
+ return null;
575
+ }
576
+ return res.json();
577
+ })
578
+ .catch((err) => {
579
+ console.error(`[EventCatalog] Error loading icon pack "${name}":`, err);
580
+ return null;
581
+ }),
582
+ }));
583
+ }
584
+
553
585
  /**
554
586
  * High-level function to render Mermaid diagrams with zoom
555
587
  */
@@ -563,15 +595,15 @@ export async function renderMermaidWithZoom(graphs: HTMLCollectionOf<Element>, m
563
595
 
564
596
  // Apply any custom mermaid configuration
565
597
  if (mermaidConfig) {
566
- const { icons } = await import('@iconify-json/logos');
567
598
  const { iconPacks = [], enableSupportForElkLayout = false } = mermaidConfig;
568
599
 
569
600
  if (iconPacks.length > 0) {
570
- const iconPacksToRegister = iconPacks.map((name: string) => ({
571
- name,
572
- icons,
573
- }));
574
- mermaid.registerIconPacks(iconPacksToRegister);
601
+ const newPacks: string[] = (iconPacks as string[]).filter((name: string) => !registeredIconPacks.has(name));
602
+
603
+ if (newPacks.length > 0) {
604
+ mermaid.registerIconPacks(buildIconPackDescriptors(newPacks));
605
+ newPacks.forEach((name: string) => registeredIconPacks.add(name));
606
+ }
575
607
  }
576
608
 
577
609
  if (enableSupportForElkLayout) {
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.2",
10
+ "version": "4.10.4",
11
11
  "publishConfig": {
12
12
  "access": "public"
13
13
  },
@@ -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/linter": "1.1.17",
123
122
  "@eventcatalog/sdk": "2.28.1",
124
- "@eventcatalog/visualiser": "^4.1.3"
123
+ "@eventcatalog/visualiser": "^4.1.3",
124
+ "@eventcatalog/linter": "1.1.17"
125
125
  },
126
126
  "devDependencies": {
127
127
  "@astrojs/check": "^0.9.10",