@eventcatalog/core 5.0.0-beta.3 → 5.0.0-beta.30

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 (277) hide show
  1. package/LICENSE +234 -134
  2. package/README.md +5 -5
  3. package/dist/analytics/analytics.cjs +18 -3
  4. package/dist/analytics/analytics.d.cts +1 -1
  5. package/dist/analytics/analytics.d.ts +1 -1
  6. package/dist/analytics/analytics.js +3 -2
  7. package/dist/analytics/log-build.cjs +160 -77
  8. package/dist/analytics/log-build.d.cts +2 -2
  9. package/dist/analytics/log-build.d.ts +2 -2
  10. package/dist/analytics/log-build.js +7 -5
  11. package/dist/analytics/studio-usage.cjs +90 -0
  12. package/dist/analytics/studio-usage.d.cts +5 -0
  13. package/dist/analytics/studio-usage.d.ts +5 -0
  14. package/dist/analytics/studio-usage.js +10 -0
  15. package/dist/analytics/telemetry.cjs +42 -0
  16. package/dist/analytics/telemetry.d.cts +20 -0
  17. package/dist/analytics/telemetry.d.ts +20 -0
  18. package/dist/analytics/telemetry.js +8 -0
  19. package/dist/catalog-runtime.cjs +1 -1
  20. package/dist/{chunk-RFIXKATC.js → chunk-4G7FSRPN.js} +35 -42
  21. package/dist/{chunk-6OC46WQJ.js → chunk-55QETQZ3.js} +66 -35
  22. package/dist/{chunk-TQLRG35T.js → chunk-AD7CL772.js} +78 -45
  23. package/dist/chunk-CA6WCQ2T.js +54 -0
  24. package/dist/chunk-CPW6G62V.js +17 -0
  25. package/dist/{chunk-423S2KHN.js → chunk-FLAZ2JVN.js} +4 -2
  26. package/dist/{chunk-BH2F5WPN.js → chunk-GQI5UYXZ.js} +1 -1
  27. package/dist/{chunk-GYIVJXOJ.js → chunk-NA7OTBWW.js} +1 -1
  28. package/dist/{chunk-MDWB5HLO.js → chunk-NKNOXQ62.js} +1 -1
  29. package/dist/{chunk-3PKS2IIP.js → chunk-OX6TSVHY.js} +1 -1
  30. package/dist/{chunk-36RYTYT5.js → chunk-PD7KTSYN.js} +1 -1
  31. package/dist/chunk-S5GWAUG5.js +29 -0
  32. package/dist/{chunk-NDJOAITI.js → chunk-T3OROMAU.js} +9 -3
  33. package/dist/constants.cjs +1 -1
  34. package/dist/constants.js +1 -1
  35. package/dist/eventcatalog-config-file-utils.cjs +34 -41
  36. package/dist/eventcatalog-config-file-utils.d.cts +56 -58
  37. package/dist/eventcatalog-config-file-utils.d.ts +56 -58
  38. package/dist/eventcatalog-config-file-utils.js +1 -1
  39. package/dist/eventcatalog.cjs +531 -356
  40. package/dist/eventcatalog.config.d.cts +59 -1
  41. package/dist/eventcatalog.config.d.ts +59 -1
  42. package/dist/eventcatalog.js +63 -25
  43. package/dist/features.cjs +34 -41
  44. package/dist/features.js +2 -2
  45. package/dist/federation/federate.cjs +37 -44
  46. package/dist/federation/federate.js +2 -2
  47. package/dist/generate.cjs +37 -42
  48. package/dist/generate.js +4 -4
  49. package/dist/resolve-catalog-dependencies.cjs +34 -41
  50. package/dist/resolve-catalog-dependencies.js +2 -2
  51. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
  52. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
  53. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
  54. package/dist/runtime-dependencies/@hocuspocus__provider.mjs +3 -0
  55. package/dist/runtime-dependencies/@hocuspocus__server.mjs +3 -0
  56. package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +3 -0
  57. package/dist/runtime-dependencies/@mcp-b__webmcp-polyfill.mjs +3 -0
  58. package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
  59. package/dist/runtime-dependencies/manifest.json +13 -1
  60. package/dist/runtime-dependencies/react-hotkeys-hook.mjs +3 -0
  61. package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
  62. package/dist/runtime-dependencies/y-protocols.mjs +3 -0
  63. package/dist/runtime-dependencies/y-protocols__awareness.mjs +3 -0
  64. package/dist/runtime-dependencies/yjs.mjs +3 -0
  65. package/dist/utils/child-process-signals.cjs +53 -0
  66. package/dist/utils/child-process-signals.d.cts +19 -0
  67. package/dist/utils/child-process-signals.d.ts +19 -0
  68. package/dist/utils/child-process-signals.js +6 -0
  69. package/dist/utils/cli-logger.cjs +1 -1
  70. package/dist/utils/cli-logger.js +2 -2
  71. package/dist/utils/license-status.cjs +78 -45
  72. package/dist/utils/license-status.d.cts +15 -5
  73. package/dist/utils/license-status.d.ts +15 -5
  74. package/dist/utils/license-status.js +1 -1
  75. package/eventcatalog/astro.config.mjs +23 -1
  76. package/eventcatalog/integrations/config-loader.mjs +56 -58
  77. package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
  78. package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
  79. package/eventcatalog/integrations/storage.mjs +20 -0
  80. package/eventcatalog/integrations/studio-server.mjs +32 -0
  81. package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
  82. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
  83. package/eventcatalog/src/components/Header.astro +3 -3
  84. package/eventcatalog/src/components/Homepage/CatalogDashboard.astro +342 -0
  85. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +60 -4
  86. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
  87. package/eventcatalog/src/components/NavigationProgress.astro +7 -0
  88. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +2 -0
  89. package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +2 -0
  90. package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -0
  91. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -0
  92. package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
  93. package/eventcatalog/src/components/Search/SearchModal.tsx +2 -10
  94. package/eventcatalog/src/components/Search/search-utils.ts +26 -0
  95. package/eventcatalog/src/components/Seo.astro +5 -1
  96. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +53 -48
  97. package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +183 -178
  98. package/eventcatalog/src/components/Settings/LicenseSettings.tsx +140 -31
  99. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +40 -35
  100. package/eventcatalog/src/components/Settings/LogoUpload.tsx +1 -1
  101. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +9 -8
  102. package/eventcatalog/src/components/Settings/Row.tsx +7 -4
  103. package/eventcatalog/src/components/Settings/SettingsShared.tsx +3 -3
  104. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +53 -83
  105. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
  106. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +131 -0
  107. package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
  108. package/eventcatalog/src/components/TrialBadge.astro +20 -9
  109. package/eventcatalog/src/content.config.ts +19 -2
  110. package/eventcatalog/src/features/auth/error.astro +4 -2
  111. package/eventcatalog/src/features/auth/login.astro +2 -1
  112. package/eventcatalog/src/features/auth/middleware/middleware-auth.ts +10 -0
  113. package/eventcatalog/src/features/auth/unauthorized.astro +1 -1
  114. package/eventcatalog/src/features/fields/pages/fields.astro +1 -1
  115. package/eventcatalog/src/features/integrations/eventcatalog-features.ts +34 -1
  116. package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
  117. package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +47 -0
  118. package/eventcatalog/src/features/mcp/apps/canvas/styles.css +24 -0
  119. package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +278 -0
  120. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +272 -0
  121. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +65 -65
  122. package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +2 -1
  123. package/eventcatalog/src/features/mcp/mcp-apps.ts +6 -3
  124. package/eventcatalog/src/features/mcp/mcp-server.ts +36 -5
  125. package/eventcatalog/src/features/server/start.ts +25 -0
  126. package/eventcatalog/src/features/storage/database.ts +88 -0
  127. package/eventcatalog/src/features/storage/migrations.ts +85 -0
  128. package/eventcatalog/src/features/storage/sql/database.sql +5 -0
  129. package/eventcatalog/src/features/storage/sql/migrations/0001-studio-canvases.sql +12 -0
  130. package/eventcatalog/src/features/storage/sql/migrations.sql +15 -0
  131. package/eventcatalog/src/features/storage/sql.ts +28 -0
  132. package/eventcatalog/src/features/studio/agent-choreography.ts +384 -0
  133. package/eventcatalog/src/features/studio/agents.ts +28 -0
  134. package/eventcatalog/src/features/studio/api/canvases-api.ts +219 -0
  135. package/eventcatalog/src/features/studio/api/canvases.ts +25 -0
  136. package/eventcatalog/src/features/studio/api/client.ts +40 -0
  137. package/eventcatalog/src/features/studio/canvas-actions.ts +540 -0
  138. package/eventcatalog/src/features/studio/canvas-preview.ts +52 -0
  139. package/eventcatalog/src/features/studio/catalog-resources.ts +155 -0
  140. package/eventcatalog/src/features/studio/catalog.ts +173 -0
  141. package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +518 -0
  142. package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +118 -0
  143. package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +434 -0
  144. package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +143 -0
  145. package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +65 -0
  146. package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
  147. package/eventcatalog/src/features/studio/components/JoinForm.tsx +109 -0
  148. package/eventcatalog/src/features/studio/components/LeftPanel.tsx +206 -0
  149. package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
  150. package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
  151. package/eventcatalog/src/features/studio/components/Presence.tsx +293 -0
  152. package/eventcatalog/src/features/studio/components/ShareDialog.tsx +396 -0
  153. package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
  154. package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +2091 -0
  155. package/eventcatalog/src/features/studio/components/StudioNotice.astro +24 -0
  156. package/eventcatalog/src/features/studio/document-name.ts +7 -0
  157. package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
  158. package/eventcatalog/src/features/studio/hooks/presence-sender.ts +63 -0
  159. package/eventcatalog/src/features/studio/hooks/presence-store.ts +119 -0
  160. package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +353 -0
  161. package/eventcatalog/src/features/studio/hooks/use-comments.ts +54 -0
  162. package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +109 -0
  163. package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +782 -0
  164. package/eventcatalog/src/features/studio/identity.ts +59 -0
  165. package/eventcatalog/src/features/studio/limits.ts +2 -0
  166. package/eventcatalog/src/features/studio/pages/[id].astro +69 -0
  167. package/eventcatalog/src/features/studio/pages/index.astro +784 -0
  168. package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +27 -0
  169. package/eventcatalog/src/features/studio/server/canvas-mcp.ts +495 -0
  170. package/eventcatalog/src/features/studio/server/runtime.ts +498 -0
  171. package/eventcatalog/src/features/studio/server/sign-in.ts +18 -0
  172. package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
  173. package/eventcatalog/src/features/studio/server/storage.ts +90 -0
  174. package/eventcatalog/src/features/studio/server/tool-icons.ts +30 -0
  175. package/eventcatalog/src/features/studio/tool-sync.ts +75 -0
  176. package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
  177. package/eventcatalog/src/layouts/SettingsLayout.astro +2 -2
  178. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +13 -5
  179. package/eventcatalog/src/pages/_index.astro +5 -342
  180. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +2 -3
  181. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +0 -7
  182. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +3 -1
  183. package/eventcatalog/src/pages/diagrams/[id]/[version]/_index.data.ts +0 -7
  184. package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +1 -0
  185. package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +1 -0
  186. package/eventcatalog/src/pages/directory/[type]/_index.data.ts +5 -7
  187. package/eventcatalog/src/pages/directory/[type]/index.astro +3 -1
  188. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -7
  189. package/eventcatalog/src/pages/discover/[type]/index.astro +3 -1
  190. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +0 -7
  191. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -0
  192. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +0 -7
  193. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -0
  194. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +0 -7
  195. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +3 -1
  196. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/_[filename].data.ts +0 -7
  197. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +0 -7
  198. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -0
  199. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +1 -0
  200. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/_[...filename].data.ts +0 -4
  201. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/_index.data.ts +0 -7
  202. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/index.astro +1 -0
  203. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +3 -1
  204. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/_[filename].data.ts +0 -7
  205. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
  206. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +2 -3
  207. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +0 -7
  208. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +1 -0
  209. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +1 -0
  210. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/_[filename].data.ts +0 -7
  211. package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +0 -7
  212. package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +2 -1
  213. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/_index.data.ts +0 -7
  214. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +1 -0
  215. package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +0 -7
  216. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +1 -0
  217. package/eventcatalog/src/pages/docs/custom/[...path]/_index.data.ts +0 -7
  218. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +1 -0
  219. package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +1 -1
  220. package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +1 -0
  221. package/eventcatalog/src/pages/docs/services/[id]/asyncapi/[filename].astro +1 -1
  222. package/eventcatalog/src/pages/docs/services/[id]/changelog/index.astro +1 -1
  223. package/eventcatalog/src/pages/docs/services/[id]/graphql/[filename].astro +1 -1
  224. package/eventcatalog/src/pages/docs/services/[id]/spec/[filename].astro +1 -1
  225. package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +0 -7
  226. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +1 -0
  227. package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +0 -7
  228. package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -0
  229. package/eventcatalog/src/pages/index.astro +4 -2
  230. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +0 -7
  231. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +1 -0
  232. package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +0 -7
  233. package/eventcatalog/src/pages/schemas/explorer/index.astro +4 -2
  234. package/eventcatalog/src/pages/settings/license.astro +9 -1
  235. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/_index.data.ts +0 -7
  236. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/index.astro +1 -0
  237. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +0 -7
  238. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/_index.data.ts +0 -7
  239. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +1 -0
  240. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/_index.data.ts +0 -7
  241. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -0
  242. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -0
  243. package/eventcatalog/src/pages/visualiser/[type]/[id]/_index.data.ts +38 -0
  244. package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +18 -41
  245. package/eventcatalog/src/pages/visualiser/designs/[id]/_index.data.ts +0 -7
  246. package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -1
  247. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +0 -7
  248. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -0
  249. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +1 -0
  250. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +0 -7
  251. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +1 -0
  252. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +0 -7
  253. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +1 -0
  254. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +1 -0
  255. package/eventcatalog/src/types/react-syntax-highlighter.d.ts +10 -0
  256. package/eventcatalog/src/utils/collections/util.ts +8 -4
  257. package/eventcatalog/src/utils/feature.ts +8 -0
  258. package/eventcatalog/src/utils/git.ts +22 -5
  259. package/eventcatalog/src/utils/homepage-dashboard.ts +143 -0
  260. package/eventcatalog/src/utils/license.ts +1 -1
  261. package/eventcatalog/src/utils/link-validation.ts +25 -19
  262. package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +3 -1
  263. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
  264. package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +0 -2
  265. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +4 -2
  266. package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +20 -1
  267. package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
  268. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
  269. package/eventcatalog/src/utils/page-loaders/hybrid-page.ts +4 -15
  270. package/eventcatalog/src/utils/page-title.ts +15 -0
  271. package/eventcatalog/src/utils/syntax-highlighter-renderer.ts +64 -0
  272. package/eventcatalog/src/utils/trial.ts +14 -1
  273. package/package.json +19 -13
  274. package/dist/runtime-dependencies/shelljs.mjs +0 -3
  275. package/eventcatalog/public/studio-bg.png +0 -0
  276. package/eventcatalog/src/components/Studio/StudioPageModal.tsx +0 -150
  277. package/eventcatalog/src/pages/studio.astro +0 -316
@@ -22,19 +22,19 @@ 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.1/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
 
29
29
  // src/eventcatalog.ts
30
30
  var import_commander = require("commander");
31
31
  var import_node_child_process2 = require("child_process");
32
- var import_node_path20 = require("path");
32
+ var import_node_path21 = require("path");
33
33
  var import_node_http = __toESM(require("http"), 1);
34
34
  var import_fs = __toESM(require("fs"), 1);
35
- var import_node_path21 = __toESM(require("path"), 1);
35
+ var import_node_path22 = __toESM(require("path"), 1);
36
36
  var import_node_url2 = require("url");
37
- var import_node_module2 = require("module");
37
+ var import_node_module3 = require("module");
38
38
 
39
39
  // src/generate.js
40
40
  var import_node_path3 = __toESM(require("path"), 1);
@@ -50,65 +50,58 @@ var import_promises = require("fs/promises");
50
50
  var import_node_fs = require("fs");
51
51
  var import_node_path = __toESM(require("path"), 1);
52
52
  var import_node_url = require("url");
53
- var import_node_os = require("os");
53
+ var import_node_module = require("module");
54
54
  async function cleanup(projectDirectory) {
55
55
  const filePath = import_node_path.default.join(projectDirectory, "eventcatalog.config.mjs");
56
56
  if ((0, import_node_fs.existsSync)(filePath)) {
57
57
  await (0, import_promises.rm)(filePath);
58
58
  }
59
59
  }
60
- var findNodeModulesDirectory = (directory) => {
61
- let currentDirectory = directory;
62
- while (true) {
63
- const nodeModulesDirectory = import_node_path.default.join(currentDirectory, "node_modules");
64
- if ((0, import_node_fs.existsSync)(nodeModulesDirectory)) {
65
- return nodeModulesDirectory;
66
- }
67
- const parentDirectory = import_node_path.default.dirname(currentDirectory);
68
- if (parentDirectory === currentDirectory) {
69
- return void 0;
70
- }
71
- currentDirectory = parentDirectory;
72
- }
73
- };
74
- var linkNodeModulesIntoTempDirectory = async ({ projectDirectory, tempDir }) => {
75
- const nodeModulesDirectory = findNodeModulesDirectory(projectDirectory);
76
- if (!nodeModulesDirectory) {
77
- return;
78
- }
79
- await (0, import_promises.symlink)(nodeModulesDirectory, import_node_path.default.join(tempDir, "node_modules"), "dir");
60
+ var hidesConfigModuleTypeWarning = false;
61
+ var loads = 0;
62
+ var hideConfigModuleTypeWarning = () => {
63
+ if (hidesConfigModuleTypeWarning) return;
64
+ hidesConfigModuleTypeWarning = true;
65
+ const emitWarning = process.emitWarning;
66
+ process.emitWarning = function(warning, ...args) {
67
+ const code = typeof args[0] === "object" ? args[0]?.code : args[1];
68
+ const message2 = typeof warning === "string" ? warning : warning?.message;
69
+ if (code === "MODULE_TYPELESS_PACKAGE_JSON" && message2?.includes("eventcatalog.config.js")) return;
70
+ return emitWarning.call(this, warning, ...args);
71
+ };
80
72
  };
81
- var createTemporaryConfigDirectory = async (projectDirectory) => {
82
- const nodeModulesDirectory = findNodeModulesDirectory(projectDirectory);
83
- if (nodeModulesDirectory) {
84
- return (0, import_promises.mkdtemp)(import_node_path.default.join(nodeModulesDirectory, ".eventcatalog-config-"));
73
+ var AS_MODULE_QUERY = "eventcatalog-config-as-module";
74
+ var loadsMarkedConfigsAsModules = false;
75
+ var loadMarkedConfigsAsModules = () => {
76
+ if (loadsMarkedConfigsAsModules) return;
77
+ loadsMarkedConfigsAsModules = true;
78
+ const hook = `export async function load(url, context, nextLoad) {
79
+ return nextLoad(url, url.includes('${AS_MODULE_QUERY}=') ? { ...context, format: 'module' } : context);
80
+ }`;
81
+ (0, import_node_module.register)(`data:text/javascript,${encodeURIComponent(hook)}`);
82
+ };
83
+ var isCommonJSPackage = async (projectDirectory) => {
84
+ try {
85
+ const packageJson = JSON.parse(await (0, import_promises.readFile)(import_node_path.default.join(projectDirectory, "package.json"), "utf-8"));
86
+ return packageJson?.type === "commonjs";
87
+ } catch {
88
+ return false;
85
89
  }
86
- const tempDir = await (0, import_promises.mkdtemp)(import_node_path.default.join((0, import_node_os.tmpdir)(), "eventcatalog-config-"));
87
- await linkNodeModulesIntoTempDirectory({ projectDirectory, tempDir });
88
- return tempDir;
89
90
  };
90
91
  var getEventCatalogConfigFile = async (projectDirectory) => {
91
- let tempDir;
92
92
  try {
93
- let configFilePath = import_node_path.default.join(projectDirectory, "eventcatalog.config.js");
94
- const filePath = import_node_path.default.join(projectDirectory, "package.json");
95
- const packageJson = JSON.parse(await (0, import_promises.readFile)(filePath, "utf-8"));
96
- if (packageJson?.type !== "module") {
97
- tempDir = await createTemporaryConfigDirectory(projectDirectory);
98
- configFilePath = import_node_path.default.join(tempDir, "eventcatalog.config.mjs");
99
- await (0, import_promises.copyFile)(import_node_path.default.join(projectDirectory, "eventcatalog.config.js"), configFilePath);
100
- }
101
- const configFileURL = `${(0, import_node_url.pathToFileURL)(configFilePath).href}?t=${Date.now()}`;
93
+ hideConfigModuleTypeWarning();
94
+ const asModule = await isCommonJSPackage(projectDirectory);
95
+ if (asModule) loadMarkedConfigsAsModules();
96
+ const configFileURL = (0, import_node_url.pathToFileURL)(import_node_path.default.join(projectDirectory, "eventcatalog.config.js")).href;
97
+ const query = `${asModule ? AS_MODULE_QUERY : "loaded"}=${Date.now()}-${loads++}`;
102
98
  const config = await import(
103
99
  /* @vite-ignore */
104
- configFileURL
100
+ `${configFileURL}?${query}`
105
101
  );
106
102
  return config.default;
107
103
  } finally {
108
104
  await cleanup(projectDirectory);
109
- if (tempDir) {
110
- await (0, import_promises.rm)(tempDir, { recursive: true, force: true });
111
- }
112
105
  }
113
106
  };
114
107
 
@@ -181,7 +174,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
181
174
  var import_picocolors = __toESM(require("picocolors"), 1);
182
175
 
183
176
  // package.json
184
- var version = "5.0.0-beta.3";
177
+ var version = "5.0.0-beta.30";
185
178
 
186
179
  // src/constants.ts
187
180
  var VERSION = version;
@@ -191,8 +184,8 @@ var getTimestamp = () => {
191
184
  const now = /* @__PURE__ */ new Date();
192
185
  return now.toLocaleTimeString("en-US", { hour12: false });
193
186
  };
194
- var formatMessage = (tag, message, tagColor) => {
195
- return `${import_picocolors.default.dim(getTimestamp())} ${tagColor(`[${tag}]`)} ${message}`;
187
+ var formatMessage = (tag, message2, tagColor) => {
188
+ return `${import_picocolors.default.dim(getTimestamp())} ${tagColor(`[${tag}]`)} ${message2}`;
196
189
  };
197
190
  var logger = {
198
191
  welcome: () => {
@@ -208,28 +201,28 @@ var logger = {
208
201
  );
209
202
  console.log();
210
203
  },
211
- info: (message, tag = "info") => {
212
- console.log(formatMessage(tag, message, import_picocolors.default.blue));
204
+ info: (message2, tag = "info") => {
205
+ console.log(formatMessage(tag, message2, import_picocolors.default.blue));
213
206
  },
214
- success: (message, tag = "success") => {
215
- console.log(formatMessage(tag, message, import_picocolors.default.green));
207
+ success: (message2, tag = "success") => {
208
+ console.log(formatMessage(tag, message2, import_picocolors.default.green));
216
209
  },
217
- error: (message, tag = "error") => {
218
- console.log(formatMessage(tag, message, import_picocolors.default.red));
210
+ error: (message2, tag = "error") => {
211
+ console.log(formatMessage(tag, message2, import_picocolors.default.red));
219
212
  },
220
- warning: (message, tag = "warn") => {
221
- console.log(formatMessage(tag, message, import_picocolors.default.yellow));
213
+ warning: (message2, tag = "warn") => {
214
+ console.log(formatMessage(tag, message2, import_picocolors.default.yellow));
222
215
  },
223
- line: (message = "") => {
224
- console.log(message);
216
+ line: (message2 = "") => {
217
+ console.log(message2);
225
218
  },
226
- diagnostic: (severity, message, rule, attributes = []) => {
219
+ diagnostic: (severity, message2, rule, attributes = []) => {
227
220
  const isError = severity === "error";
228
221
  const color = isError ? import_picocolors.default.red : import_picocolors.default.yellow;
229
222
  const icon = isError ? "\u2716" : "\u26A0";
230
- const label = `${icon} ${severity.padEnd(7)} ${message}`;
223
+ const label = `${icon} ${severity.padEnd(7)} ${message2}`;
231
224
  const ruleSpacing = " ".repeat(Math.max(2, 72 - label.length));
232
- console.log(` ${color(icon)} ${color(severity.padEnd(7))} ${message}${ruleSpacing}${import_picocolors.default.gray(rule)}`);
225
+ console.log(` ${color(icon)} ${color(severity.padEnd(7))} ${message2}${ruleSpacing}${import_picocolors.default.gray(rule)}`);
233
226
  for (const attribute of attributes) {
234
227
  console.log(` - ${import_picocolors.default.dim(`${attribute.label}:`)} ${attribute.value}`);
235
228
  }
@@ -243,8 +236,8 @@ var logger = {
243
236
  const warningCount = `${warnings} warning${warnings === 1 ? "" : "s"}`;
244
237
  console.log(color(`${icon} ${problems} (${errorCount}, ${warningCount})`));
245
238
  },
246
- dim: (message) => {
247
- console.log(import_picocolors.default.dim(message));
239
+ dim: (message2) => {
240
+ console.log(import_picocolors.default.dim(message2));
248
241
  }
249
242
  };
250
243
 
@@ -295,16 +288,34 @@ var generate = async (PROJECT_DIRECTORY) => {
295
288
  for (const { plugin } of errors) {
296
289
  logger.error(` - ${plugin}`, "generator");
297
290
  }
291
+ process.exitCode = 1;
298
292
  }
299
293
  } catch (error) {
300
294
  console.error(error);
301
295
  await cleanup(PROJECT_DIRECTORY);
296
+ process.exitCode = 1;
302
297
  }
303
298
  };
304
299
 
305
300
  // src/analytics/analytics.js
306
301
  var import_os = __toESM(require("os"), 1);
307
- async function raiseEvent(eventData) {
302
+
303
+ // src/analytics/telemetry.ts
304
+ var TELEMETRY_REQUEST_TIMEOUT_MS = 2e3;
305
+ var isOptOutEnvValue = (value) => {
306
+ if (typeof value !== "string") return false;
307
+ const normalized = value.trim().toLowerCase();
308
+ return normalized === "1" || normalized === "true";
309
+ };
310
+ var isTelemetryDisabled = (config, env) => {
311
+ if (isOptOutEnvValue(env.EVENTCATALOG_TELEMETRY_DISABLED)) return true;
312
+ if (isOptOutEnvValue(env.DO_NOT_TRACK)) return true;
313
+ return config?.telemetry === false;
314
+ };
315
+
316
+ // src/analytics/analytics.js
317
+ async function raiseEvent(eventData, config) {
318
+ if (isTelemetryDisabled(config, process.env)) return;
308
319
  if (typeof eventData?.command !== "string" || typeof eventData?.cId !== "string") return;
309
320
  const url = "https://queue.simpleanalyticscdn.com/events";
310
321
  const userAgent = `@eventcatalog/eventcatalog@${VERSION} (${import_os.default.platform()}; ${import_os.default.arch()}; Node/${process.version})`;
@@ -326,7 +337,8 @@ async function raiseEvent(eventData) {
326
337
  const response = await fetch(url, {
327
338
  method: "POST",
328
339
  headers,
329
- body: JSON.stringify(payload)
340
+ body: JSON.stringify(payload),
341
+ signal: AbortSignal.timeout(TELEMETRY_REQUEST_TIMEOUT_MS)
330
342
  });
331
343
  if (!response.ok) {
332
344
  throw new Error(`Failed to raise analytics event: ${response.status}`);
@@ -403,12 +415,16 @@ function serializeCounts(counts) {
403
415
 
404
416
  // src/utils/license-status.ts
405
417
  var import_boxen = __toESM(require("boxen"), 1);
418
+ var import_picocolors2 = __toESM(require("picocolors"), 1);
406
419
  var import_license2 = require("@eventcatalog/license");
407
420
 
408
421
  // eventcatalog/src/utils/trial.ts
409
- var TRIAL_LENGTH_DAYS = 90;
422
+ var TRIAL_LENGTH_DAYS = 60;
410
423
  var LICENSE_FAQ_URL = "https://www.eventcatalog.dev/license-faq";
411
424
  var LICENSE_RENEW_URL = "https://eventcatalog.cloud";
425
+ var BUY_BUSINESS_URL = "https://www.eventcatalog.dev/buy?source=cli";
426
+ var PRICING_URL = "https://www.eventcatalog.dev/pricing";
427
+ var FREE_USE_NOTE = "Under $10M revenue and $10M raised, an individual or an open-source project? You qualify for Free Use; get a free key at eventcatalog.cloud.";
412
428
  var DAY_IN_MS = 24 * 60 * 60 * 1e3;
413
429
  var getTrialStatus = (tsd, now = Date.now()) => {
414
430
  if (typeof tsd !== "number" || !Number.isFinite(tsd) || tsd <= 0) return;
@@ -525,79 +541,157 @@ var getLicenseAnalytics = (license = { state: "none" }, tsd) => ({
525
541
  });
526
542
  var formatDate = (date) => date.toLocaleDateString(void 0, { dateStyle: "medium" });
527
543
  var formatDays = (days) => `${days} ${days === 1 ? "day" : "days"}`;
528
- var getTrialLine = (tsd, now) => {
544
+ var PLAIN = { bold: (text) => text, dim: (text) => text, link: (text) => text };
545
+ var COLOURS = { bold: import_picocolors2.default.bold, dim: import_picocolors2.default.dim, link: (text) => import_picocolors2.default.cyan(text) };
546
+ var render = ({ headline, rows, links, note }, colours) => {
547
+ const width = Math.max(0, ...[...rows, ...links].map(([label]) => label.length));
548
+ const row = ([label, value]) => `${colours.dim(label.padEnd(width))} ${value}`;
549
+ return [
550
+ colours.bold(headline),
551
+ ...rows.length ? ["", ...rows.map(row)] : [],
552
+ ...links.length ? ["", ...links.map(([label, url]) => row([label, colours.link(url)]))] : [],
553
+ ...note?.length ? ["", ...note.map(colours.dim)] : []
554
+ ].join("\n");
555
+ };
556
+ var FREE_USE_LINES = FREE_USE_NOTE.split(/(?<=\?) /);
557
+ var message = (content) => ({
558
+ ...content,
559
+ text: render(content, PLAIN)
560
+ });
561
+ var getTrialRow = (tsd, now) => {
529
562
  const trial = getTrialStatus(tsd, now);
530
563
  if (!trial) return;
531
- return trial.ended ? `Your ${TRIAL_LENGTH_DAYS}-day EventCatalog trial ended on ${formatDate(trial.endsAt)}.` : `${formatDays(trial.daysLeft)} left of your ${TRIAL_LENGTH_DAYS}-day EventCatalog trial (ends ${formatDate(trial.endsAt)}).`;
564
+ return [
565
+ "Trial",
566
+ trial.ended ? `Ended ${formatDate(trial.endsAt)}` : `${formatDays(trial.daysLeft)} left of ${TRIAL_LENGTH_DAYS} (ends ${formatDate(trial.endsAt)})`
567
+ ];
532
568
  };
533
569
  var getLicenseStatusMessage = (license, tsd, now = Date.now()) => {
570
+ const licensing = ["Licensing", LICENSE_FAQ_URL];
571
+ const renew = ["Renew", LICENSE_RENEW_URL];
572
+ const licensedTo = "org" in license && license.org ? [["Licensed to", license.org]] : [];
534
573
  if (license.state === "licensed") {
535
574
  const daysLeft = Math.max(0, Math.ceil((license.expiresAt.getTime() - now) / DAY_IN_MS2));
536
- const licensedTo = license.org ? `Licensed to ${license.org}` : "Licensed";
537
575
  if (daysLeft < LICENSE_REMINDER_DAYS) {
538
- return {
539
- title: "EventCatalog Commercial License",
576
+ return message({
577
+ title: "EventCatalog license",
540
578
  color: "yellow",
541
- text: [
542
- licensedTo,
543
- `Your license expires in ${formatDays(daysLeft)}, on ${formatDate(license.expiresAt)}.`,
544
- `Renew it to keep using EventCatalog commercially: ${LICENSE_RENEW_URL}`
545
- ].join("\n")
546
- };
579
+ headline: `Your commercial license expires in ${formatDays(daysLeft)}`,
580
+ rows: [...licensedTo, ["Expires", formatDate(license.expiresAt)]],
581
+ links: [renew]
582
+ });
547
583
  }
548
- return {
549
- title: "EventCatalog Commercial License",
584
+ return message({
585
+ title: "EventCatalog license",
550
586
  color: "green",
551
- text: `${licensedTo}
552
- Valid until ${formatDate(license.expiresAt)} (${formatDays(daysLeft)} left)`
553
- };
587
+ headline: "Commercial license active",
588
+ rows: [...licensedTo, ["Valid until", `${formatDate(license.expiresAt)} (${formatDays(daysLeft)} left)`]],
589
+ links: []
590
+ });
554
591
  }
555
592
  if (license.state === "plan") return;
556
- const trialLine = getTrialLine(tsd, now);
593
+ const trialRow = getTrialRow(tsd, now);
594
+ const trialRows = trialRow ? [trialRow] : [];
557
595
  if (license.state === "none") {
558
- if (!trialLine) return;
559
- const ended = getTrialStatus(tsd, now)?.ended;
560
- return {
596
+ const trial = getTrialStatus(tsd, now);
597
+ if (!trial || !trialRow) return;
598
+ return message({
561
599
  title: "EventCatalog trial",
562
- color: ended ? "yellow" : "green",
563
- text: `${trialLine}
564
- Learn about licensing: ${LICENSE_FAQ_URL}`
565
- };
600
+ color: trial.ended ? "yellow" : "green",
601
+ headline: trial.ended ? "Your EventCatalog trial has ended" : `You're on the ${TRIAL_LENGTH_DAYS}-day EventCatalog trial`,
602
+ rows: trialRows,
603
+ links: trial.ended ? [["Get a license", LICENSE_RENEW_URL], ["Buy Business", BUY_BUSINESS_URL], licensing] : [["Buy a license", PRICING_URL], licensing],
604
+ note: trial.ended ? FREE_USE_LINES : void 0
605
+ });
566
606
  }
567
607
  if (license.state === "expired") {
568
- const expiredOn = license.expiresAt ? `expired on ${formatDate(license.expiresAt)} (${formatDays(Math.floor((now - license.expiresAt.getTime()) / DAY_IN_MS2))} ago)` : "has expired";
569
- return {
570
- title: "EventCatalog License Expired",
608
+ const expiredOn = license.expiresAt ? [
609
+ [
610
+ "Expired",
611
+ `${formatDate(license.expiresAt)} (${formatDays(Math.floor((now - license.expiresAt.getTime()) / DAY_IN_MS2))} ago)`
612
+ ]
613
+ ] : [];
614
+ return message({
615
+ title: "EventCatalog license",
571
616
  color: "yellow",
572
- text: [
573
- `Your EventCatalog commercial license${license.org ? ` for ${license.org}` : ""} ${expiredOn}.`,
574
- `Renew it to keep using EventCatalog commercially: ${LICENSE_RENEW_URL}`,
575
- trialLine,
576
- `Learn about licensing: ${LICENSE_FAQ_URL}`
577
- ].filter(Boolean).join("\n")
578
- };
617
+ headline: "Your commercial license has expired",
618
+ // A catalog has a license or is on the trial: an expired license is renewed, not replaced by the trial
619
+ rows: [...licensedTo, ...expiredOn],
620
+ links: [renew, licensing]
621
+ });
579
622
  }
580
- return {
623
+ return message({
581
624
  title: "EventCatalog license",
582
625
  color: "yellow",
583
- text: [`Your license.jwt could not be verified: ${license.reason}.`, trialLine, `Learn about licensing: ${LICENSE_FAQ_URL}`].filter(Boolean).join("\n")
584
- };
626
+ headline: "Your license.jwt couldn't be verified",
627
+ rows: [["Reason", license.reason.charAt(0).toUpperCase() + license.reason.slice(1)], ...trialRows],
628
+ links: [licensing]
629
+ });
585
630
  };
586
631
  var printLicenseStatus = (license, tsd) => {
587
- const message = getLicenseStatusMessage(license, tsd);
588
- if (!message) return;
632
+ const status = getLicenseStatusMessage(license, tsd);
633
+ if (!status) return;
589
634
  console.log(
590
- (0, import_boxen.default)(message.text, {
591
- padding: 1,
635
+ (0, import_boxen.default)(render(status, COLOURS), {
636
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
592
637
  margin: 1,
593
638
  borderStyle: "round",
594
- borderColor: message.color,
595
- title: message.title,
596
- titleAlignment: "center"
639
+ borderColor: status.color,
640
+ title: status.title,
641
+ titleAlignment: "left"
597
642
  })
598
643
  );
599
644
  };
600
645
 
646
+ // src/analytics/studio-usage.js
647
+ var import_node_fs3 = __toESM(require("fs"), 1);
648
+ var import_node_path6 = __toESM(require("path"), 1);
649
+ var DAY_IN_MS3 = 24 * 60 * 60 * 1e3;
650
+ var DEFAULT_DATABASE_PATH = ".eventcatalog/eventcatalog.db";
651
+ var getStudioMode = (configFile) => {
652
+ const enabled = configFile.studio?.enabled;
653
+ if (enabled === false) return "off";
654
+ return configFile.output === "server" && enabled === true ? "server" : "dev";
655
+ };
656
+ var getStorageType = (configFile) => configFile.storage?.type || "memory";
657
+ var loadSqlite = () => {
658
+ const emitWarning = process.emitWarning;
659
+ process.emitWarning = function(warning, ...args) {
660
+ const type = typeof args[0] === "object" ? args[0]?.type : args[0];
661
+ const message2 = typeof warning === "string" ? warning : warning?.message;
662
+ if (type === "ExperimentalWarning" && message2?.startsWith("SQLite")) return;
663
+ return emitWarning.call(this, warning, ...args);
664
+ };
665
+ try {
666
+ return process.getBuiltinModule?.("node:sqlite");
667
+ } catch {
668
+ return void 0;
669
+ } finally {
670
+ process.emitWarning = emitWarning;
671
+ }
672
+ };
673
+ var UNKNOWN = "canvases:unknown";
674
+ var serializeStudioUsage = (projectDirectory, configFile, now = Date.now()) => {
675
+ if (getStudioMode(configFile) === "off" || getStorageType(configFile) !== "sqlite") return UNKNOWN;
676
+ const file = import_node_path6.default.resolve(projectDirectory, configFile.storage.path ?? DEFAULT_DATABASE_PATH);
677
+ if (!import_node_fs3.default.existsSync(file)) return "canvases:0,changed7d:0,changed30d:0,deleted:0";
678
+ let database;
679
+ try {
680
+ const sqlite = loadSqlite();
681
+ if (!sqlite?.DatabaseSync) return UNKNOWN;
682
+ database = new sqlite.DatabaseSync(file, { readOnly: true });
683
+ const canvases = database.prepare(
684
+ "SELECT COUNT(*) AS total, SUM(updated_at >= ?) AS changed7d, SUM(updated_at >= ?) AS changed30d FROM studio_canvases"
685
+ ).get(now - 7 * DAY_IN_MS3, now - 30 * DAY_IN_MS3);
686
+ const { deleted } = database.prepare("SELECT COUNT(*) AS deleted FROM studio_deleted_canvases").get();
687
+ return `canvases:${canvases.total},changed7d:${canvases.changed7d ?? 0},changed30d:${canvases.changed30d ?? 0},deleted:${deleted}`;
688
+ } catch {
689
+ return UNKNOWN;
690
+ } finally {
691
+ database?.close();
692
+ }
693
+ };
694
+
601
695
  // src/analytics/log-build.js
602
696
  var isMCPEnabled = (configFile) => configFile.output === "server" && (configFile.mcp?.enabled ?? true);
603
697
  var getFeatures = async (configFile) => {
@@ -611,7 +705,9 @@ var getFeatures = async (configFile) => {
611
705
  environments: Array.isArray(configFile.environments) && configFile.environments.length > 0,
612
706
  output: configFile.output || "static",
613
707
  mcp,
614
- mcpAuth: mcp && (configFile.mcp?.auth?.enabled ?? false)
708
+ mcpAuth: mcp && (configFile.mcp?.auth?.enabled ?? false),
709
+ studio: getStudioMode(configFile),
710
+ storage: getStorageType(configFile)
615
711
  };
616
712
  };
617
713
  var getDirectoryProvider = (source) => {
@@ -653,50 +749,70 @@ var toCloudResourceCounts = (counts) => ({
653
749
  customPages: counts.customPages || 0,
654
750
  customApis: counts.customApis || 0
655
751
  });
656
- var reportCloudResourceInventory = async (configFile, resourceCounts) => {
752
+ var getEnabledCloudAnalytics = (configFile) => {
657
753
  const analytics = configFile.cloud?.analytics;
658
- if (!analytics?.enabled || !analytics.trackingId || !analytics.writeKey) return;
754
+ if (!analytics?.enabled || !analytics.trackingId || !analytics.writeKey) return null;
755
+ return analytics;
756
+ };
757
+ var reportCloudResourceInventory = async (configFile, resourceCounts) => {
758
+ const analytics = getEnabledCloudAnalytics(configFile);
759
+ if (!analytics) return;
659
760
  const endpoint = analytics.endpoint || CLOUD_ANALYTICS_ENDPOINT;
660
- await fetch(endpoint, {
661
- method: "POST",
662
- headers: {
663
- "Content-Type": "application/json",
664
- "X-EventCatalog-Analytics-Key": analytics.writeKey
665
- },
666
- body: JSON.stringify({
667
- trackingId: analytics.trackingId,
668
- event: "catalog.resource_inventory_reported",
669
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
670
- counts: toCloudResourceCounts(resourceCounts)
671
- })
672
- });
761
+ try {
762
+ await fetch(endpoint, {
763
+ method: "POST",
764
+ headers: {
765
+ "Content-Type": "application/json",
766
+ "X-EventCatalog-Analytics-Key": analytics.writeKey
767
+ },
768
+ body: JSON.stringify({
769
+ trackingId: analytics.trackingId,
770
+ event: "catalog.resource_inventory_reported",
771
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
772
+ counts: toCloudResourceCounts(resourceCounts)
773
+ }),
774
+ signal: AbortSignal.timeout(TELEMETRY_REQUEST_TIMEOUT_MS)
775
+ });
776
+ } catch {
777
+ }
673
778
  };
674
779
  var main = async (projectDir, { command = "build", license } = {}) => {
675
780
  try {
676
781
  await verifyRequiredFieldsAreInCatalogConfigFile(projectDir);
677
782
  const configFile = await getEventCatalogConfigFile(projectDir);
783
+ if (isTelemetryDisabled(configFile, process.env)) {
784
+ if (getEnabledCloudAnalytics(configFile)) {
785
+ const resourceCounts2 = await countResources(projectDir);
786
+ await reportCloudResourceInventory(configFile, resourceCounts2);
787
+ }
788
+ return;
789
+ }
678
790
  const { cId, tsd, organizationName, generators = [] } = configFile;
679
791
  const generatorNames = generators.length > 0 ? generators.map((generator) => generator[0]) : ["none"];
680
792
  const features = await getFeatures(configFile);
681
793
  const resourceCounts = await countResources(projectDir);
682
794
  const contentHash = await hashCatalogContent(projectDir);
683
795
  await reportCloudResourceInventory(configFile, resourceCounts);
684
- await raiseEvent({
685
- command,
686
- org: organizationName,
687
- cId,
688
- // Trial start date (unix ms) from eventcatalog.config.js
689
- tsd,
690
- // Commercial license or trial, and when each expires (unix ms)
691
- ...getLicenseAnalytics(license, tsd),
692
- // CI redeploys and human-run builds are different signals; tag rather than suppress
693
- ci: process.env.CI ? "true" : "false",
694
- contentHash,
695
- generators: generatorNames.toString(),
696
- features: Object.keys(features).map((feature) => `${feature}:${features[feature]}`).join(","),
697
- directorySources: serializeDirectorySources(configFile),
698
- resources: serializeCounts(resourceCounts)
699
- });
796
+ await raiseEvent(
797
+ {
798
+ command,
799
+ org: organizationName,
800
+ cId,
801
+ // Trial start date (unix ms) from eventcatalog.config.js
802
+ tsd,
803
+ // Commercial license or trial, and when each expires (unix ms)
804
+ ...getLicenseAnalytics(license, tsd),
805
+ // CI redeploys and human-run builds are different signals; tag rather than suppress
806
+ ci: process.env.CI ? "true" : "false",
807
+ contentHash,
808
+ generators: generatorNames.toString(),
809
+ features: Object.keys(features).map((feature) => `${feature}:${features[feature]}`).join(","),
810
+ directorySources: serializeDirectorySources(configFile),
811
+ resources: serializeCounts(resourceCounts),
812
+ studio: serializeStudioUsage(projectDir, configFile)
813
+ },
814
+ configFile
815
+ );
700
816
  } catch (error) {
701
817
  }
702
818
  };
@@ -714,8 +830,8 @@ async function watch(projectDirectory, catalogDirectory, callback = () => {
714
830
  }
715
831
 
716
832
  // src/resolve-catalog-dependencies.js
717
- var import_node_path6 = __toESM(require("path"), 1);
718
- var import_node_fs3 = __toESM(require("fs"), 1);
833
+ var import_node_path7 = __toESM(require("path"), 1);
834
+ var import_node_fs4 = __toESM(require("fs"), 1);
719
835
  var import_gray_matter2 = __toESM(require("gray-matter"), 1);
720
836
  var resolve_catalog_dependencies_default = async (catalogDir, core2) => {
721
837
  const catalogConfig = await getEventCatalogConfigFile(catalogDir);
@@ -723,11 +839,11 @@ var resolve_catalog_dependencies_default = async (catalogDir, core2) => {
723
839
  if (!dependencies) {
724
840
  return;
725
841
  }
726
- const dependenciesDir = import_node_path6.default.join(catalogDir, "dependencies");
727
- if (import_node_fs3.default.existsSync(dependenciesDir)) {
728
- import_node_fs3.default.rmSync(dependenciesDir, { recursive: true, force: true });
842
+ const dependenciesDir = import_node_path7.default.join(catalogDir, "dependencies");
843
+ if (import_node_fs4.default.existsSync(dependenciesDir)) {
844
+ import_node_fs4.default.rmSync(dependenciesDir, { recursive: true, force: true });
729
845
  }
730
- import_node_fs3.default.mkdirSync(dependenciesDir, { recursive: true });
846
+ import_node_fs4.default.mkdirSync(dependenciesDir, { recursive: true });
731
847
  const resourceTypes = Object.keys(dependencies);
732
848
  for (const resourceType of resourceTypes) {
733
849
  for (const dependency of dependencies[resourceType]) {
@@ -747,9 +863,9 @@ var resolve_catalog_dependencies_default = async (catalogDir, core2) => {
747
863
  },
748
864
  frontmatter
749
865
  );
750
- const resourceFile = import_node_path6.default.join(dependenciesDir, resourceType, dependency.id, `index.md`);
751
- import_node_fs3.default.mkdirSync(import_node_path6.default.dirname(resourceFile), { recursive: true });
752
- import_node_fs3.default.writeFileSync(resourceFile, markdown);
866
+ const resourceFile = import_node_path7.default.join(dependenciesDir, resourceType, dependency.id, `index.md`);
867
+ import_node_fs4.default.mkdirSync(import_node_path7.default.dirname(resourceFile), { recursive: true });
868
+ import_node_fs4.default.writeFileSync(resourceFile, markdown);
753
869
  }
754
870
  }
755
871
  return;
@@ -759,8 +875,8 @@ var resolve_catalog_dependencies_default = async (catalogDir, core2) => {
759
875
  var import_boxen2 = __toESM(require("boxen"), 1);
760
876
 
761
877
  // src/features.ts
762
- var import_node_path7 = require("path");
763
- var import_node_fs4 = __toESM(require("fs"), 1);
878
+ var import_node_path8 = require("path");
879
+ var import_node_fs5 = __toESM(require("fs"), 1);
764
880
  var getProjectOutDir = async () => {
765
881
  const config = await getEventCatalogConfigFile(process.env.PROJECT_DIR || "");
766
882
  return config?.outDir || "dist";
@@ -775,7 +891,7 @@ var isIndexedSearchEnabled = async () => {
775
891
  };
776
892
  var isAuthEnabled = async () => {
777
893
  const directory = process.env.PROJECT_DIR || process.cwd();
778
- const hasAuthConfig = import_node_fs4.default.existsSync((0, import_node_path7.join)(directory, "eventcatalog.auth.js"));
894
+ const hasAuthConfig = import_node_fs5.default.existsSync((0, import_node_path8.join)(directory, "eventcatalog.auth.js"));
779
895
  return hasAuthConfig;
780
896
  };
781
897
 
@@ -784,11 +900,11 @@ var import_update_notifier = __toESM(require("update-notifier"), 1);
784
900
  var import_dotenv = __toESM(require("dotenv"), 1);
785
901
 
786
902
  // src/migrations/message-channels-to-service-channels.ts
787
- var import_node_fs5 = __toESM(require("fs"), 1);
903
+ var import_node_fs6 = __toESM(require("fs"), 1);
788
904
  var import_glob2 = require("glob");
789
- var import_node_os2 = __toESM(require("os"), 1);
905
+ var import_node_os = __toESM(require("os"), 1);
790
906
  var import_gray_matter3 = __toESM(require("gray-matter"), 1);
791
- var import_node_path8 = __toESM(require("path"), 1);
907
+ var import_node_path9 = __toESM(require("path"), 1);
792
908
  var DISABLE_CHANNEL_MIGRATION_ENV = "EVENTCATALOG_DISABLE_CHANNEL_MIGRATION";
793
909
  var isChannelMigrationDisabled = () => {
794
910
  return ["true", "1", "yes"].includes((process.env[DISABLE_CHANNEL_MIGRATION_ENV] ?? "").toLowerCase());
@@ -797,7 +913,7 @@ var message_channels_to_service_channels_default = async (dir2) => {
797
913
  if (isChannelMigrationDisabled()) {
798
914
  return { status: "skipped", message: `Channel migration disabled by ${DISABLE_CHANNEL_MIGRATION_ENV}` };
799
915
  }
800
- const PROJECT_DIR = import_node_path8.default.join(dir2 || process.env.PROJECT_DIR);
916
+ const PROJECT_DIR = import_node_path9.default.join(dir2 || process.env.PROJECT_DIR);
801
917
  const messages = await (0, import_glob2.glob)(
802
918
  [
803
919
  "**/events/*/index.mdx",
@@ -820,7 +936,7 @@ var message_channels_to_service_channels_default = async (dir2) => {
820
936
  cwd: PROJECT_DIR,
821
937
  absolute: true,
822
938
  nodir: true,
823
- windowsPathsNoEscape: import_node_os2.default.platform() == "win32",
939
+ windowsPathsNoEscape: import_node_os.default.platform() == "win32",
824
940
  ignore: ["node_modules/**", "**/dist/**", "**/teams", "**/users", "**/package.json", "**/Dockerfile"]
825
941
  }
826
942
  );
@@ -836,13 +952,13 @@ var message_channels_to_service_channels_default = async (dir2) => {
836
952
  absolute: true
837
953
  }
838
954
  );
839
- const messagesWithChannels = messages.reduce((acc, message) => {
840
- const file = import_node_fs5.default.readFileSync(message, "utf8");
955
+ const messagesWithChannels = messages.reduce((acc, message2) => {
956
+ const file = import_node_fs6.default.readFileSync(message2, "utf8");
841
957
  const { data } = (0, import_gray_matter3.default)(file);
842
958
  if (data.channels?.length > 0) {
843
959
  acc.push({
844
960
  ...data,
845
- path: message
961
+ path: message2
846
962
  });
847
963
  }
848
964
  return acc;
@@ -851,11 +967,11 @@ var message_channels_to_service_channels_default = async (dir2) => {
851
967
  return { status: "success", message: "No messages with channels found in the catalog" };
852
968
  }
853
969
  const servicesWithChannels = services.reduce((acc, service) => {
854
- const file = import_node_fs5.default.readFileSync(service, "utf8");
970
+ const file = import_node_fs6.default.readFileSync(service, "utf8");
855
971
  const { data } = (0, import_gray_matter3.default)(file);
856
- const isSending = data.sends?.some((send) => messagesWithChannels.some((message) => message.id === send.id));
972
+ const isSending = data.sends?.some((send) => messagesWithChannels.some((message2) => message2.id === send.id));
857
973
  const isReceiving = data.receives?.some(
858
- (receive) => messagesWithChannels.some((message) => message.id === receive.id)
974
+ (receive) => messagesWithChannels.some((message2) => message2.id === receive.id)
859
975
  );
860
976
  if (isSending || isReceiving) {
861
977
  acc.push({
@@ -866,18 +982,18 @@ var message_channels_to_service_channels_default = async (dir2) => {
866
982
  return acc;
867
983
  }, []);
868
984
  for (const service of servicesWithChannels) {
869
- const file = import_node_fs5.default.readFileSync(service.path, "utf8");
985
+ const file = import_node_fs6.default.readFileSync(service.path, "utf8");
870
986
  const { data } = (0, import_gray_matter3.default)(file);
871
- const messagesTheServiceSendsThatNeedUpdating = data.sends?.filter((send) => messagesWithChannels.some((message) => message.id === send.id)) ?? [];
872
- const messagesTheServiceReceivesThatNeedUpdating = data.receives?.filter((receive) => messagesWithChannels.some((message) => message.id === receive.id)) ?? [];
987
+ const messagesTheServiceSendsThatNeedUpdating = data.sends?.filter((send) => messagesWithChannels.some((message2) => message2.id === send.id)) ?? [];
988
+ const messagesTheServiceReceivesThatNeedUpdating = data.receives?.filter((receive) => messagesWithChannels.some((message2) => message2.id === receive.id)) ?? [];
873
989
  if (messagesTheServiceSendsThatNeedUpdating.length > 0 || messagesTheServiceReceivesThatNeedUpdating.length > 0) {
874
990
  const newSends = (data.sends ?? []).map((send) => {
875
- const match = messagesWithChannels.find((message) => message.id === send.id);
991
+ const match = messagesWithChannels.find((message2) => message2.id === send.id);
876
992
  if (!match) return send;
877
993
  return { ...send, to: (match.channels ?? []).filter((channel) => channel !== null) };
878
994
  });
879
995
  const newReceives = (data.receives ?? []).map((receive) => {
880
- const match = messagesWithChannels.find((message) => message.id === receive.id);
996
+ const match = messagesWithChannels.find((message2) => message2.id === receive.id);
881
997
  if (!match) return receive;
882
998
  return { ...receive, from: (match.channels ?? []).filter((channel) => channel !== null) };
883
999
  });
@@ -886,14 +1002,14 @@ var message_channels_to_service_channels_default = async (dir2) => {
886
1002
  ...newSends.length > 0 ? { sends: newSends } : {},
887
1003
  ...newReceives.length > 0 ? { receives: newReceives } : {}
888
1004
  };
889
- import_node_fs5.default.writeFileSync(service.path, import_gray_matter3.default.stringify(file, newData));
1005
+ import_node_fs6.default.writeFileSync(service.path, import_gray_matter3.default.stringify(file, newData));
890
1006
  }
891
1007
  }
892
- for (const message of messagesWithChannels) {
893
- const file = import_node_fs5.default.readFileSync(message.path, "utf8");
1008
+ for (const message2 of messagesWithChannels) {
1009
+ const file = import_node_fs6.default.readFileSync(message2.path, "utf8");
894
1010
  const parsed = (0, import_gray_matter3.default)(file);
895
1011
  const { channels, ...newData } = parsed.data;
896
- import_node_fs5.default.writeFileSync(message.path, import_gray_matter3.default.stringify(parsed.content, newData));
1012
+ import_node_fs6.default.writeFileSync(message2.path, import_gray_matter3.default.stringify(parsed.content, newData));
897
1013
  }
898
1014
  console.log("\u2714 Channels migrated to new services API");
899
1015
  };
@@ -903,13 +1019,39 @@ var runMigrations = async (dir2) => {
903
1019
  await message_channels_to_service_channels_default(dir2);
904
1020
  };
905
1021
 
1022
+ // src/utils/child-process-signals.ts
1023
+ var import_node_os2 = require("os");
1024
+ var FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
1025
+ var isRunning = (child) => child.exitCode === null && child.signalCode === null;
1026
+ var stopChildWithParent = (child, parent = process) => {
1027
+ let received;
1028
+ const onSignal = (signal) => {
1029
+ received = signal;
1030
+ if (isRunning(child)) child.kill(signal);
1031
+ };
1032
+ const onExit = () => {
1033
+ if (isRunning(child)) child.kill("SIGTERM");
1034
+ };
1035
+ for (const signal of FORWARDED_SIGNALS) parent.on(signal, onSignal);
1036
+ parent.on("exit", onExit);
1037
+ return {
1038
+ childClosed: () => {
1039
+ for (const signal of FORWARDED_SIGNALS) parent.off(signal, onSignal);
1040
+ parent.off("exit", onExit);
1041
+ if (!received) return false;
1042
+ parent.exit(128 + import_node_os2.constants.signals[received]);
1043
+ return true;
1044
+ }
1045
+ };
1046
+ };
1047
+
906
1048
  // eventcatalog/src/features/fields/field-indexer.ts
907
- var import_node_path10 = __toESM(require("path"), 1);
908
- var import_node_fs7 = __toESM(require("fs"), 1);
1049
+ var import_node_path11 = __toESM(require("path"), 1);
1050
+ var import_node_fs8 = __toESM(require("fs"), 1);
909
1051
 
910
1052
  // eventcatalog/src/features/fields/fields-db.ts
911
1053
  var import_sql = __toESM(require("sql.js"), 1);
912
- var import_node_fs6 = __toESM(require("fs"), 1);
1054
+ var import_node_fs7 = __toESM(require("fs"), 1);
913
1055
  var SCHEMA_SQL = `
914
1056
  CREATE TABLE IF NOT EXISTS fields (
915
1057
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -978,13 +1120,13 @@ var FieldsDatabase = class _FieldsDatabase {
978
1120
  this.dbPath = dbPath;
979
1121
  }
980
1122
  static async create(dbPath, options) {
981
- if (options?.recreate && import_node_fs6.default.existsSync(dbPath)) {
982
- import_node_fs6.default.unlinkSync(dbPath);
1123
+ if (options?.recreate && import_node_fs7.default.existsSync(dbPath)) {
1124
+ import_node_fs7.default.unlinkSync(dbPath);
983
1125
  }
984
1126
  const SQL = await (0, import_sql.default)();
985
1127
  let db;
986
- if (!options?.recreate && import_node_fs6.default.existsSync(dbPath)) {
987
- const buffer = import_node_fs6.default.readFileSync(dbPath);
1128
+ if (!options?.recreate && import_node_fs7.default.existsSync(dbPath)) {
1129
+ const buffer = import_node_fs7.default.readFileSync(dbPath);
988
1130
  db = new SQL.Database(buffer);
989
1131
  } else {
990
1132
  db = new SQL.Database();
@@ -1045,7 +1187,7 @@ var FieldsDatabase = class _FieldsDatabase {
1045
1187
  save() {
1046
1188
  const data = this.db.export();
1047
1189
  const buffer = Buffer.from(data);
1048
- import_node_fs6.default.writeFileSync(this.dbPath, buffer);
1190
+ import_node_fs7.default.writeFileSync(this.dbPath, buffer);
1049
1191
  }
1050
1192
  queryFields(params) {
1051
1193
  const {
@@ -1055,7 +1197,7 @@ var FieldsDatabase = class _FieldsDatabase {
1055
1197
  format,
1056
1198
  type,
1057
1199
  messageType,
1058
- message,
1200
+ message: message2,
1059
1201
  producer,
1060
1202
  consumer,
1061
1203
  required,
@@ -1089,9 +1231,9 @@ var FieldsDatabase = class _FieldsDatabase {
1089
1231
  conditions.push(`f.message_type IN (${types2.map(() => "?").join(", ")})`);
1090
1232
  bindings.push(...types2);
1091
1233
  }
1092
- if (message) {
1234
+ if (message2) {
1093
1235
  conditions.push(`f.message_id = ?`);
1094
- bindings.push(message);
1236
+ bindings.push(message2);
1095
1237
  }
1096
1238
  if (required) {
1097
1239
  conditions.push(`f.required = 1`);
@@ -1270,22 +1412,22 @@ function getAvroTypeName(type) {
1270
1412
  function walkAvroRecord(schema, prefix, fields) {
1271
1413
  if (!schema.fields || !Array.isArray(schema.fields)) return;
1272
1414
  for (const field of schema.fields) {
1273
- const path20 = prefix ? `${prefix}.${field.name}` : field.name;
1415
+ const path21 = prefix ? `${prefix}.${field.name}` : field.name;
1274
1416
  const isOptional = Array.isArray(field.type) && field.type.includes("null");
1275
1417
  const typeName = getAvroTypeName(field.type);
1276
1418
  fields.push({
1277
- path: path20,
1419
+ path: path21,
1278
1420
  type: typeName,
1279
1421
  description: field.doc || "",
1280
1422
  required: !isOptional
1281
1423
  });
1282
1424
  const innerType = Array.isArray(field.type) ? field.type.find((t) => typeof t === "object" && t.type === "record") : typeof field.type === "object" && field.type.type === "record" ? field.type : null;
1283
1425
  if (innerType) {
1284
- walkAvroRecord(innerType, path20, fields);
1426
+ walkAvroRecord(innerType, path21, fields);
1285
1427
  }
1286
1428
  const arrayType = Array.isArray(field.type) ? field.type.find((t) => typeof t === "object" && t.type === "array") : typeof field.type === "object" && field.type.type === "array" ? field.type : null;
1287
1429
  if (arrayType && typeof arrayType.items === "object" && arrayType.items.type === "record") {
1288
- walkAvroRecord(arrayType.items, `${path20}[]`, fields);
1430
+ walkAvroRecord(arrayType.items, `${path21}[]`, fields);
1289
1431
  }
1290
1432
  }
1291
1433
  }
@@ -1316,32 +1458,32 @@ function walkJsonSchema(node, prefix, requiredList, rootSchema, fields) {
1316
1458
  }
1317
1459
  if (!node.properties) return;
1318
1460
  for (const [name, prop] of Object.entries(node.properties)) {
1319
- const path20 = prefix ? `${prefix}.${name}` : name;
1461
+ const path21 = prefix ? `${prefix}.${name}` : name;
1320
1462
  const isRequired = requiredList.includes(name);
1321
1463
  if (prop.$ref) {
1322
1464
  const resolved = resolveLocalRef(prop.$ref, rootSchema);
1323
1465
  if (resolved) {
1324
1466
  const rawRefType = resolved.type || "object";
1325
1467
  const type2 = Array.isArray(rawRefType) ? [...rawRefType].sort().join(" | ") : rawRefType;
1326
- fields.push({ path: path20, type: type2, description: resolved.description || "", required: isRequired });
1468
+ fields.push({ path: path21, type: type2, description: resolved.description || "", required: isRequired });
1327
1469
  if (resolved.properties) {
1328
- walkJsonSchema(resolved, path20, resolved.required || [], rootSchema, fields);
1470
+ walkJsonSchema(resolved, path21, resolved.required || [], rootSchema, fields);
1329
1471
  }
1330
1472
  } else {
1331
- fields.push({ path: path20, type: "$ref", description: "", required: isRequired });
1473
+ fields.push({ path: path21, type: "$ref", description: "", required: isRequired });
1332
1474
  }
1333
1475
  continue;
1334
1476
  }
1335
1477
  const rawType = prop.type || (prop.enum ? "enum" : prop.$ref ? "$ref" : "object");
1336
1478
  const typeList = Array.isArray(rawType) ? rawType : [rawType];
1337
1479
  const type = Array.isArray(rawType) ? [...rawType].sort().join(" | ") : rawType;
1338
- fields.push({ path: path20, type, description: prop.description || "", required: isRequired });
1480
+ fields.push({ path: path21, type, description: prop.description || "", required: isRequired });
1339
1481
  if (typeList.includes("object") && prop.properties) {
1340
- walkJsonSchema(prop, path20, prop.required || [], rootSchema, fields);
1482
+ walkJsonSchema(prop, path21, prop.required || [], rootSchema, fields);
1341
1483
  }
1342
1484
  if (typeList.includes("array") && prop.items) {
1343
1485
  if (prop.items.type === "object" && prop.items.properties) {
1344
- walkJsonSchema(prop.items, `${path20}[]`, prop.items.required || [], rootSchema, fields);
1486
+ walkJsonSchema(prop.items, `${path21}[]`, prop.items.required || [], rootSchema, fields);
1345
1487
  }
1346
1488
  }
1347
1489
  }
@@ -1358,22 +1500,22 @@ function resolveLocalRef(ref, rootSchema) {
1358
1500
  }
1359
1501
 
1360
1502
  // eventcatalog/integrations/runtime-paths.mjs
1361
- var import_node_path9 = __toESM(require("path"), 1);
1503
+ var import_node_path10 = __toESM(require("path"), 1);
1362
1504
  function getRuntimePaths(projectDirectory, runtimeDirectory) {
1363
- const project = import_node_path9.default.resolve(projectDirectory);
1364
- const cacheDirectory = import_node_path9.default.join(project, ".astro");
1365
- const runtime = runtimeDirectory ? import_node_path9.default.resolve(runtimeDirectory) : import_node_path9.default.join(cacheDirectory, "eventcatalog");
1505
+ const project = import_node_path10.default.resolve(projectDirectory);
1506
+ const cacheDirectory = import_node_path10.default.join(project, ".astro");
1507
+ const runtime = runtimeDirectory ? import_node_path10.default.resolve(runtimeDirectory) : import_node_path10.default.join(cacheDirectory, "eventcatalog");
1366
1508
  return {
1367
1509
  projectDirectory: project,
1368
1510
  cacheDirectory,
1369
1511
  runtimeDirectory: runtime,
1370
- fieldsDatabasePath: import_node_path9.default.join(runtime, ".eventcatalog", "fields.db")
1512
+ fieldsDatabasePath: import_node_path10.default.join(runtime, ".eventcatalog", "fields.db")
1371
1513
  };
1372
1514
  }
1373
1515
 
1374
1516
  // eventcatalog/src/features/fields/field-indexer.ts
1375
1517
  function detectFormat(fileName) {
1376
- const ext = import_node_path10.default.extname(fileName).toLowerCase();
1518
+ const ext = import_node_path11.default.extname(fileName).toLowerCase();
1377
1519
  if (ext === ".proto") return "proto";
1378
1520
  if (ext === ".avro" || ext === ".avsc") return "avro";
1379
1521
  return "json-schema";
@@ -1382,9 +1524,9 @@ async function buildFieldsIndex(catalogDir, outputDir) {
1382
1524
  const sdkModule = await import("@eventcatalog/sdk");
1383
1525
  const sdk = sdkModule.default(catalogDir);
1384
1526
  const { fieldsDatabasePath: dbPath } = getRuntimePaths(catalogDir, outputDir || catalogDir);
1385
- const dbDir = import_node_path10.default.dirname(dbPath);
1386
- if (!import_node_fs7.default.existsSync(dbDir)) {
1387
- import_node_fs7.default.mkdirSync(dbDir, { recursive: true });
1527
+ const dbDir = import_node_path11.default.dirname(dbPath);
1528
+ if (!import_node_fs8.default.existsSync(dbDir)) {
1529
+ import_node_fs8.default.mkdirSync(dbDir, { recursive: true });
1388
1530
  }
1389
1531
  const db = await FieldsDatabase.create(dbPath, { recreate: true });
1390
1532
  const warnings = [];
@@ -1468,7 +1610,7 @@ async function buildFieldsIndex(catalogDir, outputDir) {
1468
1610
 
1469
1611
  // src/search-indexer.ts
1470
1612
  var import_promises4 = __toESM(require("fs/promises"), 1);
1471
- var import_node_path11 = __toESM(require("path"), 1);
1613
+ var import_node_path12 = __toESM(require("path"), 1);
1472
1614
  var import_glob3 = require("glob");
1473
1615
  var import_gray_matter4 = __toESM(require("gray-matter"), 1);
1474
1616
  var RESOURCE_COLLECTIONS = {
@@ -1532,9 +1674,9 @@ var markdownToSearchText = (content) => {
1532
1674
  };
1533
1675
  var inferDocIdFromFile = (relativePath, frontmatterId) => {
1534
1676
  if (frontmatterId) return frontmatterId;
1535
- const fileName = import_node_path11.default.posix.basename(removeExtension(relativePath));
1677
+ const fileName = import_node_path12.default.posix.basename(removeExtension(relativePath));
1536
1678
  if (fileName.toLowerCase() === "index") {
1537
- return import_node_path11.default.posix.basename(import_node_path11.default.posix.dirname(relativePath));
1679
+ return import_node_path12.default.posix.basename(import_node_path12.default.posix.dirname(relativePath));
1538
1680
  }
1539
1681
  return stripNumericPrefix(fileName);
1540
1682
  };
@@ -1552,7 +1694,7 @@ var findResourceSegment = (segments) => {
1552
1694
  return match;
1553
1695
  };
1554
1696
  var readResourceFrontmatter = async (projectDir, resourcePath) => {
1555
- const candidates = [import_node_path11.default.join(projectDir, resourcePath, "index.mdx"), import_node_path11.default.join(projectDir, resourcePath, "index.md")];
1697
+ const candidates = [import_node_path12.default.join(projectDir, resourcePath, "index.mdx"), import_node_path12.default.join(projectDir, resourcePath, "index.md")];
1556
1698
  for (const candidate of candidates) {
1557
1699
  try {
1558
1700
  const file = await import_promises4.default.readFile(candidate, "utf8");
@@ -1577,7 +1719,7 @@ var deriveRecordFromPath = async ({
1577
1719
  }
1578
1720
  if (segments[0] === "docs") {
1579
1721
  const customPath = normalizeUrlPath(removeExtension(segments.slice(1).join("/")));
1580
- const title = data.title || data.label || import_node_path11.default.posix.basename(customPath) || "Custom docs";
1722
+ const title = data.title || data.label || import_node_path12.default.posix.basename(customPath) || "Custom docs";
1581
1723
  return {
1582
1724
  url: buildUrl(`/docs/custom/${customPath}`, config),
1583
1725
  title,
@@ -1695,7 +1837,7 @@ var collectSearchRecords = async ({
1695
1837
  files.map(async (file) => {
1696
1838
  const raw = await import_promises4.default.readFile(file, "utf8");
1697
1839
  const parsed = (0, import_gray_matter4.default)(raw);
1698
- const relativePath = normalizePath(import_node_path11.default.relative(projectDir, file));
1840
+ const relativePath = normalizePath(import_node_path12.default.relative(projectDir, file));
1699
1841
  const baseRecord = await deriveRecordFromPath({
1700
1842
  projectDir,
1701
1843
  relativePath,
@@ -1743,7 +1885,7 @@ var getSearchOutputPath = ({
1743
1885
  if (searchOutputPath) {
1744
1886
  return searchOutputPath;
1745
1887
  }
1746
- return import_node_path11.default.join(outDir, isServer ? "client" : "", "pagefind");
1888
+ return import_node_path12.default.join(outDir, isServer ? "client" : "", "pagefind");
1747
1889
  };
1748
1890
  var buildSearchIndex = async ({ projectDir, outDir, config, isServer, searchOutputPath }) => {
1749
1891
  const records = await collectSearchRecords({ projectDir, config });
@@ -1797,74 +1939,74 @@ ${errors.join("\n")}`);
1797
1939
  };
1798
1940
 
1799
1941
  // src/catalog-runtime.ts
1800
- var import_node_fs8 = __toESM(require("fs"), 1);
1801
- var import_node_path12 = __toESM(require("path"), 1);
1802
- var import_node_module = require("module");
1803
- var require2 = (0, import_node_module.createRequire)(importMetaUrl);
1942
+ var import_node_fs9 = __toESM(require("fs"), 1);
1943
+ var import_node_path13 = __toESM(require("path"), 1);
1944
+ var import_node_module2 = require("module");
1945
+ var require2 = (0, import_node_module2.createRequire)(importMetaUrl);
1804
1946
  var writeIfChanged = (file, content) => {
1805
- if (import_node_fs8.default.existsSync(file) && import_node_fs8.default.readFileSync(file, "utf8") === content) return;
1806
- import_node_fs8.default.mkdirSync(import_node_path12.default.dirname(file), { recursive: true });
1807
- import_node_fs8.default.writeFileSync(file, content);
1947
+ if (import_node_fs9.default.existsSync(file) && import_node_fs9.default.readFileSync(file, "utf8") === content) return;
1948
+ import_node_fs9.default.mkdirSync(import_node_path13.default.dirname(file), { recursive: true });
1949
+ import_node_fs9.default.writeFileSync(file, content);
1808
1950
  };
1809
1951
  var importPath = (file) => file.replace(/\\/g, "/");
1810
- var hasLegacyCatalogRuntime = (projectDirectory) => import_node_fs8.default.existsSync(import_node_path12.default.join(projectDirectory, ".eventcatalog-core"));
1952
+ var hasLegacyCatalogRuntime = (projectDirectory) => import_node_fs9.default.existsSync(import_node_path13.default.join(projectDirectory, ".eventcatalog-core"));
1811
1953
  var clearCatalogCache = (projectDirectory) => {
1812
1954
  const { cacheDirectory } = getRuntimePaths(projectDirectory);
1813
- import_node_fs8.default.rmSync(cacheDirectory, { recursive: true, force: true });
1955
+ import_node_fs9.default.rmSync(cacheDirectory, { recursive: true, force: true });
1814
1956
  };
1815
1957
  var prepareCatalogRuntime = ({ projectDirectory, catalogDirectory, packageDirectory }) => {
1816
- const runtime = import_node_path12.default.resolve(catalogDirectory);
1817
- const source = import_node_path12.default.resolve(packageDirectory);
1818
- const project = import_node_path12.default.resolve(projectDirectory);
1958
+ const runtime = import_node_path13.default.resolve(catalogDirectory);
1959
+ const source = import_node_path13.default.resolve(packageDirectory);
1960
+ const project = import_node_path13.default.resolve(projectDirectory);
1819
1961
  if (runtime === source || runtime === project) {
1820
1962
  throw new Error("The catalog runtime must be separate from the project and installed application directories.");
1821
1963
  }
1822
- import_node_fs8.default.mkdirSync(runtime, { recursive: true });
1964
+ import_node_fs9.default.mkdirSync(runtime, { recursive: true });
1823
1965
  writeIfChanged(
1824
- import_node_path12.default.join(runtime, "content.config.ts"),
1825
- `export { collections } from ${JSON.stringify(importPath(import_node_path12.default.join(source, "src/content.config.ts")))};
1966
+ import_node_path13.default.join(runtime, "content.config.ts"),
1967
+ `export { collections } from ${JSON.stringify(importPath(import_node_path13.default.join(source, "src/content.config.ts")))};
1826
1968
  `
1827
1969
  );
1828
- const packageTsconfig = JSON.parse(import_node_fs8.default.readFileSync(import_node_path12.default.join(source, "tsconfig.json"), "utf8"));
1970
+ const packageTsconfig = JSON.parse(import_node_fs9.default.readFileSync(import_node_path13.default.join(source, "tsconfig.json"), "utf8"));
1829
1971
  const paths = Object.fromEntries(
1830
1972
  Object.entries(packageTsconfig.compilerOptions.paths).map(([alias, targets]) => [
1831
1973
  alias,
1832
- targets.map((target) => importPath(import_node_path12.default.resolve(source, target)))
1974
+ targets.map((target) => importPath(import_node_path13.default.resolve(source, target)))
1833
1975
  ])
1834
1976
  );
1835
- paths["@config"] = [importPath(import_node_path12.default.join(project, "eventcatalog.config.js"))];
1836
- paths["@catalog/styles"] = [importPath(import_node_path12.default.join(project, "eventcatalog.styles.css"))];
1977
+ paths["@config"] = [importPath(import_node_path13.default.join(project, "eventcatalog.config.js"))];
1978
+ paths["@catalog/styles"] = [importPath(import_node_path13.default.join(project, "eventcatalog.styles.css"))];
1837
1979
  paths["@catalog/components/*"] = [
1838
- importPath(import_node_path12.default.join(project, "components/*")),
1839
- importPath(import_node_path12.default.join(project, "federated/components/*"))
1980
+ importPath(import_node_path13.default.join(project, "components/*")),
1981
+ importPath(import_node_path13.default.join(project, "federated/components/*"))
1840
1982
  ];
1841
- paths["@catalog/snippets/*"] = [importPath(import_node_path12.default.join(project, "snippets/*"))];
1983
+ paths["@catalog/snippets/*"] = [importPath(import_node_path13.default.join(project, "snippets/*"))];
1842
1984
  for (const specifier of ["astro", "astro/zod", "astro/loaders", "astro/runtime/server/index.js"]) {
1843
1985
  paths[specifier] = [importPath(require2.resolve(specifier).replace(/\.js$/, ".d.ts"))];
1844
1986
  }
1845
1987
  writeIfChanged(
1846
- import_node_path12.default.join(runtime, "tsconfig.json"),
1988
+ import_node_path13.default.join(runtime, "tsconfig.json"),
1847
1989
  JSON.stringify(
1848
1990
  {
1849
- extends: importPath(import_node_path12.default.join(source, "tsconfig.json")),
1991
+ extends: importPath(import_node_path13.default.join(source, "tsconfig.json")),
1850
1992
  compilerOptions: {
1851
1993
  baseUrl: ".",
1852
1994
  paths,
1853
1995
  typeRoots: [
1854
- importPath(import_node_path12.default.join(project, "node_modules/@types")),
1855
- importPath(import_node_path12.default.join(source, "../node_modules/@types")),
1856
- importPath(import_node_path12.default.join(source, "../node_modules")),
1857
- importPath(import_node_path12.default.join(project, "node_modules"))
1996
+ importPath(import_node_path13.default.join(project, "node_modules/@types")),
1997
+ importPath(import_node_path13.default.join(source, "../node_modules/@types")),
1998
+ importPath(import_node_path13.default.join(source, "../node_modules")),
1999
+ importPath(import_node_path13.default.join(project, "node_modules"))
1858
2000
  ]
1859
2001
  },
1860
2002
  include: [
1861
- importPath(import_node_path12.default.join(project, ".astro/types.d.ts")),
2003
+ importPath(import_node_path13.default.join(project, ".astro/types.d.ts")),
1862
2004
  "content.config.ts",
1863
- importPath(import_node_path12.default.join(project, "components/**/*")),
1864
- importPath(import_node_path12.default.join(source, "src/**/*"))
2005
+ importPath(import_node_path13.default.join(project, "components/**/*")),
2006
+ importPath(import_node_path13.default.join(source, "src/**/*"))
1865
2007
  ],
1866
2008
  // Keep legacy generated files out of checks on an existing checkout.
1867
- exclude: (packageTsconfig.exclude ?? []).map((entry) => importPath(import_node_path12.default.resolve(source, entry)))
2009
+ exclude: (packageTsconfig.exclude ?? []).map((entry) => importPath(import_node_path13.default.resolve(source, entry)))
1868
2010
  },
1869
2011
  null,
1870
2012
  2
@@ -1904,8 +2046,8 @@ var KNOWN_EVENTCATALOG_COLLECTIONS = /* @__PURE__ */ new Set([
1904
2046
  var EMPTY_COLLECTION_MESSAGE = /^The collection ("(?:\\.|[^"\\])*") does not exist or is empty\. Please check your content config file for errors\.$/;
1905
2047
  var ANSI_PATTERN = /\u001B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
1906
2048
  var ASTRO_CONTENT_WARN_PREFIX = /^[^[\]]*\[WARN\]\s+\[content\](?:\s+\[[^\]]+\])*\s*$/;
1907
- function collectionNameFromEmptyWarning(message) {
1908
- const match = message.match(EMPTY_COLLECTION_MESSAGE);
2049
+ function collectionNameFromEmptyWarning(message2) {
2050
+ const match = message2.match(EMPTY_COLLECTION_MESSAGE);
1909
2051
  if (!match) return null;
1910
2052
  try {
1911
2053
  const name = JSON.parse(match[1]);
@@ -1914,8 +2056,8 @@ function collectionNameFromEmptyWarning(message) {
1914
2056
  return null;
1915
2057
  }
1916
2058
  }
1917
- function isIntentionalEmptyCollectionMessage(message) {
1918
- const name = collectionNameFromEmptyWarning(message);
2059
+ function isIntentionalEmptyCollectionMessage(message2) {
2060
+ const name = collectionNameFromEmptyWarning(message2);
1919
2061
  return name !== null && KNOWN_EVENTCATALOG_COLLECTIONS.has(name);
1920
2062
  }
1921
2063
  function isIntentionalEmptyCollectionLine(line) {
@@ -1923,8 +2065,8 @@ function isIntentionalEmptyCollectionLine(line) {
1923
2065
  const marker = 'The collection "';
1924
2066
  const start = plain.indexOf(marker);
1925
2067
  if (start === -1) return false;
1926
- const message = plain.slice(start).trim();
1927
- if (!isIntentionalEmptyCollectionMessage(message)) return false;
2068
+ const message2 = plain.slice(start).trim();
2069
+ if (!isIntentionalEmptyCollectionMessage(message2)) return false;
1928
2070
  const before = plain.slice(0, start).trim();
1929
2071
  return before.length === 0 || ASTRO_CONTENT_WARN_PREFIX.test(before);
1930
2072
  }
@@ -1944,8 +2086,8 @@ var createAstroDevLineFilter = () => {
1944
2086
  };
1945
2087
 
1946
2088
  // src/astro-config-path.ts
1947
- var import_node_path13 = __toESM(require("path"), 1);
1948
- var getAstroConfigPath = (projectDirectory, configFile, paths = import_node_path13.default) => {
2089
+ var import_node_path14 = __toESM(require("path"), 1);
2090
+ var getAstroConfigPath = (projectDirectory, configFile, paths = import_node_path14.default) => {
1949
2091
  const relative = paths.relative(projectDirectory, configFile);
1950
2092
  const projectRoot = paths.parse(paths.resolve(projectDirectory)).root.toLowerCase();
1951
2093
  const configRoot = paths.parse(paths.resolve(configFile)).root.toLowerCase();
@@ -1960,18 +2102,18 @@ var getAstroConfigPath = (projectDirectory, configFile, paths = import_node_path
1960
2102
  // src/federation/federate.ts
1961
2103
  var import_node_crypto5 = require("crypto");
1962
2104
  var import_promises10 = __toESM(require("fs/promises"), 1);
1963
- var import_node_path19 = __toESM(require("path"), 1);
2105
+ var import_node_path20 = __toESM(require("path"), 1);
1964
2106
  var import_sdk3 = __toESM(require("@eventcatalog/sdk"), 1);
1965
2107
 
1966
2108
  // src/federation/content-cache.ts
1967
2109
  var import_node_crypto2 = require("crypto");
1968
2110
  var import_promises5 = __toESM(require("fs/promises"), 1);
1969
- var import_node_path14 = __toESM(require("path"), 1);
2111
+ var import_node_path15 = __toESM(require("path"), 1);
1970
2112
  var getContentHash = (content) => `sha256:${(0, import_node_crypto2.createHash)("sha256").update(content).digest("hex")}`;
1971
2113
  var isContentHash = (key) => /^sha256:[a-f0-9]{64}$/i.test(key);
1972
2114
  var createFederationContentCache = (projectDirectory, options = {}) => {
1973
- const cacheDirectory = import_node_path14.default.join(projectDirectory, ".eventcatalog-cache", "federation", "content");
1974
- const getCachePath = (key) => import_node_path14.default.join(cacheDirectory, encodeURIComponent(key));
2115
+ const cacheDirectory = import_node_path15.default.join(projectDirectory, ".eventcatalog-cache", "federation", "content");
2116
+ const getCachePath = (key) => import_node_path15.default.join(cacheDirectory, encodeURIComponent(key));
1975
2117
  return {
1976
2118
  async get(key) {
1977
2119
  if (options.read === false || !isContentHash(key)) return void 0;
@@ -2158,20 +2300,20 @@ var getVisibleFederationDiagnostics = (diagnostics, verbose) => diagnostics.filt
2158
2300
 
2159
2301
  // src/federation/output-transaction.ts
2160
2302
  var import_promises6 = __toESM(require("fs/promises"), 1);
2161
- var import_node_path15 = __toESM(require("path"), 1);
2303
+ var import_node_path16 = __toESM(require("path"), 1);
2162
2304
  var getSafePublicPath = (publicDirectory, relativePath) => {
2163
- const normalizedPath = import_node_path15.default.posix.normalize(relativePath);
2164
- const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path15.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2305
+ const normalizedPath = import_node_path16.default.posix.normalize(relativePath);
2306
+ const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path16.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2165
2307
  if (unsafe) return void 0;
2166
- const destinationPath = import_node_path15.default.resolve(publicDirectory, relativePath);
2167
- const relativeDestinationPath = import_node_path15.default.relative(publicDirectory, destinationPath);
2168
- return relativeDestinationPath !== "" && relativeDestinationPath !== ".." && !relativeDestinationPath.startsWith(`..${import_node_path15.default.sep}`) && !import_node_path15.default.isAbsolute(relativeDestinationPath) ? destinationPath : void 0;
2308
+ const destinationPath = import_node_path16.default.resolve(publicDirectory, relativePath);
2309
+ const relativeDestinationPath = import_node_path16.default.relative(publicDirectory, destinationPath);
2310
+ return relativeDestinationPath !== "" && relativeDestinationPath !== ".." && !relativeDestinationPath.startsWith(`..${import_node_path16.default.sep}`) && !import_node_path16.default.isAbsolute(relativeDestinationPath) ? destinationPath : void 0;
2169
2311
  };
2170
2312
  var beginFederationOutputTransaction = async (projectDirectory, outDir, relativePublicPaths) => {
2171
- const transactionDirectory = await import_promises6.default.mkdtemp(import_node_path15.default.join(projectDirectory, ".eventcatalog-federation-transaction-"));
2172
- const previousOutDir = import_node_path15.default.join(transactionDirectory, "federated");
2173
- const publicBackupDirectory = import_node_path15.default.join(transactionDirectory, "public");
2174
- const publicDirectory = import_node_path15.default.resolve(projectDirectory, "public");
2313
+ const transactionDirectory = await import_promises6.default.mkdtemp(import_node_path16.default.join(projectDirectory, ".eventcatalog-federation-transaction-"));
2314
+ const previousOutDir = import_node_path16.default.join(transactionDirectory, "federated");
2315
+ const publicBackupDirectory = import_node_path16.default.join(transactionDirectory, "public");
2316
+ const publicDirectory = import_node_path16.default.resolve(projectDirectory, "public");
2175
2317
  const publicSnapshots = [];
2176
2318
  const missingPublicDirectories = /* @__PURE__ */ new Set();
2177
2319
  let hadPreviousOutDir = false;
@@ -2182,8 +2324,8 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2182
2324
  try {
2183
2325
  const stat = await import_promises6.default.lstat(destinationPath);
2184
2326
  if (!stat.isFile()) continue;
2185
- const backupPath = import_node_path15.default.join(publicBackupDirectory, `${publicSnapshots.length}`);
2186
- await import_promises6.default.mkdir(import_node_path15.default.dirname(backupPath), { recursive: true });
2327
+ const backupPath = import_node_path16.default.join(publicBackupDirectory, `${publicSnapshots.length}`);
2328
+ await import_promises6.default.mkdir(import_node_path16.default.dirname(backupPath), { recursive: true });
2187
2329
  await import_promises6.default.copyFile(destinationPath, backupPath);
2188
2330
  publicSnapshots.push({ backupPath, destinationPath, state: "file" });
2189
2331
  } catch (error) {
@@ -2191,7 +2333,7 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2191
2333
  if (code === "ENOTDIR") continue;
2192
2334
  if (code !== "ENOENT") throw error;
2193
2335
  publicSnapshots.push({ destinationPath, state: "missing" });
2194
- let directory = import_node_path15.default.dirname(destinationPath);
2336
+ let directory = import_node_path16.default.dirname(destinationPath);
2195
2337
  while (directory !== publicDirectory) {
2196
2338
  try {
2197
2339
  await import_promises6.default.lstat(directory);
@@ -2201,7 +2343,7 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2201
2343
  if (directoryCode === "ENOTDIR") break;
2202
2344
  if (directoryCode !== "ENOENT") throw directoryError;
2203
2345
  missingPublicDirectories.add(directory);
2204
- directory = import_node_path15.default.dirname(directory);
2346
+ directory = import_node_path16.default.dirname(directory);
2205
2347
  }
2206
2348
  }
2207
2349
  }
@@ -2237,7 +2379,7 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2237
2379
  continue;
2238
2380
  }
2239
2381
  await attempt(async () => {
2240
- await import_promises6.default.mkdir(import_node_path15.default.dirname(snapshot.destinationPath), { recursive: true });
2382
+ await import_promises6.default.mkdir(import_node_path16.default.dirname(snapshot.destinationPath), { recursive: true });
2241
2383
  await import_promises6.default.copyFile(snapshot.backupPath, snapshot.destinationPath);
2242
2384
  });
2243
2385
  }
@@ -2274,7 +2416,7 @@ var withFederationOutputTransaction = async (projectDirectory, outDir, relativeP
2274
2416
  // src/federation/public-assets.ts
2275
2417
  var import_node_crypto3 = require("crypto");
2276
2418
  var import_promises7 = __toESM(require("fs/promises"), 1);
2277
- var import_node_path16 = __toESM(require("path"), 1);
2419
+ var import_node_path17 = __toESM(require("path"), 1);
2278
2420
  var getContentHash2 = (content) => `sha256:${(0, import_node_crypto3.createHash)("sha256").update(content).digest("hex")}`;
2279
2421
  var getFileHash = async (filePath) => {
2280
2422
  try {
@@ -2286,13 +2428,13 @@ var getFileHash = async (filePath) => {
2286
2428
  }
2287
2429
  };
2288
2430
  var getSafePath = (directory, relativePath) => {
2289
- const normalizedPath = import_node_path16.default.posix.normalize(relativePath);
2290
- const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path16.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2431
+ const normalizedPath = import_node_path17.default.posix.normalize(relativePath);
2432
+ const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path17.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2291
2433
  if (unsafe) return void 0;
2292
- const resolvedDirectory = import_node_path16.default.resolve(directory);
2293
- const resolvedPath = import_node_path16.default.resolve(resolvedDirectory, relativePath);
2294
- const relativeResolvedPath = import_node_path16.default.relative(resolvedDirectory, resolvedPath);
2295
- if (relativeResolvedPath === "" || relativeResolvedPath === ".." || relativeResolvedPath.startsWith(`..${import_node_path16.default.sep}`) || import_node_path16.default.isAbsolute(relativeResolvedPath)) {
2434
+ const resolvedDirectory = import_node_path17.default.resolve(directory);
2435
+ const resolvedPath = import_node_path17.default.resolve(resolvedDirectory, relativePath);
2436
+ const relativeResolvedPath = import_node_path17.default.relative(resolvedDirectory, resolvedPath);
2437
+ if (relativeResolvedPath === "" || relativeResolvedPath === ".." || relativeResolvedPath.startsWith(`..${import_node_path17.default.sep}`) || import_node_path17.default.isAbsolute(relativeResolvedPath)) {
2296
2438
  return void 0;
2297
2439
  }
2298
2440
  return resolvedPath;
@@ -2300,16 +2442,16 @@ var getSafePath = (directory, relativePath) => {
2300
2442
  var listFiles = async (directory, relativeDirectory = "") => {
2301
2443
  let entries;
2302
2444
  try {
2303
- entries = await import_promises7.default.readdir(import_node_path16.default.join(directory, relativeDirectory), { withFileTypes: true });
2445
+ entries = await import_promises7.default.readdir(import_node_path17.default.join(directory, relativeDirectory), { withFileTypes: true });
2304
2446
  } catch (error) {
2305
2447
  if (error.code === "ENOENT") return [];
2306
2448
  throw error;
2307
2449
  }
2308
2450
  const files = await Promise.all(
2309
2451
  entries.map(async (entry) => {
2310
- const relativePath = import_node_path16.default.join(relativeDirectory, entry.name);
2452
+ const relativePath = import_node_path17.default.join(relativeDirectory, entry.name);
2311
2453
  if (entry.isDirectory()) return listFiles(directory, relativePath);
2312
- return entry.isFile() ? [relativePath.split(import_node_path16.default.sep).join("/")] : [];
2454
+ return entry.isFile() ? [relativePath.split(import_node_path17.default.sep).join("/")] : [];
2313
2455
  })
2314
2456
  );
2315
2457
  return files.flat().sort();
@@ -2324,19 +2466,19 @@ var pathExists = async (filePath) => {
2324
2466
  }
2325
2467
  };
2326
2468
  var hasBlockingParent = async (publicDirectory, destinationPath) => {
2327
- let currentPath = import_node_path16.default.dirname(destinationPath);
2469
+ let currentPath = import_node_path17.default.dirname(destinationPath);
2328
2470
  while (currentPath !== publicDirectory) {
2329
2471
  try {
2330
2472
  if (!(await import_promises7.default.lstat(currentPath)).isDirectory()) return true;
2331
2473
  } catch (error) {
2332
2474
  if (error.code !== "ENOENT") throw error;
2333
2475
  }
2334
- currentPath = import_node_path16.default.dirname(currentPath);
2476
+ currentPath = import_node_path17.default.dirname(currentPath);
2335
2477
  }
2336
2478
  return false;
2337
2479
  };
2338
2480
  var pruneEmptyDirectories = async (publicDirectory, filePath) => {
2339
- let currentPath = import_node_path16.default.dirname(filePath);
2481
+ let currentPath = import_node_path17.default.dirname(filePath);
2340
2482
  while (currentPath !== publicDirectory) {
2341
2483
  try {
2342
2484
  await import_promises7.default.rmdir(currentPath);
@@ -2344,7 +2486,7 @@ var pruneEmptyDirectories = async (publicDirectory, filePath) => {
2344
2486
  if (!["ENOENT", "ENOTEMPTY"].includes(error.code ?? "")) throw error;
2345
2487
  if (error.code === "ENOTEMPTY") return;
2346
2488
  }
2347
- currentPath = import_node_path16.default.dirname(currentPath);
2489
+ currentPath = import_node_path17.default.dirname(currentPath);
2348
2490
  }
2349
2491
  };
2350
2492
  var composePublicAssets = async ({
@@ -2354,8 +2496,8 @@ var composePublicAssets = async ({
2354
2496
  previousFiles = {},
2355
2497
  collisionPaths = /* @__PURE__ */ new Set()
2356
2498
  }) => {
2357
- const publicDirectory = import_node_path16.default.resolve(projectDirectory, "public");
2358
- const federatedPublicDirectory = import_node_path16.default.resolve(federatedDirectory, "public");
2499
+ const publicDirectory = import_node_path17.default.resolve(projectDirectory, "public");
2500
+ const federatedPublicDirectory = import_node_path17.default.resolve(federatedDirectory, "public");
2359
2501
  const sourceFiles = await listFiles(federatedPublicDirectory);
2360
2502
  const sourceFileSet = new Set(sourceFiles);
2361
2503
  const managedFiles = /* @__PURE__ */ new Set();
@@ -2391,7 +2533,7 @@ var composePublicAssets = async ({
2391
2533
  const asset = publicAssetsByPath.get(relativePath);
2392
2534
  if (!asset) throw new Error(`Cannot identify the source of federated public asset "${relativePath}"`);
2393
2535
  const content = await import_promises7.default.readFile(sourcePath);
2394
- await import_promises7.default.mkdir(import_node_path16.default.dirname(destinationPath), { recursive: true });
2536
+ await import_promises7.default.mkdir(import_node_path17.default.dirname(destinationPath), { recursive: true });
2395
2537
  await import_promises7.default.writeFile(destinationPath, content);
2396
2538
  files[relativePath] = { source: asset.resolvedFrom.source, hash: getContentHash2(content) };
2397
2539
  copied += 1;
@@ -2404,17 +2546,17 @@ var composePublicAssets = async ({
2404
2546
  // src/federation/filesystem-source-provider.ts
2405
2547
  var import_node_crypto4 = require("crypto");
2406
2548
  var import_promises8 = __toESM(require("fs/promises"), 1);
2407
- var import_node_path17 = __toESM(require("path"), 1);
2549
+ var import_node_path18 = __toESM(require("path"), 1);
2408
2550
  var import_sdk = __toESM(require("@eventcatalog/sdk"), 1);
2409
2551
  var FILESYSTEM_SOURCE_PREFIX = "file:";
2410
2552
  var isWithinDirectory = (directory, target) => {
2411
- const relativePath = import_node_path17.default.relative(directory, target);
2412
- return relativePath === "" || !relativePath.startsWith(`..${import_node_path17.default.sep}`) && relativePath !== ".." && !import_node_path17.default.isAbsolute(relativePath);
2553
+ const relativePath = import_node_path18.default.relative(directory, target);
2554
+ return relativePath === "" || !relativePath.startsWith(`..${import_node_path18.default.sep}`) && relativePath !== ".." && !import_node_path18.default.isAbsolute(relativePath);
2413
2555
  };
2414
2556
  var assertPortableRelativePath = (filePath, label, allowRoot = true) => {
2415
2557
  const portablePath = filePath.replaceAll("\\", "/");
2416
- const normalizedPath = import_node_path17.default.posix.normalize(portablePath);
2417
- const isUnsafe = filePath.includes("\\") || filePath.includes("\0") || import_node_path17.default.posix.isAbsolute(normalizedPath) || /^[a-zA-Z]:\//.test(normalizedPath) || normalizedPath === ".." || normalizedPath.startsWith("../") || !allowRoot && (normalizedPath === "." || normalizedPath === "");
2558
+ const normalizedPath = import_node_path18.default.posix.normalize(portablePath);
2559
+ const isUnsafe = filePath.includes("\\") || filePath.includes("\0") || import_node_path18.default.posix.isAbsolute(normalizedPath) || /^[a-zA-Z]:\//.test(normalizedPath) || normalizedPath === ".." || normalizedPath.startsWith("../") || !allowRoot && (normalizedPath === "." || normalizedPath === "");
2418
2560
  if (isUnsafe) throw new Error(`${label} "${filePath}" escapes its filesystem source`);
2419
2561
  return normalizedPath;
2420
2562
  };
@@ -2424,13 +2566,13 @@ var getSourceRoot = (projectDirectory, source) => {
2424
2566
  }
2425
2567
  const locator = source.source.slice(FILESYSTEM_SOURCE_PREFIX.length);
2426
2568
  if (!locator.trim()) throw new Error(`Filesystem federation source "${source.id}" requires a path after "file:".`);
2427
- return import_node_path17.default.resolve(projectDirectory, locator);
2569
+ return import_node_path18.default.resolve(projectDirectory, locator);
2428
2570
  };
2429
2571
  var getCatalogDirectory = async (projectDirectory, source) => {
2430
2572
  if (source.ref) throw new Error(`Filesystem federation source "${source.id}" does not support "ref".`);
2431
2573
  const sourceRoot = getSourceRoot(projectDirectory, source);
2432
2574
  const catalogPath = assertPortableRelativePath(source.path ?? ".", "Catalog path");
2433
- const catalogDirectory = import_node_path17.default.resolve(sourceRoot, ...catalogPath.split("/"));
2575
+ const catalogDirectory = import_node_path18.default.resolve(sourceRoot, ...catalogPath.split("/"));
2434
2576
  if (!isWithinDirectory(sourceRoot, catalogDirectory)) {
2435
2577
  throw new Error(`Catalog path "${source.path}" escapes source "${source.id}"`);
2436
2578
  }
@@ -2452,7 +2594,7 @@ var getCatalogDirectory = async (projectDirectory, source) => {
2452
2594
  };
2453
2595
  var getArtifactPath = async (catalogDirectory, source, artifactPath) => {
2454
2596
  const normalizedPath = assertPortableRelativePath(artifactPath, "Federated artifact path", false);
2455
- const filePath = import_node_path17.default.resolve(catalogDirectory, ...normalizedPath.split("/"));
2597
+ const filePath = import_node_path18.default.resolve(catalogDirectory, ...normalizedPath.split("/"));
2456
2598
  if (!isWithinDirectory(catalogDirectory, filePath)) {
2457
2599
  throw new Error(`Federated artifact path "${artifactPath}" escapes source "${source.id}"`);
2458
2600
  }
@@ -2492,7 +2634,7 @@ var createFileSystemSourceProvider = (projectDirectory) => ({
2492
2634
  var import_node_child_process = require("child_process");
2493
2635
  var import_promises9 = __toESM(require("fs/promises"), 1);
2494
2636
  var import_node_os3 = __toESM(require("os"), 1);
2495
- var import_node_path18 = __toESM(require("path"), 1);
2637
+ var import_node_path19 = __toESM(require("path"), 1);
2496
2638
  var import_node_util = require("util");
2497
2639
  var import_sdk2 = __toESM(require("@eventcatalog/sdk"), 1);
2498
2640
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
@@ -2503,8 +2645,8 @@ var parseGitHubSource = (source) => {
2503
2645
  };
2504
2646
  var assertSafeCatalogPath = (source) => {
2505
2647
  const catalogPath = source.path ?? ".";
2506
- const normalized = import_node_path18.default.posix.normalize(catalogPath.replaceAll("\\", "/"));
2507
- if (catalogPath.includes("\\") || import_node_path18.default.posix.isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
2648
+ const normalized = import_node_path19.default.posix.normalize(catalogPath.replaceAll("\\", "/"));
2649
+ if (catalogPath.includes("\\") || import_node_path19.default.posix.isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
2508
2650
  throw new Error(`Catalog path "${catalogPath}" escapes source "${source.id}"`);
2509
2651
  }
2510
2652
  };
@@ -2547,8 +2689,8 @@ var getGitEnvironment = (token) => {
2547
2689
  };
2548
2690
  var createCheckout = (executeFile, token) => async (source, ref, callback) => {
2549
2691
  const { owner, repository } = parseGitHubSource(source);
2550
- const catalogPath = import_node_path18.default.posix.normalize(source.path ?? ".");
2551
- const directory = await import_promises9.default.mkdtemp(import_node_path18.default.join(import_node_os3.default.tmpdir(), "eventcatalog-federation-"));
2692
+ const catalogPath = import_node_path19.default.posix.normalize(source.path ?? ".");
2693
+ const directory = await import_promises9.default.mkdtemp(import_node_path19.default.join(import_node_os3.default.tmpdir(), "eventcatalog-federation-"));
2552
2694
  const env = getGitEnvironment(token);
2553
2695
  try {
2554
2696
  const git = (args) => executeFile("git", args, { cwd: directory, env, encoding: "utf8" });
@@ -2568,16 +2710,16 @@ var createCheckout = (executeFile, token) => async (source, ref, callback) => {
2568
2710
  var generateIndex = async (source, ref, checkout, executeFile) => checkout(source, ref, async (directory) => {
2569
2711
  const { stdout } = await executeFile("git", ["rev-parse", "HEAD"], { cwd: directory, encoding: "utf8" });
2570
2712
  const commit = stdout.trim();
2571
- const catalogDirectory = import_node_path18.default.resolve(directory, source.path ?? ".");
2572
- const relativeCatalogDirectory = import_node_path18.default.relative(directory, catalogDirectory);
2573
- if (relativeCatalogDirectory.startsWith("..") || import_node_path18.default.isAbsolute(relativeCatalogDirectory)) {
2713
+ const catalogDirectory = import_node_path19.default.resolve(directory, source.path ?? ".");
2714
+ const relativeCatalogDirectory = import_node_path19.default.relative(directory, catalogDirectory);
2715
+ if (relativeCatalogDirectory.startsWith("..") || import_node_path19.default.isAbsolute(relativeCatalogDirectory)) {
2574
2716
  throw new Error(`Catalog path "${source.path}" escapes source "${source.id}"`);
2575
2717
  }
2576
2718
  const index = await (0, import_sdk2.default)(catalogDirectory).buildIndex({ source: source.id, commit });
2577
2719
  return { bytes: Buffer.from(JSON.stringify(index)), index, commit, generated: true };
2578
2720
  });
2579
2721
  var fetchPublishedIndex = async (source, ref, fetcher, token) => {
2580
- const indexPath = import_node_path18.default.posix.join(source.path ?? ".", "catalog.index.json");
2722
+ const indexPath = import_node_path19.default.posix.join(source.path ?? ".", "catalog.index.json");
2581
2723
  const bytes = await fetchBytes(source, ref, indexPath, fetcher, token);
2582
2724
  if (!bytes) return void 0;
2583
2725
  const index = (0, import_sdk2.parseIndex)(JSON.parse(bytes.toString("utf8")));
@@ -2600,7 +2742,7 @@ var createGitHubSourceProvider = (options = {}) => {
2600
2742
  },
2601
2743
  async fetchContent({ source, commit, path: artifactPath }) {
2602
2744
  assertSafeCatalogPath(source);
2603
- const catalogPath = import_node_path18.default.posix.join(source.path ?? ".", artifactPath);
2745
+ const catalogPath = import_node_path19.default.posix.join(source.path ?? ".", artifactPath);
2604
2746
  const content = await fetchBytes(source, commit, catalogPath, fetcher, token);
2605
2747
  if (!content) throw new Error(`Federated artifact not found for "${source.id}": ${artifactPath}`);
2606
2748
  return content;
@@ -2711,8 +2853,8 @@ var pathExists2 = async (filePath) => {
2711
2853
  }
2712
2854
  };
2713
2855
  var cleanupPreviousFederation = async (projectDirectory, onProgress) => {
2714
- const outDir = import_node_path19.default.join(projectDirectory, "federated");
2715
- const lockPath = import_node_path19.default.join(projectDirectory, "eventcatalog.lock");
2856
+ const outDir = import_node_path20.default.join(projectDirectory, "federated");
2857
+ const lockPath = import_node_path20.default.join(projectDirectory, "eventcatalog.lock");
2716
2858
  const previousLock = await readLock(lockPath);
2717
2859
  const hadFederatedOutput = await pathExists2(outDir);
2718
2860
  const hadLock = previousLock !== void 0;
@@ -2768,12 +2910,12 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2768
2910
  generated: resolved.generated
2769
2911
  });
2770
2912
  } catch (error) {
2771
- const message = error instanceof Error ? error.message : String(error);
2772
- throw new Error(`Failed to federate source "${source.id}": ${message}`, { cause: error });
2913
+ const message2 = error instanceof Error ? error.message : String(error);
2914
+ throw new Error(`Failed to federate source "${source.id}": ${message2}`, { cause: error });
2773
2915
  }
2774
2916
  }
2775
- const outDir = import_node_path19.default.join(projectDirectory, "federated");
2776
- const lockPath = import_node_path19.default.join(projectDirectory, "eventcatalog.lock");
2917
+ const outDir = import_node_path20.default.join(projectDirectory, "federated");
2918
+ const lockPath = import_node_path20.default.join(projectDirectory, "eventcatalog.lock");
2777
2919
  const previousLock = await readLock(lockPath);
2778
2920
  const resources = resolvedSources.reduce((total, source) => total + source.resolved.index.resources.length, 0);
2779
2921
  const remoteIndexes = resolvedSources.map(({ resolved }) => resolved.index);
@@ -2885,16 +3027,17 @@ Run npm i @eventcatalog/core to update`;
2885
3027
  };
2886
3028
 
2887
3029
  // src/eventcatalog.ts
2888
- var currentDir = import_node_path21.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
2889
- var astroCli = import_node_path21.default.join(import_node_path21.default.dirname((0, import_node_module2.createRequire)(importMetaUrl).resolve("astro/package.json")), "bin/astro.mjs");
3030
+ var currentDir = import_node_path22.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
3031
+ var astroCli = import_node_path22.default.join(import_node_path22.default.dirname((0, import_node_module3.createRequire)(importMetaUrl).resolve("astro/package.json")), "bin/astro.mjs");
3032
+ var ASTRO_IN_FOREGROUND = { ASTRO_DEV_BACKGROUND: "1", ASTRO_PREVIEW_BACKGROUND: "1" };
2890
3033
  var program = new import_commander.Command().version(VERSION);
2891
- var dir = import_node_path21.default.resolve(process.env.PROJECT_DIR || process.cwd());
2892
- var eventCatalogDir = import_node_path21.default.resolve((0, import_node_path20.join)(currentDir, "../eventcatalog/"));
2893
- var astroConfigPath = () => getAstroConfigPath(dir, (0, import_node_path20.join)(eventCatalogDir, "astro.config.mjs"));
3034
+ var dir = import_node_path22.default.resolve(process.env.PROJECT_DIR || process.cwd());
3035
+ var eventCatalogDir = import_node_path22.default.resolve((0, import_node_path21.join)(currentDir, "../eventcatalog/"));
3036
+ var astroConfigPath = () => getAstroConfigPath(dir, (0, import_node_path21.join)(eventCatalogDir, "astro.config.mjs"));
2894
3037
  var { runtimeDirectory: core } = getRuntimePaths(dir);
2895
3038
  var getInstalledEventCatalogVersion = () => {
2896
3039
  try {
2897
- const pkg = import_fs.default.readFileSync((0, import_node_path20.join)(dir, "package.json"), "utf8");
3040
+ const pkg = import_fs.default.readFileSync((0, import_node_path21.join)(dir, "package.json"), "utf8");
2898
3041
  const json = JSON.parse(pkg);
2899
3042
  return json.dependencies["@eventcatalog/core"];
2900
3043
  } catch (error) {
@@ -2918,7 +3061,7 @@ var resolveDevPort = async ({ projectDir }) => {
2918
3061
  };
2919
3062
  var startDevPrewarm = ({
2920
3063
  port = 3e3,
2921
- paths = ["/ping", "/"],
3064
+ paths = ["/"],
2922
3065
  retries = 80,
2923
3066
  intervalMs = 250,
2924
3067
  initialDelayMs = 500
@@ -2927,10 +3070,13 @@ var startDevPrewarm = ({
2927
3070
  const hit = (requestPath) => new Promise((resolve2) => {
2928
3071
  const req = import_node_http.default.get(
2929
3072
  {
2930
- hostname: "127.0.0.1",
3073
+ // Not 127.0.0.1: the dev server can listen on IPv6 only ([::1]), which refused
3074
+ // every prewarm request
3075
+ hostname: "localhost",
2931
3076
  port,
2932
3077
  path: requestPath,
2933
- timeout: 1200
3078
+ // A refused connection fails at once; once connected, let the first render finish
3079
+ timeout: 3e4
2934
3080
  },
2935
3081
  (res) => {
2936
3082
  res.resume();
@@ -2960,12 +3106,12 @@ var startDevPrewarm = ({
2960
3106
  var buildDevSearchIndex = async ({ config }) => {
2961
3107
  const result = await buildSearchIndex({
2962
3108
  projectDir: dir,
2963
- outDir: import_node_path21.default.join(core, "public"),
2964
- searchOutputPath: import_node_path21.default.join(core, "public", "pagefind"),
3109
+ outDir: import_node_path22.default.join(core, "public"),
3110
+ searchOutputPath: import_node_path22.default.join(core, "public", "pagefind"),
2965
3111
  config,
2966
3112
  isServer: false
2967
3113
  });
2968
- logger.info(`Indexed ${result.records} page(s) into ${import_node_path21.default.relative(core, result.outputPath)}`, "search");
3114
+ logger.info(`Indexed ${result.records} page(s) into ${import_node_path22.default.relative(core, result.outputPath)}`, "search");
2969
3115
  };
2970
3116
  var warnIfIndexedSearchUsesAuth = async () => {
2971
3117
  if (!await isAuthEnabled()) {
@@ -3028,10 +3174,14 @@ var runCommandWithFilteredOutput = async ({
3028
3174
  cwd,
3029
3175
  env: {
3030
3176
  ...process.env,
3177
+ // Astro sends usage data (commands, config, machine details) to Astro by default: turn it off
3178
+ // for everyone using EventCatalog
3179
+ ASTRO_TELEMETRY_DISABLED: "1",
3031
3180
  ...env
3032
3181
  },
3033
3182
  stdio: ["inherit", "pipe", "pipe"]
3034
3183
  });
3184
+ const signals = stopChildWithParent(child);
3035
3185
  let stdoutBuffer = "";
3036
3186
  let stderrBuffer = "";
3037
3187
  const flush = (buffer, writer, isFinal = false) => {
@@ -3059,11 +3209,13 @@ var runCommandWithFilteredOutput = async ({
3059
3209
  stderrBuffer = flush(stderrBuffer, process.stderr);
3060
3210
  });
3061
3211
  child.on("error", (error) => {
3212
+ signals.childClosed();
3062
3213
  reject(error);
3063
3214
  });
3064
3215
  child.on("close", (code) => {
3065
3216
  stdoutBuffer = flush(stdoutBuffer, process.stdout, true);
3066
3217
  stderrBuffer = flush(stderrBuffer, process.stderr, true);
3218
+ if (signals.childClosed()) return;
3067
3219
  if (code === 0) {
3068
3220
  resolve2();
3069
3221
  return;
@@ -3114,10 +3266,10 @@ Upgrade now: npm i @eventcatalog/core@beta`;
3114
3266
  if (!installedVersion) return;
3115
3267
  const pkg = { name: "@eventcatalog/core", version: installedVersion };
3116
3268
  const notifier = (0, import_update_notifier.default)({ pkg, updateCheckInterval: 0 });
3117
- const message = getEventCatalogUpdateMessage(installedVersion, notifier.update?.latest);
3118
- if (message) {
3269
+ const message2 = getEventCatalogUpdateMessage(installedVersion, notifier.update?.latest);
3270
+ if (message2) {
3119
3271
  console.log(
3120
- (0, import_boxen2.default)(message, {
3272
+ (0, import_boxen2.default)(message2, {
3121
3273
  padding: 1,
3122
3274
  margin: 1,
3123
3275
  align: "center",
@@ -3141,8 +3293,8 @@ program.command("dev").description("Run development server of EventCatalog").opt
3141
3293
  logger.info("Setting up EventCatalog...", "eventcatalog");
3142
3294
  const isServer = await isOutputServer();
3143
3295
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
3144
- if (import_fs.default.existsSync(import_node_path21.default.join(dir, ".env"))) {
3145
- import_dotenv.default.config({ path: import_node_path21.default.join(dir, ".env") });
3296
+ if (import_fs.default.existsSync(import_node_path22.default.join(dir, ".env"))) {
3297
+ import_dotenv.default.config({ path: import_node_path22.default.join(dir, ".env") });
3146
3298
  }
3147
3299
  if (options.debug) {
3148
3300
  logger.info("Debug mode enabled", "debug");
@@ -3189,7 +3341,9 @@ program.command("dev").description("Run development server of EventCatalog").opt
3189
3341
  });
3190
3342
  startDevPrewarm({
3191
3343
  port: prewarmPort,
3192
- paths: ["/ping", "/"]
3344
+ // Renders the homepage before anyone opens it. Requests stop at the first response,
3345
+ // so a probe path like /ping first would leave the homepage cold.
3346
+ paths: ["/"]
3193
3347
  });
3194
3348
  }
3195
3349
  await runCommandWithFilteredOutput({
@@ -3201,7 +3355,8 @@ program.command("dev").description("Run development server of EventCatalog").opt
3201
3355
  CATALOG_DIR: core,
3202
3356
  EVENTCATALOG_DEV_MODE: "true",
3203
3357
  IGNORE_BUILD_ARTIFACTS: "true",
3204
- NODE_NO_WARNINGS: "1"
3358
+ NODE_NO_WARNINGS: "1",
3359
+ ...ASTRO_IN_FOREGROUND
3205
3360
  },
3206
3361
  shouldFilterLine: createAstroDevLineFilter(),
3207
3362
  transformLine: replaceAstroReadyVersionLine
@@ -3217,8 +3372,8 @@ program.command("build").description("Run build of EventCatalog").action(async (
3217
3372
  logger.info("Building EventCatalog...", "build");
3218
3373
  const isServer = await isOutputServer();
3219
3374
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
3220
- if (import_fs.default.existsSync(import_node_path21.default.join(dir, ".env"))) {
3221
- import_dotenv.default.config({ path: import_node_path21.default.join(dir, ".env") });
3375
+ if (import_fs.default.existsSync(import_node_path22.default.join(dir, ".env"))) {
3376
+ import_dotenv.default.config({ path: import_node_path22.default.join(dir, ".env") });
3222
3377
  }
3223
3378
  await verifyRequiredFieldsAreInCatalogConfigFile(dir);
3224
3379
  const config = await getEventCatalogConfigFile(dir);
@@ -3255,7 +3410,7 @@ program.command("build").description("Run build of EventCatalog").action(async (
3255
3410
  });
3256
3411
  if (await isIndexedSearchEnabled()) {
3257
3412
  await warnIfIndexedSearchUsesAuth();
3258
- const outDir = import_node_path21.default.resolve(dir, await getProjectOutDir());
3413
+ const outDir = import_node_path22.default.resolve(dir, await getProjectOutDir());
3259
3414
  logger.info("Building indexed search...", "search");
3260
3415
  const result = await buildSearchIndex({
3261
3416
  projectDir: dir,
@@ -3263,7 +3418,7 @@ program.command("build").description("Run build of EventCatalog").action(async (
3263
3418
  config,
3264
3419
  isServer
3265
3420
  });
3266
- logger.info(`Indexed ${result.records} page(s) into ${import_node_path21.default.relative(dir, result.outputPath)}`, "search");
3421
+ logger.info(`Indexed ${result.records} page(s) into ${import_node_path22.default.relative(dir, result.outputPath)}`, "search");
3267
3422
  }
3268
3423
  });
3269
3424
  var previewCatalog = async ({ command }) => {
@@ -3273,20 +3428,39 @@ var previewCatalog = async ({ command }) => {
3273
3428
  cwd: dir,
3274
3429
  env: {
3275
3430
  PROJECT_DIR: dir,
3276
- CATALOG_DIR: core
3431
+ CATALOG_DIR: core,
3432
+ ...ASTRO_IN_FOREGROUND
3277
3433
  },
3278
3434
  shouldFilterLine: createAstroLineFilter()
3279
3435
  });
3280
3436
  };
3437
+ var SERVER_BOOTSTRAP = `
3438
+ const entry = await import(process.argv[1]);
3439
+ const { server } = entry.startServer();
3440
+ globalThis[Symbol.for('eventcatalog.http-server')] = server.server;
3441
+ const start = process.env.EVENTCATALOG_START_PATH;
3442
+ if (start) {
3443
+ server.server.once('listening', () => {
3444
+ // Where the server listens (HOST can be one address only); loopback when it listens on every address
3445
+ const { address, port } = server.server.address();
3446
+ const host = ['0.0.0.0', '::'].includes(address) ? '127.0.0.1' : address.includes(':') ? '[' + address + ']' : address;
3447
+ fetch('http://' + host + ':' + port + start).catch((error) => console.error('[eventcatalog] Could not start the server:', error.message));
3448
+ });
3449
+ }
3450
+ `;
3281
3451
  var startServerCatalog = async () => {
3282
- const serverEntryPath = import_node_path21.default.join(dir, "dist", "server", "entry.mjs");
3452
+ const serverEntryPath = import_node_path22.default.join(dir, "dist", "server", "entry.mjs");
3453
+ const config = await getEventCatalogConfigFile(dir);
3454
+ const base = (config?.base || "/").replace(/\/$/, "");
3283
3455
  await runCommandWithFilteredOutput({
3284
3456
  command: process.execPath,
3285
- args: [serverEntryPath],
3457
+ args: ["--input-type=module", "-e", SERVER_BOOTSTRAP, (0, import_node_url2.pathToFileURL)(serverEntryPath).href],
3286
3458
  cwd: dir,
3287
3459
  env: {
3288
3460
  PROJECT_DIR: dir,
3289
- CATALOG_DIR: core
3461
+ CATALOG_DIR: core,
3462
+ ASTRO_NODE_AUTOSTART: "disabled",
3463
+ EVENTCATALOG_START_PATH: `${base}/_eventcatalog/start`
3290
3464
  },
3291
3465
  shouldFilterLine: createAstroLineFilter()
3292
3466
  });
@@ -3294,20 +3468,21 @@ var startServerCatalog = async () => {
3294
3468
  program.command("preview").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
3295
3469
  logger.welcome();
3296
3470
  logger.info("Starting preview of your build...", "preview");
3297
- if (import_fs.default.existsSync(import_node_path21.default.join(dir, ".env"))) {
3298
- import_dotenv.default.config({ path: import_node_path21.default.join(dir, ".env") });
3471
+ if (import_fs.default.existsSync(import_node_path22.default.join(dir, ".env"))) {
3472
+ import_dotenv.default.config({ path: import_node_path22.default.join(dir, ".env") });
3299
3473
  }
3300
3474
  await previewCatalog({ command });
3301
3475
  });
3302
3476
  program.command("start").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
3303
3477
  logger.welcome();
3304
3478
  logger.info("Starting preview of your build...", "preview");
3305
- if (import_fs.default.existsSync(import_node_path21.default.join(dir, ".env"))) {
3306
- import_dotenv.default.config({ path: import_node_path21.default.join(dir, ".env") });
3479
+ if (import_fs.default.existsSync(import_node_path22.default.join(dir, ".env"))) {
3480
+ import_dotenv.default.config({ path: import_node_path22.default.join(dir, ".env") });
3307
3481
  }
3308
3482
  const isServerOutput = await isOutputServer();
3309
3483
  if (isServerOutput) {
3310
- await getLicenseStatus2(dir);
3484
+ const license = await getLicenseStatus2(dir);
3485
+ void log_build_default(dir, { command: "start", license });
3311
3486
  await startServerCatalog();
3312
3487
  } else {
3313
3488
  await previewCatalog({ command });
@@ -3316,22 +3491,22 @@ program.command("start").description("Serves the contents of your eventcatalog b
3316
3491
  program.command("export").description("Export your EventCatalog using the SDK dumpCatalog function").option("--include-markdown", "Include markdown content in the export", false).action(async (options) => {
3317
3492
  logger.welcome();
3318
3493
  logger.info("Exporting EventCatalog...", "export");
3319
- if (import_fs.default.existsSync(import_node_path21.default.join(dir, ".env"))) {
3320
- import_dotenv.default.config({ path: import_node_path21.default.join(dir, ".env") });
3494
+ if (import_fs.default.existsSync(import_node_path22.default.join(dir, ".env"))) {
3495
+ import_dotenv.default.config({ path: import_node_path22.default.join(dir, ".env") });
3321
3496
  }
3322
3497
  const { default: initSDK } = await import("@eventcatalog/sdk");
3323
3498
  const sdk = initSDK(dir);
3324
3499
  const catalog = await sdk.dumpCatalog({ includeMarkdown: options.includeMarkdown });
3325
- const exportsDir = import_node_path21.default.join(dir, "exports");
3500
+ const exportsDir = import_node_path22.default.join(dir, "exports");
3326
3501
  ensureDir(exportsDir);
3327
3502
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
3328
- const exportFile = import_node_path21.default.join(exportsDir, `catalog-${date}.json`);
3503
+ const exportFile = import_node_path22.default.join(exportsDir, `catalog-${date}.json`);
3329
3504
  import_fs.default.writeFileSync(exportFile, JSON.stringify(catalog, null, 2), "utf-8");
3330
3505
  logger.info(`Catalog exported to ${exportFile}`, "export");
3331
3506
  });
3332
3507
  program.command("generate [siteDir]").description("Start the generator scripts.").action(async () => {
3333
- if (import_fs.default.existsSync(import_node_path21.default.join(dir, ".env"))) {
3334
- import_dotenv.default.config({ path: import_node_path21.default.join(dir, ".env") });
3508
+ if (import_fs.default.existsSync(import_node_path22.default.join(dir, ".env"))) {
3509
+ import_dotenv.default.config({ path: import_node_path22.default.join(dir, ".env") });
3335
3510
  }
3336
3511
  await generate(dir);
3337
3512
  });
@@ -3404,7 +3579,7 @@ var reportFederationProgress = (event, verbose = false) => {
3404
3579
  }
3405
3580
  return;
3406
3581
  case "hydrating":
3407
- logger.info(`Hydrating federated content into ${import_node_path21.default.relative(dir, event.outDir)}/...`, "federation");
3582
+ logger.info(`Hydrating federated content into ${import_node_path22.default.relative(dir, event.outDir)}/...`, "federation");
3408
3583
  return;
3409
3584
  case "hydrate:cache":
3410
3585
  if (event.files === 1 || event.files % 25 === 0) {
@@ -3427,13 +3602,13 @@ var reportFederationProgress = (event, verbose = false) => {
3427
3602
  `Federation complete: ${event.result.sources} sources, ${event.result.resources} remote resources, ${event.result.hydrate.written} files written (${event.result.hydrate.fetched} downloaded, ${event.result.hydrate.written - event.result.hydrate.fetched} cached)`,
3428
3603
  "federation"
3429
3604
  );
3430
- logger.info(`Recorded resolved source state in ${import_node_path21.default.relative(dir, event.result.lockPath)}`, "federation");
3605
+ logger.info(`Recorded resolved source state in ${import_node_path22.default.relative(dir, event.result.lockPath)}`, "federation");
3431
3606
  }
3432
3607
  };
3433
3608
  program.command("federate").description("Fetch, resolve, and hydrate the catalogs configured in federation.sources.").option("--no-cache", "Download all federation content and refresh the cache.").option("-v, --verbose", "Show detailed federation diagnostics.").action(async (commandOptions) => {
3434
3609
  logger.welcome();
3435
- if (import_fs.default.existsSync(import_node_path21.default.join(dir, ".env"))) {
3436
- import_dotenv.default.config({ path: import_node_path21.default.join(dir, ".env") });
3610
+ if (import_fs.default.existsSync(import_node_path22.default.join(dir, ".env"))) {
3611
+ import_dotenv.default.config({ path: import_node_path22.default.join(dir, ".env") });
3437
3612
  }
3438
3613
  logger.info("Starting federation...", "federation");
3439
3614
  let cleanedPreviousOutput = false;
@@ -3454,7 +3629,7 @@ program.addHelpText(
3454
3629
  Example: npx eventcatalog dev --debug -- --env=production --port=3000
3455
3630
  `
3456
3631
  );
3457
- program.parseAsync().then(() => process.exit(0)).catch((err) => {
3632
+ program.parseAsync().then(() => process.exit()).catch((err) => {
3458
3633
  if (!(err instanceof FederationConflictError) && !(err instanceof FederationDiagnosticError)) console.error(err);
3459
3634
  process.exit(1);
3460
3635
  });