@eventcatalog/core 5.0.0-beta.12 → 5.0.0-beta.14

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 (90) hide show
  1. package/LICENSE +13 -12
  2. package/dist/analytics/analytics.cjs +1 -1
  3. package/dist/analytics/analytics.js +2 -2
  4. package/dist/analytics/log-build.cjs +1 -1
  5. package/dist/analytics/log-build.js +3 -3
  6. package/dist/catalog-runtime.cjs +1 -1
  7. package/dist/{chunk-TSY5CC27.js → chunk-4KE3EUDJ.js} +1 -1
  8. package/dist/{chunk-FY6MSP6J.js → chunk-I3XDOICA.js} +1 -1
  9. package/dist/{chunk-QB7X34OD.js → chunk-OFK7U7BX.js} +1 -1
  10. package/dist/{chunk-CX2VB7AI.js → chunk-PI5YNZZZ.js} +1 -1
  11. package/dist/{chunk-BWC4YKW3.js → chunk-WY6M3RPT.js} +1 -1
  12. package/dist/constants.cjs +1 -1
  13. package/dist/constants.js +1 -1
  14. package/dist/eventcatalog.cjs +11 -6
  15. package/dist/eventcatalog.js +14 -9
  16. package/dist/generate.cjs +1 -1
  17. package/dist/generate.js +3 -3
  18. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
  19. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
  20. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
  21. package/dist/runtime-dependencies/manifest.json +3 -0
  22. package/dist/utils/cli-logger.cjs +1 -1
  23. package/dist/utils/cli-logger.js +2 -2
  24. package/eventcatalog/astro.config.mjs +13 -1
  25. package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
  26. package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
  27. package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
  28. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +11 -3
  29. package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
  30. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +37 -76
  31. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
  32. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +122 -1
  33. package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
  34. package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +3 -3
  35. package/eventcatalog/src/features/mcp/apps/canvas/styles.css +3 -1
  36. package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +7 -5
  37. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +133 -71
  38. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +66 -66
  39. package/eventcatalog/src/features/studio/agent-choreography.ts +5 -4
  40. package/eventcatalog/src/features/studio/agents.ts +28 -0
  41. package/eventcatalog/src/features/studio/api/canvases-api.ts +1 -1
  42. package/eventcatalog/src/features/studio/canvas-actions.ts +22 -14
  43. package/eventcatalog/src/features/studio/canvas-preview.ts +1 -2
  44. package/eventcatalog/src/features/studio/catalog.ts +1 -4
  45. package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +246 -115
  46. package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +7 -3
  47. package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +272 -119
  48. package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +1 -2
  49. package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +1 -1
  50. package/eventcatalog/src/features/studio/components/JoinForm.tsx +101 -26
  51. package/eventcatalog/src/features/studio/components/LeftPanel.tsx +102 -241
  52. package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
  53. package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +1 -1
  54. package/eventcatalog/src/features/studio/components/Presence.tsx +6 -8
  55. package/eventcatalog/src/features/studio/components/ShareDialog.tsx +277 -141
  56. package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
  57. package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +1005 -354
  58. package/eventcatalog/src/features/studio/document-name.ts +7 -0
  59. package/eventcatalog/src/features/studio/from-visualiser.ts +1 -1
  60. package/eventcatalog/src/features/studio/hooks/presence-sender.ts +19 -2
  61. package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +9 -3
  62. package/eventcatalog/src/features/studio/hooks/use-comments.ts +2 -2
  63. package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +162 -23
  64. package/eventcatalog/src/features/studio/identity.ts +23 -1
  65. package/eventcatalog/src/features/studio/pages/[id].astro +2 -1
  66. package/eventcatalog/src/features/studio/pages/index.astro +1 -2
  67. package/eventcatalog/src/features/studio/server/canvas-mcp.ts +7 -22
  68. package/eventcatalog/src/features/studio/server/runtime.ts +4 -5
  69. package/package.json +3 -3
  70. package/eventcatalog/src/features/studio/canvas-doc.ts +0 -569
  71. package/eventcatalog/src/features/studio/clipboard.ts +0 -97
  72. package/eventcatalog/src/features/studio/components/CanvasControls.tsx +0 -119
  73. package/eventcatalog/src/features/studio/components/Comments.tsx +0 -777
  74. package/eventcatalog/src/features/studio/components/ContainerChooser.tsx +0 -145
  75. package/eventcatalog/src/features/studio/components/DragGhost.tsx +0 -115
  76. package/eventcatalog/src/features/studio/components/Picture.tsx +0 -21
  77. package/eventcatalog/src/features/studio/components/PropertiesPanel.tsx +0 -212
  78. package/eventcatalog/src/features/studio/components/canvas-nodes.tsx +0 -271
  79. package/eventcatalog/src/features/studio/components/icons.ts +0 -53
  80. package/eventcatalog/src/features/studio/components/status.ts +0 -53
  81. package/eventcatalog/src/features/studio/edges.ts +0 -56
  82. package/eventcatalog/src/features/studio/flow-state.ts +0 -121
  83. package/eventcatalog/src/features/studio/grouping.ts +0 -230
  84. package/eventcatalog/src/features/studio/hooks/use-counter-scale.ts +0 -20
  85. package/eventcatalog/src/features/studio/layout.ts +0 -56
  86. package/eventcatalog/src/features/studio/level-layout.ts +0 -145
  87. package/eventcatalog/src/features/studio/levels.ts +0 -337
  88. package/eventcatalog/src/features/studio/node-types.ts +0 -245
  89. package/eventcatalog/src/features/studio/placement.ts +0 -197
  90. package/eventcatalog/src/features/studio/studio.css +0 -273
package/LICENSE CHANGED
@@ -17,13 +17,13 @@ Licensed Work: EventCatalog version 5.0 or later, including pre-releases,
17
17
  and the examples directory. The Licensed Work is (c) 2026
18
18
  EventCatalog Ltd.
19
19
  Additional Use Grant: You may make Production use of the Licensed Work if You
20
- are an Eligible User and Your use is not a Hosted
20
+ qualify for Free Use and Your use is not a Hosted
21
21
  Offering. Sections 1 to 7 below form part of this grant.
22
22
  Capitalised terms are defined in section 6.
23
23
 
24
- 1. Eligible Users
24
+ 1. Free Use
25
25
 
26
- You are an "Eligible User" if You are:
26
+ You qualify for "Free Use" if You are:
27
27
 
28
28
  (a) an individual using the Licensed Work for Your own
29
29
  personal purposes, and not for or on behalf of any
@@ -47,9 +47,9 @@ Additional Use Grant: You may make Production use of the Licensed Work if You
47
47
 
48
48
  2. Growing past the thresholds
49
49
 
50
- An Organisation that is an Eligible User under 1(b)
51
- remains one until ninety (90) days after the first of the
52
- following to happen:
50
+ An Organisation that qualifies for Free Use under 1(b)
51
+ continues to qualify until ninety (90) days after the
52
+ first of the following to happen:
53
53
 
54
54
  (a) the end of the first financial year in which its
55
55
  Annual Revenue reaches USD 10,000,000; or
@@ -68,7 +68,7 @@ Additional Use Grant: You may make Production use of the Licensed Work if You
68
68
  vendor), including building, customising, hosting or
69
69
  distributing the Licensed Work or a catalog built with it
70
70
  for that client, Your use for that client is permitted if
71
- the client is an Eligible User or holds a Commercial
71
+ the client qualifies for Free Use or holds a Commercial
72
72
  License covering that use. You may rely on a client's
73
73
  written statement of its status unless You know it is
74
74
  wrong. Your own use of the Licensed Work for Your own
@@ -76,7 +76,7 @@ Additional Use Grant: You may make Production use of the Licensed Work if You
76
76
 
77
77
  4. Coming into compliance
78
78
 
79
- (a) If You stop being an Eligible User (for example
79
+ (a) If You stop qualifying for Free Use (for example
80
80
  because Your Evaluation Period ends), or You become
81
81
  aware (including by notice from the Licensor) that
82
82
  Your Production use is not permitted by this grant,
@@ -219,7 +219,8 @@ Additional Use Grant: You may make Production use of the Licensed Work if You
219
219
  Public Open Source Projects.
220
220
 
221
221
  "Commercial License" means a written license from the
222
- Licensor permitting Production use beyond this grant.
222
+ Licensor, including one accepted online, permitting
223
+ Production use beyond this grant.
223
224
 
224
225
  7. Everything else
225
226
 
@@ -230,9 +231,9 @@ Additional Use Grant: You may make Production use of the Licensed Work if You
230
231
  Work. The content of Your own catalog (the documentation,
231
232
  schemas, diagrams and configuration You create) is Yours
232
233
  and is not part of the Licensed Work.
233
- Change Date: Four years after the first public release, including any
234
- pre-release, of any release in the same release series as
235
- the Licensed Work.
234
+ Change Date: Four years after the first public release (including any
235
+ pre-release) in the same release series as the Licensed
236
+ Work.
236
237
 
237
238
  A "release series" is every release that shares the same
238
239
  major and minor release number, including its pre-releases
@@ -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 = "5.0.0-beta.12";
39
+ var version = "5.0.0-beta.14";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-CX2VB7AI.js";
3
+ } from "../chunk-PI5YNZZZ.js";
4
4
  import "../chunk-CPW6G62V.js";
5
- import "../chunk-FY6MSP6J.js";
5
+ import "../chunk-I3XDOICA.js";
6
6
  export {
7
7
  raiseEvent
8
8
  };
@@ -176,7 +176,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
176
176
  var import_os = __toESM(require("os"), 1);
177
177
 
178
178
  // package.json
179
- var version = "5.0.0-beta.12";
179
+ var version = "5.0.0-beta.14";
180
180
 
181
181
  // src/constants.ts
182
182
  var VERSION = version;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-BWC4YKW3.js";
3
+ } from "../chunk-WY6M3RPT.js";
4
4
  import "../chunk-AWOO63ME.js";
5
5
  import "../chunk-ZAZHAVKB.js";
6
- import "../chunk-CX2VB7AI.js";
6
+ import "../chunk-PI5YNZZZ.js";
7
7
  import "../chunk-CPW6G62V.js";
8
- import "../chunk-FY6MSP6J.js";
8
+ import "../chunk-I3XDOICA.js";
9
9
  import "../chunk-RFIXKATC.js";
10
10
  export {
11
11
  log_build_default as default
@@ -36,7 +36,7 @@ __export(catalog_runtime_exports, {
36
36
  });
37
37
  module.exports = __toCommonJS(catalog_runtime_exports);
38
38
 
39
- // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.15_tsx@4.21.0_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
39
+ // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.29_tsx@4.23.15_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
40
40
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
41
41
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
42
42
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-QB7X34OD.js";
3
+ } from "./chunk-OFK7U7BX.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "5.0.0-beta.12";
2
+ var version = "5.0.0-beta.14";
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-FY6MSP6J.js";
3
+ } from "./chunk-I3XDOICA.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-CPW6G62V.js";
5
5
  import {
6
6
  VERSION
7
- } from "./chunk-FY6MSP6J.js";
7
+ } from "./chunk-I3XDOICA.js";
8
8
 
9
9
  // src/analytics/analytics.js
10
10
  import os from "os";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-ZAZHAVKB.js";
9
9
  import {
10
10
  raiseEvent
11
- } from "./chunk-CX2VB7AI.js";
11
+ } from "./chunk-PI5YNZZZ.js";
12
12
  import {
13
13
  TELEMETRY_REQUEST_TIMEOUT_MS,
14
14
  isTelemetryDisabled
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "5.0.0-beta.12";
28
+ var version = "5.0.0-beta.14";
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-FY6MSP6J.js";
3
+ } from "./chunk-I3XDOICA.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
 
25
- // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.15_tsx@4.21.0_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
25
+ // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.29_tsx@4.23.15_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
26
26
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
27
27
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
28
28
 
@@ -181,7 +181,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
181
181
  var import_picocolors = __toESM(require("picocolors"), 1);
182
182
 
183
183
  // package.json
184
- var version = "5.0.0-beta.12";
184
+ var version = "5.0.0-beta.14";
185
185
 
186
186
  // src/constants.ts
187
187
  var VERSION = version;
@@ -2980,7 +2980,7 @@ var resolveDevPort = async ({ projectDir }) => {
2980
2980
  };
2981
2981
  var startDevPrewarm = ({
2982
2982
  port = 3e3,
2983
- paths = ["/ping", "/"],
2983
+ paths = ["/"],
2984
2984
  retries = 80,
2985
2985
  intervalMs = 250,
2986
2986
  initialDelayMs = 500
@@ -2989,10 +2989,13 @@ var startDevPrewarm = ({
2989
2989
  const hit = (requestPath) => new Promise((resolve2) => {
2990
2990
  const req = import_node_http.default.get(
2991
2991
  {
2992
- hostname: "127.0.0.1",
2992
+ // Not 127.0.0.1: the dev server can listen on IPv6 only ([::1]), which refused
2993
+ // every prewarm request
2994
+ hostname: "localhost",
2993
2995
  port,
2994
2996
  path: requestPath,
2995
- timeout: 1200
2997
+ // A refused connection fails at once; once connected, let the first render finish
2998
+ timeout: 3e4
2996
2999
  },
2997
3000
  (res) => {
2998
3001
  res.resume();
@@ -3251,7 +3254,9 @@ program.command("dev").description("Run development server of EventCatalog").opt
3251
3254
  });
3252
3255
  startDevPrewarm({
3253
3256
  port: prewarmPort,
3254
- paths: ["/ping", "/"]
3257
+ // Renders the homepage before anyone opens it. Requests stop at the first response,
3258
+ // so a probe path like /ping first would leave the homepage cold.
3259
+ paths: ["/"]
3255
3260
  });
3256
3261
  }
3257
3262
  await runCommandWithFilteredOutput({
@@ -4,7 +4,7 @@ import {
4
4
  import "./chunk-CA4U2JP7.js";
5
5
  import {
6
6
  log_build_default
7
- } from "./chunk-BWC4YKW3.js";
7
+ } from "./chunk-WY6M3RPT.js";
8
8
  import {
9
9
  getLicenseStatus,
10
10
  printLicenseStatus
@@ -33,10 +33,10 @@ import {
33
33
  } from "./chunk-MDWB5HLO.js";
34
34
  import {
35
35
  generate
36
- } from "./chunk-TSY5CC27.js";
36
+ } from "./chunk-4KE3EUDJ.js";
37
37
  import {
38
38
  logger
39
- } from "./chunk-QB7X34OD.js";
39
+ } from "./chunk-OFK7U7BX.js";
40
40
  import {
41
41
  resolve_catalog_dependencies_default
42
42
  } from "./chunk-36RYTYT5.js";
@@ -50,7 +50,7 @@ import {
50
50
  import {
51
51
  watch
52
52
  } from "./chunk-U63GDPPY.js";
53
- import "./chunk-CX2VB7AI.js";
53
+ import "./chunk-PI5YNZZZ.js";
54
54
  import "./chunk-CPW6G62V.js";
55
55
  import {
56
56
  getAstroConfigPath
@@ -67,7 +67,7 @@ import {
67
67
  } from "./chunk-LFQJXLHG.js";
68
68
  import {
69
69
  VERSION
70
- } from "./chunk-FY6MSP6J.js";
70
+ } from "./chunk-I3XDOICA.js";
71
71
  import {
72
72
  getEventCatalogConfigFile,
73
73
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -669,7 +669,7 @@ var resolveDevPort = async ({ projectDir }) => {
669
669
  };
670
670
  var startDevPrewarm = ({
671
671
  port = 3e3,
672
- paths = ["/ping", "/"],
672
+ paths = ["/"],
673
673
  retries = 80,
674
674
  intervalMs = 250,
675
675
  initialDelayMs = 500
@@ -678,10 +678,13 @@ var startDevPrewarm = ({
678
678
  const hit = (requestPath) => new Promise((resolve) => {
679
679
  const req = http.get(
680
680
  {
681
- hostname: "127.0.0.1",
681
+ // Not 127.0.0.1: the dev server can listen on IPv6 only ([::1]), which refused
682
+ // every prewarm request
683
+ hostname: "localhost",
682
684
  port,
683
685
  path: requestPath,
684
- timeout: 1200
686
+ // A refused connection fails at once; once connected, let the first render finish
687
+ timeout: 3e4
685
688
  },
686
689
  (res) => {
687
690
  res.resume();
@@ -940,7 +943,9 @@ program.command("dev").description("Run development server of EventCatalog").opt
940
943
  });
941
944
  startDevPrewarm({
942
945
  port: prewarmPort,
943
- paths: ["/ping", "/"]
946
+ // Renders the homepage before anyone opens it. Requests stop at the first response,
947
+ // so a probe path like /ping first would leave the homepage cold.
948
+ paths: ["/"]
944
949
  });
945
950
  }
946
951
  await runCommandWithFilteredOutput({
package/dist/generate.cjs CHANGED
@@ -112,7 +112,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
112
112
  var import_picocolors = __toESM(require("picocolors"), 1);
113
113
 
114
114
  // package.json
115
- var version = "5.0.0-beta.12";
115
+ var version = "5.0.0-beta.14";
116
116
 
117
117
  // src/constants.ts
118
118
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-TSY5CC27.js";
4
- import "./chunk-QB7X34OD.js";
5
- import "./chunk-FY6MSP6J.js";
3
+ } from "./chunk-4KE3EUDJ.js";
4
+ import "./chunk-OFK7U7BX.js";
5
+ import "./chunk-I3XDOICA.js";
6
6
  import "./chunk-RFIXKATC.js";
7
7
  export {
8
8
  generate
@@ -0,0 +1,3 @@
1
+ export * from "@eventcatalog/visualiser/studio-fonts.css";
2
+ import * as dependency from "@eventcatalog/visualiser/studio-fonts.css";
3
+ export default dependency.default;
@@ -0,0 +1,3 @@
1
+ export * from "@eventcatalog/visualiser/studio.css";
2
+ import * as dependency from "@eventcatalog/visualiser/studio.css";
3
+ export default dependency.default;
@@ -0,0 +1,3 @@
1
+ export * from "@eventcatalog/visualiser/studio";
2
+ import * as dependency from "@eventcatalog/visualiser/studio";
3
+ export default dependency.default;
@@ -21,6 +21,9 @@
21
21
  "@eventcatalog/sdk": "@eventcatalog__sdk.mjs",
22
22
  "@eventcatalog/visualiser": "@eventcatalog__visualiser.mjs",
23
23
  "@eventcatalog/visualiser/layout": "@eventcatalog__visualiser__layout.mjs",
24
+ "@eventcatalog/visualiser/studio": "@eventcatalog__visualiser__studio.mjs",
25
+ "@eventcatalog/visualiser/studio-fonts.css": "@eventcatalog__visualiser__studio-fonts.css.mjs",
26
+ "@eventcatalog/visualiser/studio.css": "@eventcatalog__visualiser__studio.css.mjs",
24
27
  "@eventcatalog/visualiser/styles-core.css": "@eventcatalog__visualiser__styles-core.css.mjs",
25
28
  "@fontsource/inter": "@fontsource__inter.mjs",
26
29
  "@fontsource/inter/400.css": "@fontsource__inter__400.css.mjs",
@@ -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 = "5.0.0-beta.12";
39
+ var version = "5.0.0-beta.14";
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-QB7X34OD.js";
4
- import "../chunk-FY6MSP6J.js";
3
+ } from "../chunk-OFK7U7BX.js";
4
+ import "../chunk-I3XDOICA.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -35,6 +35,8 @@ import config from './src/utils/eventcatalog-config/source.ts';
35
35
  import preprocessExpressiveCodeConfig from './integrations/expressive-code-config.mjs';
36
36
  import catalogAssets from './integrations/catalog-assets.mjs';
37
37
  import runtimeDependencies from './integrations/runtime-dependencies.mjs';
38
+ import stableDependencyOrder from './integrations/stable-dependency-order.mjs';
39
+ import skipStartupReload from './integrations/skip-startup-reload.mjs';
38
40
  import { getRuntimePaths } from './integrations/runtime-paths.mjs';
39
41
  import { collectClientDependencies } from './integrations/client-dependencies.mjs';
40
42
 
@@ -166,6 +168,8 @@ export default defineConfig({
166
168
  },
167
169
  plugins: [
168
170
  runtimeDependencies(),
171
+ stableDependencyOrder(),
172
+ skipStartupReload(),
169
173
  tailwindcss(),
170
174
  ...(await eventCatalogLikeC4(projectDirectory)),
171
175
  ...(config.trailingSlash === true ? [astroTrailingSlashEndpointFix()] : []),
@@ -224,7 +228,15 @@ export default defineConfig({
224
228
  },
225
229
  optimizeDeps: {
226
230
  exclude: [],
227
- include: collectClientDependencies(),
231
+ include: [
232
+ ...collectClientDependencies(),
233
+ // <ClientRouter /> imports these from a virtual module the dependency scan can't follow,
234
+ // so without them every cold start re-bundles on the first page and reloads it
235
+ 'astro/virtual-modules/transitions-events.js',
236
+ 'astro/virtual-modules/transitions-router.js',
237
+ 'astro/virtual-modules/transitions-swap-functions.js',
238
+ 'astro/virtual-modules/transitions-types.js',
239
+ ],
228
240
  },
229
241
  },
230
242
  });
@@ -0,0 +1,31 @@
1
+ // Astro writes its content data store as the dev server starts, which sends the browser a
2
+ // full reload. With no browser connected yet, Vite holds that reload and hands it to the
3
+ // first page that connects, so the first page opened after every start loaded twice.
4
+ // A reload sent before any page has been served has nothing to refresh (a tab left open
5
+ // from the previous run reloads itself when it reconnects), so drop those. Once a page has
6
+ // been requested, reloads pass through as usual.
7
+
8
+ const isFullReload = (payload) => typeof payload === 'object' && payload?.type === 'full-reload';
9
+
10
+ export default function skipStartupReload() {
11
+ return {
12
+ name: 'eventcatalog:skip-startup-reload',
13
+ apply: 'serve',
14
+ configureServer(server) {
15
+ let pageRequested = false;
16
+ server.middlewares.use((req, _res, next) => {
17
+ // Browser navigations ask for HTML; the CLI's prewarm request doesn't
18
+ if (!pageRequested && req.headers.accept?.includes('text/html')) pageRequested = true;
19
+ next();
20
+ });
21
+
22
+ for (const channel of new Set([server.ws, server.environments?.client?.hot].filter(Boolean))) {
23
+ const send = channel.send.bind(channel);
24
+ channel.send = (...args) => {
25
+ if (!pageRequested && isFullReload(args[0])) return;
26
+ return send(...args);
27
+ };
28
+ }
29
+ },
30
+ };
31
+ }
@@ -0,0 +1,29 @@
1
+ // Astro crawls framework packages with vitefu, which looks them up concurrently and lists
2
+ // each one in `resolve.external` / `resolve.noExternal` as its lookup finishes, so the
3
+ // order changes from one start to the next. Vite hashes these lists unsorted to decide
4
+ // whether its pre-bundled dependencies are still valid, so every `eventcatalog dev` saw a
5
+ // "changed" config and re-bundled all of them. Only membership matters in these lists, so
6
+ // sorting them keeps the hash (and the dependency cache) stable across starts.
7
+
8
+ const byName = (a, b) => {
9
+ const left = String(a);
10
+ const right = String(b);
11
+ return left < right ? -1 : left > right ? 1 : 0;
12
+ };
13
+
14
+ const sortResolveLists = (resolve) => {
15
+ if (Array.isArray(resolve?.external)) resolve.external.sort(byName);
16
+ if (Array.isArray(resolve?.noExternal)) resolve.noExternal.sort(byName);
17
+ };
18
+
19
+ export default function stableDependencyOrder() {
20
+ return {
21
+ name: 'eventcatalog:stable-dependency-order',
22
+ apply: 'serve',
23
+ configResolved(config) {
24
+ sortResolveLists(config.resolve);
25
+ sortResolveLists(config.ssr);
26
+ for (const environment of Object.values(config.environments ?? {})) sortResolveLists(environment.resolve);
27
+ },
28
+ };
29
+ }
@@ -170,6 +170,16 @@ const nodeRadius = (degree: number, isHub = false) =>
170
170
  /** Above this node count, expensive extras (collision force) are disabled. */
171
171
  const LARGE_GRAPH_NODE_COUNT = 1500;
172
172
 
173
+ /**
174
+ * The first layout settles before it paints instead of animating into place for ~5s: ticks
175
+ * run in short slices across frames (no long tasks) until it settles, ~40ms of work for 100
176
+ * nodes. Big catalogs stop once ticking has taken the work limit, paint past their largest
177
+ * moves and animate the rest. The limit counts ticking time, not elapsed time, so a page busy
178
+ * hydrating other islands doesn't cut the settle short.
179
+ */
180
+ const INITIAL_SETTLE_SLICE_MS = 12;
181
+ const INITIAL_SETTLE_WORK_LIMIT_MS = 400;
182
+
173
183
  /** Sprite resolution for node icons (drawn scaled-down, so keep it crisp) */
174
184
  const ICON_SPRITE_SIZE = 64;
175
185
 
@@ -617,6 +627,10 @@ const CatalogForceGraph = ({
617
627
  // normal-sized, whatever the lens's usual hubs are
618
628
  const isHub = (d: SimNode) => (focusKey ? d.key === focusKey : hubs.has(d.collection));
619
629
 
630
+ // Later layouts (lens, focus and filter changes) animate from the previous positions
631
+ const isFirstLayout = positionsRef.current.size === 0;
632
+ // Nothing paints until the first layout has settled (see INITIAL_SETTLE_SLICE_MS)
633
+ let settling = isFirstLayout;
620
634
  const visibleNodes: SimNode[] = viewNodes
621
635
  .filter((n) => !hiddenCollections.has(n.collection))
622
636
  .map((n) => ({ ...n, degree: 0, ...positionsRef.current.get(n.key) }));
@@ -734,6 +748,7 @@ const CatalogForceGraph = ({
734
748
  };
735
749
 
736
750
  const draw = () => {
751
+ if (settling) return;
737
752
  context.save();
738
753
  context.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
739
754
  context.clearRect(0, 0, width, height);
@@ -1014,6 +1029,29 @@ const CatalogForceGraph = ({
1014
1029
  );
1015
1030
  }
1016
1031
 
1032
+ // Settle the first layout before it paints rather than animating it into place
1033
+ let settleFrame: number | undefined;
1034
+ if (isFirstLayout) {
1035
+ simulation.stop();
1036
+ let workLeft = INITIAL_SETTLE_WORK_LIMIT_MS;
1037
+ const settle = () => {
1038
+ const sliceStart = performance.now();
1039
+ const sliceEnd = sliceStart + Math.min(INITIAL_SETTLE_SLICE_MS, workLeft);
1040
+ while (simulation.alpha() > simulation.alphaMin() && performance.now() < sliceEnd) simulation.tick();
1041
+ workLeft -= performance.now() - sliceStart;
1042
+ if (simulation.alpha() > simulation.alphaMin() && workLeft > 0) {
1043
+ settleFrame = requestAnimationFrame(settle);
1044
+ return;
1045
+ }
1046
+ settling = false;
1047
+ // Settled: paint it as is (restarting would run one tick more than the animated
1048
+ // layout). Otherwise paint and animate whatever is left.
1049
+ if (simulation.alpha() <= simulation.alphaMin()) fitToView();
1050
+ else simulation.restart();
1051
+ };
1052
+ settleFrame = requestAnimationFrame(settle);
1053
+ }
1054
+
1017
1055
  const findNode = (canvasX: number, canvasY: number): SimNode | null => {
1018
1056
  if (Number.isNaN(canvasX) || Number.isNaN(canvasY)) return null;
1019
1057
  const x = transform.invertX(canvasX);
@@ -1219,6 +1257,7 @@ const CatalogForceGraph = ({
1219
1257
  for (const node of visibleNodes) {
1220
1258
  if (node.x !== undefined && node.y !== undefined) positionsRef.current.set(node.key, { x: node.x, y: node.y });
1221
1259
  }
1260
+ if (settleFrame !== undefined) cancelAnimationFrame(settleFrame);
1222
1261
  simulation.stop();
1223
1262
  // The tooltip outlives this effect — never leave it showing stale content
1224
1263
  tooltip.style.opacity = '0';
@@ -17,9 +17,11 @@ import type { Node, Edge } from '@xyflow/react';
17
17
  import type { FlowGroupBy, OpenInStudioRequest } from '@eventcatalog/visualiser';
18
18
  import { buildUrl } from '@utils/url-builder';
19
19
  import { createCanvasThroughApi } from '@features/studio/api/client';
20
- import { canvasFromVisualiser } from '@features/studio/from-visualiser';
21
20
  import { getStoredName } from '@features/studio/identity';
22
- import OpenInStudioDialog from '@features/studio/components/OpenInStudioDialog';
21
+
22
+ // Studio's canvas code (what turns a diagram into a canvas, and the dialog asking for its name) is only loaded when a
23
+ // diagram is opened in Studio: every page with a diagram would load it otherwise, with Studio on or not
24
+ const OpenInStudioDialog = lazy(() => import('@features/studio/components/OpenInStudioDialog'));
23
25
 
24
26
  const NodeGraph = lazy(() =>
25
27
  import('@eventcatalog/visualiser').then((module) => ({ default: module.NodeGraph }))
@@ -123,6 +125,7 @@ const AstroNodeGraph = ({ isDevMode = false, resourceKey, studioApiUrl, ...other
123
125
  async (title: string | undefined) => {
124
126
  if (!studioApiUrl || !toOpen) return;
125
127
  const snapshot = await toOpen.getSnapshot();
128
+ const { canvasFromVisualiser } = await import('@features/studio/from-visualiser');
126
129
  const { nodes, edges, levels } = canvasFromVisualiser(snapshot);
127
130
  if (nodes.length === 0) throw new Error('Nothing on this diagram can go on a canvas yet');
128
131
  const canvas = await createCanvasThroughApi(studioApiUrl, {
@@ -149,7 +152,12 @@ const AstroNodeGraph = ({ isDevMode = false, resourceKey, studioApiUrl, ...other
149
152
  onResetLayout={handleResetLayout}
150
153
  onOpenInStudio={studioApiUrl ? setToOpen : undefined}
151
154
  />
152
- {toOpen && <OpenInStudioDialog title={toOpen.title} onOpen={openInStudio} onClose={closeOpenInStudio} />}
155
+ {toOpen && (
156
+ // Its own, so the diagram isn't swapped for "Loading graph..." while the dialog loads
157
+ <Suspense fallback={null}>
158
+ <OpenInStudioDialog title={toOpen.title} onOpen={openInStudio} onClose={closeOpenInStudio} />
159
+ </Suspense>
160
+ )}
153
161
  </Suspense>
154
162
  );
155
163
  };