@eventcatalog/core 5.0.0-beta.8 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) 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 +157 -76
  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-AWOO63ME.js → chunk-AD7CL772.js} +11 -4
  22. package/dist/chunk-CA6WCQ2T.js +54 -0
  23. package/dist/chunk-CPW6G62V.js +17 -0
  24. package/dist/{chunk-PU25TOOJ.js → chunk-JZN4RSMF.js} +1 -1
  25. package/dist/{chunk-4W55ZOOS.js → chunk-NEAVAFSJ.js} +66 -35
  26. package/dist/{chunk-C6T2AAFR.js → chunk-NIVST4WY.js} +9 -3
  27. package/dist/{chunk-ENAG6UH7.js → chunk-NKNOXQ62.js} +1 -6
  28. package/dist/{chunk-AYNZXUB5.js → chunk-OX6TSVHY.js} +5 -5
  29. package/dist/{chunk-36RYTYT5.js → chunk-PD7KTSYN.js} +1 -1
  30. package/dist/{chunk-RDIZJ7UT.js → chunk-RE7UTPWH.js} +1 -1
  31. package/dist/chunk-S5GWAUG5.js +29 -0
  32. package/dist/{chunk-T4G3VVZ4.js → chunk-YQGRMDRB.js} +4 -2
  33. package/dist/constants.cjs +1 -1
  34. package/dist/constants.js +1 -1
  35. package/dist/docs/api/02-config.md +57 -7
  36. package/dist/docs/development/00-why-eventcatalog.md +11 -11
  37. package/dist/docs/development/01-fundamentals.md +20 -13
  38. package/dist/docs/development/01-getting-started/configuration-overview.md +2 -2
  39. package/dist/docs/development/01-getting-started/installation.md +9 -1
  40. package/dist/docs/development/_getting-started.mdx +1 -1
  41. package/dist/docs/development/ask-your-architecture/01-intro.md +5 -5
  42. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/01-what-is-eventcatalog-assistant.md +0 -4
  43. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/02-configuration.md +15 -3
  44. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/03-bring-your-own-tools.md +0 -3
  45. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/_category_.json +1 -1
  46. package/dist/docs/development/ask-your-architecture/02-llms.txt.md +1 -1
  47. package/dist/docs/development/ask-your-architecture/{05-skills/01-introduction.md → 03-install-skills.md} +57 -7
  48. package/dist/docs/development/ask-your-architecture/03-mcp-server/_category_.json +1 -1
  49. package/dist/docs/development/ask-your-architecture/03-mcp-server/getting-started.md +86 -33
  50. package/dist/docs/development/ask-your-architecture/03-mcp-server/introduction.md +14 -4
  51. package/dist/docs/development/ask-your-architecture/03-schemas.txt.md +1 -1
  52. package/dist/docs/development/ask-your-architecture/04-agents/_category_.json +1 -1
  53. package/dist/docs/development/authentication/01-introduction.md +2 -23
  54. package/dist/docs/development/authentication/02-enabling-authentication.md +0 -20
  55. package/dist/docs/development/authentication/07-rbac-middleware.md +0 -2
  56. package/dist/docs/development/authentication/providers/03-setting-up-github.md +0 -2
  57. package/dist/docs/development/authentication/providers/03a-setting-up-google.md +0 -2
  58. package/dist/docs/development/authentication/providers/04-setting-up-azure-ad.md +0 -2
  59. package/dist/docs/development/authentication/providers/05-setting-up-okta.md +0 -3
  60. package/dist/docs/development/authentication/providers/06-setting-up-auth0.md +0 -2
  61. package/dist/docs/development/bring-your-own-documentation/01-introduction.md +0 -4
  62. package/dist/docs/development/bring-your-own-documentation/custom-pages/01-introduction.md +0 -3
  63. package/dist/docs/development/bring-your-own-documentation/custom-pages/02-adding-custom-docs.md +0 -17
  64. package/dist/docs/development/bring-your-own-documentation/custom-pages/03-components.md +0 -4
  65. package/dist/docs/development/bring-your-own-documentation/custom-pages/04-owners.md +0 -2
  66. package/dist/docs/development/bring-your-own-documentation/resource-docs/01-introduction.md +1 -3
  67. package/dist/docs/development/bring-your-own-documentation/resource-docs/02-adding-resource-docs.md +1 -4
  68. package/dist/docs/development/bring-your-own-documentation/resource-docs/03-categories.md +0 -2
  69. package/dist/docs/development/bring-your-own-documentation/resource-docs/04-versioning.md +1 -3
  70. package/dist/docs/development/components/components/11-flow.md +17 -0
  71. package/dist/docs/development/components/components/15-nodegraph.md +43 -10
  72. package/dist/docs/development/components/components/18-remote-schema.md +1 -4
  73. package/dist/docs/development/components/custom-components/07-reference.md +14 -0
  74. package/dist/docs/development/customization/02-themes.md +0 -5
  75. package/dist/docs/development/customization/03-search.md +1 -1
  76. package/dist/docs/development/customization/05-custom-pages-and-api-routes/01-introduction.md +0 -2
  77. package/dist/docs/development/customization/05-custom-pages-and-api-routes/04-reference.md +7 -1
  78. package/dist/docs/development/customization/05-resource-sidebar.md +1 -1
  79. package/dist/docs/development/customization/09-embed-eventcatalog.md +20 -25
  80. package/dist/docs/development/deployment/hosting-options.md +7 -2
  81. package/dist/docs/development/developer-tools/eventcatalog-linter/how-to/05-fix-common-problems.md +16 -0
  82. package/dist/docs/development/developer-tools/eventcatalog-linter/reference/03-rules.md +31 -1
  83. package/dist/docs/development/developer-tools/eventcatalog-linter/reference/05-supported-resources.md +1 -1
  84. package/dist/docs/development/governance/architecture-change-detection/01-introduction.md +0 -10
  85. package/dist/docs/development/governance/architecture-change-detection/06-pipeline-gates.md +0 -4
  86. package/dist/docs/development/guides/97-architecture-graph.md +1 -1
  87. package/dist/docs/development/guides/99-adding-analytics.md +0 -7
  88. package/dist/docs/development/guides/domains/03-model-subdomains.md +2 -2
  89. package/dist/docs/development/guides/domains/04-add-resources-to-domains/01-add-systems-to-domains.md +3 -1
  90. package/dist/docs/development/guides/domains/04-add-resources-to-domains/02-add-services-to-domains.md +5 -1
  91. package/dist/docs/development/guides/domains/04-add-resources-to-domains/03-add-messages-to-domains.md +2 -2
  92. package/dist/docs/development/guides/domains/04-add-resources-to-domains/05-add-entities-to-domains.md +1 -1
  93. package/dist/docs/development/guides/domains/04-add-resources-to-domains/06-domain-resources-page.md +40 -0
  94. package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-diagram.md +89 -0
  95. package/dist/docs/development/guides/domains/06-visualize-domains/_category_.json +1 -2
  96. package/dist/docs/development/guides/domains/09-reference.md +4 -4
  97. package/dist/docs/development/guides/owners/automated-teams-and-users/create-your-own-connector.md +0 -2
  98. package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-github.md +0 -3
  99. package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-microsoft-entra.md +0 -2
  100. package/dist/docs/development/guides/resources/adrs/03-linking-resources.md +8 -0
  101. package/dist/docs/development/guides/resources/adrs/06-reference.md +4 -4
  102. package/dist/docs/development/guides/resources/agents/11-reference.md +1 -1
  103. package/dist/docs/development/guides/resources/data/04-reference.md +1 -1
  104. package/dist/docs/development/guides/resources/data-products/07-reference.md +1 -1
  105. package/dist/docs/development/guides/resources/entities/05-entity-maps.md +1 -1
  106. package/dist/docs/development/guides/resources/entities/06-reference.md +2 -2
  107. package/dist/docs/development/guides/resources/flows/01-introduction.md +11 -1
  108. package/dist/docs/development/guides/resources/flows/03-model-flow-steps.md +65 -6
  109. package/dist/docs/development/guides/resources/flows/05-explore-flows.md +112 -0
  110. package/dist/docs/development/guides/resources/flows/06-reference.md +25 -4
  111. package/dist/docs/development/guides/resources/messages/01-what-are-messages.md +19 -0
  112. package/dist/docs/development/guides/resources/messages/04-message-channels/01-introduction.md +16 -0
  113. package/dist/docs/development/guides/resources/messages/04-message-channels/05-reference.md +2 -1
  114. package/dist/docs/development/guides/resources/messages/10-reference.md +6 -3
  115. package/dist/docs/development/guides/resources/schemas/04-explore-schemas/01-schema-explorer.md +2 -2
  116. package/dist/docs/development/guides/resources/schemas/04-explore-schemas/02-fields-explorer.md +0 -9
  117. package/dist/docs/development/guides/resources/schemas/05-schema-api.md +0 -3
  118. package/dist/docs/development/guides/resources/schemas/06-schema-mcp.md +11 -3
  119. package/dist/docs/development/guides/resources/services/04-add-resources-to-services/03-add-entities-to-services.md +1 -1
  120. package/dist/docs/development/guides/resources/services/05-resources-page.md +50 -0
  121. package/dist/docs/development/guides/resources/services/08-reference.md +2 -1
  122. package/dist/docs/development/guides/systems/01-introduction.md +1 -1
  123. package/dist/docs/development/guides/systems/02-create-system.md +2 -2
  124. package/dist/docs/development/guides/systems/03-add-resources-to-systems.md +35 -9
  125. package/dist/docs/development/guides/systems/04-model-relationships-and-actors.md +5 -3
  126. package/dist/docs/development/guides/systems/05-system-context-maps.md +39 -22
  127. package/dist/docs/development/guides/systems/06-reference.md +4 -4
  128. package/dist/docs/development/license/01-license-file.md +151 -0
  129. package/dist/docs/development/license/_category_.json +12 -0
  130. package/dist/docs/development/license-keys/_category_.json +3 -3
  131. package/dist/docs/development/license-keys/integrations.md +7 -37
  132. package/dist/docs/development/license-keys/license-validation.md +4 -0
  133. package/dist/docs/development/license-keys/overview.md +5 -1
  134. package/dist/docs/development/license-keys/plans.md +4 -2
  135. package/dist/docs/development/studio/01-introduction.md +60 -0
  136. package/dist/docs/development/studio/02-create-a-canvas.md +103 -0
  137. package/dist/docs/development/studio/03-set-up-persistent-storage.md +59 -0
  138. package/dist/docs/development/studio/04-collaborate-on-a-canvas.md +78 -0
  139. package/dist/docs/development/studio/05-connect-your-agent.md +102 -0
  140. package/dist/docs/development/studio/06-run-studio-in-production.md +54 -0
  141. package/dist/docs/development/studio/07-reference.md +294 -0
  142. package/dist/docs/development/studio/_category_.json +12 -0
  143. package/dist/docs/development/upgrading/v5.md +345 -0
  144. package/dist/docs/federation/00-overview.md +2 -8
  145. package/dist/docs/federation/01-first-federation.md +6 -18
  146. package/dist/docs/federation/explanation/how-it-works.md +0 -4
  147. package/dist/docs/federation/explanation/lockfile-and-cache.md +0 -4
  148. package/dist/docs/federation/explanation/mvp-status-and-feedback.md +0 -4
  149. package/dist/docs/federation/explanation/ownership-and-references.md +0 -4
  150. package/dist/docs/federation/how-to/configure-github-sources.md +6 -5
  151. package/dist/docs/federation/how-to/configure-validation-rules.md +0 -4
  152. package/dist/docs/federation/how-to/run-in-ci.md +2 -9
  153. package/dist/docs/federation/how-to/share-assets-and-components.md +0 -4
  154. package/dist/docs/federation/how-to/use-local-sources.md +0 -4
  155. package/dist/docs/federation/legacy-federation/00-introduction.md +4 -22
  156. package/dist/docs/federation/legacy-federation/01-installation.md +7 -58
  157. package/dist/docs/federation/legacy-federation/02-plugin-configuration.md +3 -21
  158. package/dist/docs/federation/legacy-federation/03-examples.md +3 -5
  159. package/dist/docs/federation/legacy-federation/04-configuration.md +3 -8
  160. package/dist/docs/federation/legacy-federation/05-setup-team-catalog.md +3 -6
  161. package/dist/docs/federation/reference/cli.md +2 -8
  162. package/dist/docs/federation/reference/configuration.md +0 -4
  163. package/dist/docs/federation/reference/diagnostic-rules.md +0 -5
  164. package/dist/docs/federation/reference/generated-output.md +0 -4
  165. package/dist/docs/federation/reference/supported-content.md +0 -4
  166. package/dist/docs/federation/reference/troubleshooting.md +0 -14
  167. package/dist/docs/plugins/02-generators.md +1 -1
  168. package/dist/docs/plugins/amazon-apigateway/00-intro.md +3 -28
  169. package/dist/docs/plugins/amazon-apigateway/01-installation.md +4 -56
  170. package/dist/docs/plugins/amazon-apigateway/02-plugin-configuration.md +1 -6
  171. package/dist/docs/plugins/apicurio/00-intro.md +2 -31
  172. package/dist/docs/plugins/apicurio/01-installation.md +2 -26
  173. package/dist/docs/plugins/apicurio/02-plugin-configuration.md +5 -13
  174. package/dist/docs/plugins/apicurio/03-features.md +1 -3
  175. package/dist/docs/plugins/asyncapi/00-intro.md +2 -28
  176. package/dist/docs/plugins/asyncapi/01-installation.md +3 -54
  177. package/dist/docs/plugins/asyncapi/02-plugin-configuration.md +2 -1
  178. package/dist/docs/plugins/aws-glue-registry/00-intro.md +4 -32
  179. package/dist/docs/plugins/aws-glue-registry/00a-installation.md +3 -53
  180. package/dist/docs/plugins/azure-schema-registry/00-intro.md +4 -32
  181. package/dist/docs/plugins/azure-schema-registry/01-installation.md +6 -33
  182. package/dist/docs/plugins/azure-schema-registry/02-plugin-configuration.md +1 -14
  183. package/dist/docs/plugins/azure-schema-registry/04-examples.md +0 -2
  184. package/dist/docs/plugins/backstage/00-overview.md +1 -7
  185. package/dist/docs/plugins/backstage/01-get-started.md +6 -15
  186. package/dist/docs/plugins/backstage/06-configuration.md +2 -8
  187. package/dist/docs/plugins/confluent-schema-registry/00-intro.md +2 -29
  188. package/dist/docs/plugins/confluent-schema-registry/01-installation.md +2 -26
  189. package/dist/docs/plugins/eventbridge/00-intro.md +0 -4
  190. package/dist/docs/plugins/eventbridge/00a-installation.md +1 -87
  191. package/dist/docs/plugins/eventbridge/03-api.md +2 -20
  192. package/dist/docs/plugins/github/00-intro.md +0 -31
  193. package/dist/docs/plugins/github/01-installation.md +2 -34
  194. package/dist/docs/plugins/graphql/00-intro.md +0 -30
  195. package/dist/docs/plugins/graphql/01-installation.md +1 -53
  196. package/dist/docs/plugins/graphql/02-plugin-configuration.md +0 -1
  197. package/dist/docs/plugins/hookdeck/01-intro.md +1 -1
  198. package/dist/docs/plugins/openapi/00-intro.md +0 -30
  199. package/dist/docs/plugins/openapi/01-installation.md +1 -57
  200. package/dist/docs/plugins/openapi/02-plugin-configuration.md +0 -5
  201. package/dist/docs/plugins/openapi/03-features.md +0 -4
  202. package/dist/eventcatalog-config-file-utils.cjs +34 -41
  203. package/dist/eventcatalog-config-file-utils.d.cts +56 -58
  204. package/dist/eventcatalog-config-file-utils.d.ts +56 -58
  205. package/dist/eventcatalog-config-file-utils.js +1 -1
  206. package/dist/eventcatalog.cjs +408 -281
  207. package/dist/eventcatalog.config.d.cts +26 -15
  208. package/dist/eventcatalog.config.d.ts +26 -15
  209. package/dist/eventcatalog.js +46 -27
  210. package/dist/features.cjs +36 -49
  211. package/dist/features.d.cts +1 -3
  212. package/dist/features.d.ts +1 -3
  213. package/dist/features.js +4 -6
  214. package/dist/federation/federate.cjs +37 -44
  215. package/dist/federation/federate.js +5 -5
  216. package/dist/federation/source-provider.js +2 -2
  217. package/dist/generate.cjs +37 -42
  218. package/dist/generate.js +4 -4
  219. package/dist/resolve-catalog-dependencies.cjs +34 -41
  220. package/dist/resolve-catalog-dependencies.js +2 -2
  221. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
  222. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
  223. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
  224. package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
  225. package/dist/runtime-dependencies/manifest.json +5 -1
  226. package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
  227. package/dist/utils/child-process-signals.cjs +53 -0
  228. package/dist/utils/child-process-signals.d.cts +19 -0
  229. package/dist/utils/child-process-signals.d.ts +19 -0
  230. package/dist/utils/child-process-signals.js +6 -0
  231. package/dist/utils/cli-logger.cjs +1 -1
  232. package/dist/utils/cli-logger.js +2 -2
  233. package/dist/utils/license-status.cjs +11 -4
  234. package/dist/utils/license-status.d.cts +3 -2
  235. package/dist/utils/license-status.d.ts +3 -2
  236. package/dist/utils/license-status.js +1 -1
  237. package/eventcatalog/astro.config.mjs +21 -1
  238. package/eventcatalog/integrations/config-loader.mjs +56 -58
  239. package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
  240. package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
  241. package/eventcatalog/integrations/storage.mjs +20 -0
  242. package/eventcatalog/integrations/studio-server.mjs +4 -1
  243. package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
  244. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
  245. package/eventcatalog/src/components/Homepage/CatalogDashboard.astro +342 -0
  246. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +60 -4
  247. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
  248. package/eventcatalog/src/components/NavigationProgress.astro +7 -0
  249. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +2 -0
  250. package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +2 -0
  251. package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -0
  252. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -0
  253. package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
  254. package/eventcatalog/src/components/Search/SearchModal.tsx +2 -10
  255. package/eventcatalog/src/components/Search/search-utils.ts +26 -0
  256. package/eventcatalog/src/components/Seo.astro +5 -1
  257. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +53 -48
  258. package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +183 -178
  259. package/eventcatalog/src/components/Settings/LicenseSettings.tsx +140 -31
  260. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +40 -35
  261. package/eventcatalog/src/components/Settings/LogoUpload.tsx +1 -1
  262. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +9 -8
  263. package/eventcatalog/src/components/Settings/Row.tsx +7 -4
  264. package/eventcatalog/src/components/Settings/SettingsShared.tsx +3 -3
  265. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +37 -76
  266. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
  267. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +122 -1
  268. package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
  269. package/eventcatalog/src/components/TrialBadge.astro +20 -9
  270. package/eventcatalog/src/content.config.ts +19 -2
  271. package/eventcatalog/src/features/auth/error.astro +4 -2
  272. package/eventcatalog/src/features/auth/login.astro +2 -1
  273. package/eventcatalog/src/features/auth/middleware/middleware-auth.ts +21 -1
  274. package/eventcatalog/src/features/auth/unauthorized.astro +1 -1
  275. package/eventcatalog/src/features/fields/pages/fields.astro +1 -1
  276. package/eventcatalog/src/features/integrations/eventcatalog-features.ts +13 -7
  277. package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
  278. package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +3 -3
  279. package/eventcatalog/src/features/mcp/apps/canvas/styles.css +3 -1
  280. package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +7 -5
  281. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +123 -98
  282. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +118 -101
  283. package/eventcatalog/src/features/mcp/mcp-server.ts +20 -4
  284. package/eventcatalog/src/features/server/start.ts +25 -0
  285. package/eventcatalog/src/features/storage/database.ts +88 -0
  286. package/eventcatalog/src/features/storage/migrations.ts +85 -0
  287. package/eventcatalog/src/features/storage/sql/database.sql +5 -0
  288. package/eventcatalog/src/features/storage/sql/migrations/0001-studio-canvases.sql +12 -0
  289. package/eventcatalog/src/features/storage/sql/migrations.sql +15 -0
  290. package/eventcatalog/src/features/storage/sql.ts +28 -0
  291. package/eventcatalog/src/features/studio/agent-choreography.ts +13 -10
  292. package/eventcatalog/src/features/studio/agents.ts +28 -0
  293. package/eventcatalog/src/features/studio/api/canvases-api.ts +219 -0
  294. package/eventcatalog/src/features/studio/api/canvases.ts +25 -0
  295. package/eventcatalog/src/features/studio/api/client.ts +40 -0
  296. package/eventcatalog/src/features/studio/canvas-actions.ts +160 -34
  297. package/eventcatalog/src/features/studio/canvas-preview.ts +1 -2
  298. package/eventcatalog/src/features/studio/catalog.ts +16 -14
  299. package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +274 -105
  300. package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +15 -14
  301. package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +272 -119
  302. package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +1 -2
  303. package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +65 -0
  304. package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
  305. package/eventcatalog/src/features/studio/components/JoinForm.tsx +101 -26
  306. package/eventcatalog/src/features/studio/components/LeftPanel.tsx +122 -230
  307. package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
  308. package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
  309. package/eventcatalog/src/features/studio/components/Presence.tsx +52 -45
  310. package/eventcatalog/src/features/studio/components/ShareDialog.tsx +277 -141
  311. package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
  312. package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +1314 -385
  313. package/eventcatalog/src/features/studio/components/StudioNotice.astro +24 -0
  314. package/eventcatalog/src/features/studio/document-name.ts +7 -0
  315. package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
  316. package/eventcatalog/src/features/studio/hooks/presence-sender.ts +19 -2
  317. package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +9 -3
  318. package/eventcatalog/src/features/studio/hooks/use-comments.ts +2 -2
  319. package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +8 -3
  320. package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +244 -32
  321. package/eventcatalog/src/features/studio/identity.ts +25 -1
  322. package/eventcatalog/src/features/studio/limits.ts +2 -0
  323. package/eventcatalog/src/features/studio/pages/[id].astro +42 -16
  324. package/eventcatalog/src/features/studio/pages/index.astro +596 -373
  325. package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +12 -15
  326. package/eventcatalog/src/features/studio/server/canvas-mcp.ts +8 -23
  327. package/eventcatalog/src/features/studio/server/runtime.ts +150 -46
  328. package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
  329. package/eventcatalog/src/features/studio/server/storage.ts +53 -73
  330. package/eventcatalog/src/features/studio/webmcp-relay/LICENSE +21 -0
  331. package/eventcatalog/src/features/studio/webmcp-relay/README.md +5 -0
  332. package/eventcatalog/src/features/studio/webmcp-relay/embed.js +2 -0
  333. package/eventcatalog/src/features/studio/webmcp-relay/widget.html +10 -0
  334. package/eventcatalog/src/features/studio/webmcp-relay/widget.js +1 -0
  335. package/eventcatalog/src/features/tools/catalog-tools.ts +3 -1
  336. package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
  337. package/eventcatalog/src/layouts/SettingsLayout.astro +2 -2
  338. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +3 -2
  339. package/eventcatalog/src/pages/_index.astro +5 -342
  340. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +2 -3
  341. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +0 -7
  342. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +3 -1
  343. package/eventcatalog/src/pages/diagrams/[id]/[version]/_index.data.ts +0 -7
  344. package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +1 -0
  345. package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +1 -0
  346. package/eventcatalog/src/pages/directory/[type]/_index.data.ts +5 -7
  347. package/eventcatalog/src/pages/directory/[type]/index.astro +3 -1
  348. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -7
  349. package/eventcatalog/src/pages/discover/[type]/index.astro +3 -1
  350. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +0 -7
  351. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -0
  352. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +0 -7
  353. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -0
  354. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +0 -7
  355. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +3 -1
  356. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/_[filename].data.ts +0 -7
  357. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +0 -7
  358. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -0
  359. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +1 -0
  360. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/_[...filename].data.ts +0 -4
  361. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/_index.data.ts +0 -7
  362. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/index.astro +1 -0
  363. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +3 -1
  364. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/_[filename].data.ts +0 -7
  365. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
  366. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +2 -3
  367. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +0 -7
  368. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +1 -0
  369. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +1 -0
  370. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/_[filename].data.ts +0 -7
  371. package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +0 -7
  372. package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +2 -1
  373. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/_index.data.ts +0 -7
  374. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +1 -0
  375. package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +0 -7
  376. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +1 -0
  377. package/eventcatalog/src/pages/docs/custom/[...path]/_index.data.ts +0 -7
  378. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +1 -0
  379. package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +1 -1
  380. package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +1 -0
  381. package/eventcatalog/src/pages/docs/services/[id]/asyncapi/[filename].astro +1 -1
  382. package/eventcatalog/src/pages/docs/services/[id]/changelog/index.astro +1 -1
  383. package/eventcatalog/src/pages/docs/services/[id]/graphql/[filename].astro +1 -1
  384. package/eventcatalog/src/pages/docs/services/[id]/spec/[filename].astro +1 -1
  385. package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +0 -7
  386. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +1 -0
  387. package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +0 -7
  388. package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -0
  389. package/eventcatalog/src/pages/index.astro +4 -2
  390. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +0 -7
  391. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +9 -1
  392. package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +0 -7
  393. package/eventcatalog/src/pages/schemas/explorer/index.astro +4 -2
  394. package/eventcatalog/src/pages/settings/license.astro +9 -1
  395. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/_index.data.ts +0 -7
  396. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/index.astro +1 -0
  397. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +0 -7
  398. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/_index.data.ts +0 -7
  399. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +1 -0
  400. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/_index.data.ts +0 -7
  401. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -0
  402. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -0
  403. package/eventcatalog/src/pages/visualiser/[type]/[id]/_index.data.ts +38 -0
  404. package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +18 -41
  405. package/eventcatalog/src/pages/visualiser/designs/[id]/_index.data.ts +0 -7
  406. package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -1
  407. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +0 -7
  408. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -0
  409. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +1 -0
  410. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +0 -7
  411. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +1 -0
  412. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +0 -7
  413. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +1 -0
  414. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +1 -0
  415. package/eventcatalog/src/types/react-syntax-highlighter.d.ts +10 -0
  416. package/eventcatalog/src/utils/collections/flows.ts +20 -7
  417. package/eventcatalog/src/utils/collections/resource-owners.ts +8 -2
  418. package/eventcatalog/src/utils/collections/resources.ts +2 -0
  419. package/eventcatalog/src/utils/collections/util.ts +8 -4
  420. package/eventcatalog/src/utils/git.ts +11 -0
  421. package/eventcatalog/src/utils/homepage-dashboard.ts +143 -0
  422. package/eventcatalog/src/utils/license.ts +1 -1
  423. package/eventcatalog/src/utils/link-validation.ts +25 -19
  424. package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +3 -1
  425. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
  426. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +4 -2
  427. package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +20 -1
  428. package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
  429. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
  430. package/eventcatalog/src/utils/page-loaders/hybrid-page.ts +4 -15
  431. package/eventcatalog/src/utils/page-title.ts +15 -0
  432. package/eventcatalog/src/utils/syntax-highlighter-renderer.ts +64 -0
  433. package/eventcatalog/src/utils/trial.ts +13 -0
  434. package/package.json +11 -11
  435. package/dist/docs/development/ask-your-architecture/05-skills/02-installation.md +0 -60
  436. package/dist/docs/development/ask-your-architecture/05-skills/_category_.json +0 -11
  437. package/dist/docs/development/ask-your-architecture/06-slack-integration/01-introduction.md +0 -63
  438. package/dist/docs/development/ask-your-architecture/06-slack-integration/02-slack-app-setup.md +0 -154
  439. package/dist/docs/development/ask-your-architecture/06-slack-integration/03-installation.md +0 -169
  440. package/dist/docs/development/ask-your-architecture/06-slack-integration/04-deployment.md +0 -236
  441. package/dist/docs/development/ask-your-architecture/06-slack-integration/05-usage.md +0 -140
  442. package/dist/docs/development/ask-your-architecture/06-slack-integration/06-troubleshooting.md +0 -268
  443. package/dist/docs/development/ask-your-architecture/06-slack-integration/_category_.json +0 -13
  444. package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-integration-map.md +0 -40
  445. package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +0 -3
  446. package/eventcatalog/src/features/studio/canvas-doc.ts +0 -409
  447. package/eventcatalog/src/features/studio/clipboard.ts +0 -97
  448. package/eventcatalog/src/features/studio/components/CanvasControls.tsx +0 -154
  449. package/eventcatalog/src/features/studio/components/Comments.tsx +0 -770
  450. package/eventcatalog/src/features/studio/components/ContainerChooser.tsx +0 -145
  451. package/eventcatalog/src/features/studio/components/DragGhost.tsx +0 -115
  452. package/eventcatalog/src/features/studio/components/Picture.tsx +0 -21
  453. package/eventcatalog/src/features/studio/components/PropertiesPanel.tsx +0 -212
  454. package/eventcatalog/src/features/studio/components/canvas-nodes.tsx +0 -255
  455. package/eventcatalog/src/features/studio/components/icons.ts +0 -53
  456. package/eventcatalog/src/features/studio/components/status.ts +0 -51
  457. package/eventcatalog/src/features/studio/edges.ts +0 -56
  458. package/eventcatalog/src/features/studio/flow-state.ts +0 -92
  459. package/eventcatalog/src/features/studio/grouping.ts +0 -226
  460. package/eventcatalog/src/features/studio/layout.ts +0 -42
  461. package/eventcatalog/src/features/studio/levels.ts +0 -282
  462. package/eventcatalog/src/features/studio/node-types.ts +0 -205
  463. package/eventcatalog/src/features/studio/pages/new.astro +0 -24
  464. package/eventcatalog/src/features/studio/pages/wake.ts +0 -15
  465. package/eventcatalog/src/features/studio/placement.ts +0 -197
  466. package/eventcatalog/src/features/studio/studio.css +0 -273
  467. package/dist/{chunk-A2RZR3U4.js → chunk-6K7XZAYI.js} +3 -3
@@ -41,6 +41,8 @@ type McpServerOptions = {
41
41
  catalogUrl: string;
42
42
  /** The MCP client's user agent, to name agents that join a canvas */
43
43
  userAgent?: string;
44
+ /** Offer the canvas tools (by default when Studio is on, for the whole catalog) */
45
+ canvases?: boolean;
44
46
  };
45
47
 
46
48
  const catalogDirectory = process.env.PROJECT_DIR || process.cwd();
@@ -120,7 +122,10 @@ function getServerInstructions(scope?: McpScope) {
120
122
  }
121
123
 
122
124
  // Create MCP Server with tools that access Astro collections
123
- function createMcpServer(scope: McpScope | undefined, { catalogUrl, userAgent }: McpServerOptions) {
125
+ function createMcpServer(
126
+ scope: McpScope | undefined,
127
+ { catalogUrl, userAgent, canvases = !scope && isCanvasEnabled() }: McpServerOptions
128
+ ) {
124
129
  const server = new McpServer(
125
130
  {
126
131
  name: scope ? `EventCatalog MCP Server — ${scope.name} ${scope.ref.kind}` : 'EventCatalog MCP Server',
@@ -837,7 +842,7 @@ function createMcpServer(scope: McpScope | undefined, { catalogUrl, userAgent }:
837
842
  }
838
843
 
839
844
  // Collaborative canvases (when the collaboration server runs in this process)
840
- if (!scope && isCanvasEnabled()) registerCanvasTools(server, { catalogUrl, userAgent });
845
+ if (canvases) registerCanvasTools(server, { catalogUrl, userAgent });
841
846
 
842
847
  return server;
843
848
  }
@@ -993,11 +998,22 @@ const handleMcpRequest = async (c: Context, kind?: McpScopeKind) => {
993
998
  }
994
999
 
995
1000
  const scope = await resolveRequestScope(c, kind);
996
- // Canvas tools work on Studio's canvases: started (storage loaded) before they're listed
997
- if (!scope && isCanvasEnabled()) await startStudio();
1001
+ // Canvas tools work on Studio's canvases: started (storage loaded) before they're listed, and left out when
1002
+ // Studio isn't available (the rest of the catalog's tools still work)
1003
+ const canvases =
1004
+ !scope &&
1005
+ isCanvasEnabled() &&
1006
+ (await startStudio().then(
1007
+ () => true,
1008
+ (error) => {
1009
+ console.error(`[studio] Canvas tools are off: ${(error as Error).message}`);
1010
+ return false;
1011
+ }
1012
+ ));
998
1013
  const server = createMcpServer(scope, {
999
1014
  catalogUrl: new URL(c.req.url).origin,
1000
1015
  userAgent: c.req.header('user-agent'),
1016
+ canvases,
1001
1017
  });
1002
1018
  const transport = new WebStandardStreamableHTTPServerTransport({
1003
1019
  sessionIdGenerator: undefined,
@@ -0,0 +1,25 @@
1
+ import type { APIRoute } from 'astro';
2
+ import { isCanvasEnabled } from '@utils/feature';
3
+ import { startStorage } from '../storage/database';
4
+ import { startStudio } from '../studio/server/runtime';
5
+ import { isSignedIn } from '../studio/server/sign-in';
6
+
7
+ /**
8
+ * What the server starts before anyone asks for it: `eventcatalog start` calls this once the server listens. Each
9
+ * feature that needs starting has its own start function, called here in order: the storage configured is opened and
10
+ * migrated first (features keep their state in it), then Studio (so tabs reconnecting after a restart find it
11
+ * ready). Under /_eventcatalog, which sign-in lets through (the server calls it without a session); it says nothing
12
+ * about what's stored.
13
+ */
14
+ export const GET: APIRoute = async () => {
15
+ try {
16
+ await startStorage();
17
+ } catch (error) {
18
+ console.error(`[eventcatalog] Could not open the database: ${(error as Error).message}`);
19
+ }
20
+ // Studio says why if it can't start
21
+ if (isCanvasEnabled()) await startStudio({ isSignedIn }).catch(() => {});
22
+ return new Response(null, { status: 204 });
23
+ };
24
+
25
+ export const prerender = false;
@@ -0,0 +1,88 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import config from '../../utils/eventcatalog-config/source';
4
+ import type { Config } from '../../../../src/eventcatalog.config';
5
+ import { migrate, type Database } from './migrations';
6
+ import { namedStatements } from './sql';
7
+ import databaseSql from './sql/database.sql?raw';
8
+
9
+ /** `storage` in eventcatalog.config.js: memory (the default), or one SQLite database for the whole catalog */
10
+ export type StorageConfig = NonNullable<Config['storage']>;
11
+ export type StorageType = StorageConfig['type'];
12
+ export type { Database };
13
+
14
+ export const DEFAULT_STORAGE: StorageConfig = { type: 'memory' };
15
+ const DEFAULT_DATABASE_PATH = '.eventcatalog/eventcatalog.db';
16
+
17
+ const SQL = namedStatements(databaseSql, ['useWriteAheadLog']);
18
+
19
+ /** The database file a config asks for (relative to the catalog), or undefined when state is kept in memory */
20
+ export const getDatabasePath = (storage: StorageConfig | undefined, projectDirectory: string) => {
21
+ const chosen = storage ?? DEFAULT_STORAGE;
22
+ switch (chosen.type) {
23
+ case 'memory':
24
+ return undefined;
25
+ case 'sqlite':
26
+ return path.resolve(projectDirectory, chosen.path ?? DEFAULT_DATABASE_PATH);
27
+ default:
28
+ throw new Error(`Unknown storage type "${(chosen as { type?: string }).type}": use "memory" or "sqlite"`);
29
+ }
30
+ };
31
+
32
+ const open = async (file: string): Promise<Database> => {
33
+ // Node's built-in SQLite (no native package to install), asked of Node itself: the dev server loads this through
34
+ // Vite, which doesn't know node:sqlite and fails to import it
35
+ type Sqlite = { DatabaseSync: new (file: string) => Database };
36
+ const getBuiltinModule = (process as { getBuiltinModule?: (id: string) => unknown }).getBuiltinModule;
37
+ let sqlite: Sqlite | undefined;
38
+ try {
39
+ sqlite = getBuiltinModule
40
+ ? (getBuiltinModule('node:sqlite') as Sqlite | undefined)
41
+ : await import(/* @vite-ignore */ ['node', 'sqlite'].join(':'));
42
+ } catch (error) {
43
+ throw new Error(`Could not load node:sqlite (${(error as Error).message})`);
44
+ }
45
+ if (!sqlite?.DatabaseSync) {
46
+ throw new Error(
47
+ `SQLite storage needs Node.js 22.13 or later (it uses node:sqlite); this is Node.js ${process.versions.node}`
48
+ );
49
+ }
50
+ fs.mkdirSync(path.dirname(file), { recursive: true });
51
+ const database = new sqlite.DatabaseSync(file);
52
+ database.exec(SQL.useWriteAheadLog);
53
+ migrate(database);
54
+ return database;
55
+ };
56
+
57
+ // Opened once per process, by file (kept on globalThis: the dev server's integrations and the app load this module
58
+ // separately, and code reloads in dev keep globalThis)
59
+ const DATABASES = Symbol.for('eventcatalog.databases');
60
+ const store = globalThis as typeof globalThis & { [DATABASES]?: Map<string, Promise<Database>> };
61
+
62
+ /**
63
+ * The database in `file`, brought up to date by the migrations: opened the first time it's asked for, then shared by
64
+ * every feature. Rejects (every time) if it can't be opened or migrated, e.g. when a newer EventCatalog updated it.
65
+ */
66
+ export const openDatabase = (file: string): Promise<Database> => {
67
+ const databases = (store[DATABASES] ??= new Map());
68
+ let database = databases.get(file);
69
+ if (!database) {
70
+ database = open(file);
71
+ databases.set(file, database);
72
+ }
73
+ return database;
74
+ };
75
+
76
+ /**
77
+ * Opens the storage configured, running the migrations it needs. Called as the dev server and `eventcatalog start`
78
+ * start (not on build: builds often run somewhere other than where the database lives), so it's ready before any
79
+ * feature uses it. Returns the database file, or undefined when state is kept in memory.
80
+ */
81
+ export const startStorage = async (projectDirectory = process.env.PROJECT_DIR || process.cwd()) => {
82
+ if ((config as { studio?: { storage?: unknown } }).studio?.storage) {
83
+ console.warn('[eventcatalog] studio.storage is no longer used: set storage in eventcatalog.config.js instead');
84
+ }
85
+ const file = getDatabasePath(config.storage, projectDirectory);
86
+ if (file) await openDatabase(file);
87
+ return file;
88
+ };
@@ -0,0 +1,85 @@
1
+ import { namedStatements } from './sql';
2
+ import runnerSql from './sql/migrations.sql?raw';
3
+
4
+ /**
5
+ * Changes to the database's schema, for every feature that keeps state, as .sql files in ./sql/migrations named
6
+ * `NNNN-what-it-does.sql` (one numbered order for the whole catalog; tables are named for their feature, e.g.
7
+ * `studio_canvases`). They run in order when the database opens, each once, recorded in its `migrations` table. To
8
+ * change the schema, add a file with the next number: never change one that has shipped, since databases out there have
9
+ * already run it.
10
+ */
11
+ export type Migration = { version: number; name: string; sql: string };
12
+
13
+ /** The parts of node:sqlite's DatabaseSync EventCatalog uses */
14
+ export type Database = {
15
+ exec: (sql: string) => void;
16
+ prepare: (sql: string) => { run: (...values: unknown[]) => unknown; all: () => unknown[] };
17
+ };
18
+
19
+ // Built into the server code (no files to find at runtime, wherever it's deployed)
20
+ const files = import.meta.glob<string>('./sql/migrations/*.sql', { query: '?raw', import: 'default', eager: true });
21
+ const SQL = namedStatements(runnerSql, ['createMigrationsTable', 'appliedVersions', 'recordMigration']);
22
+
23
+ /** Migrations from their files, in order (an error if a file is misnamed or two have the same number) */
24
+ export const toMigrations = (sources: Record<string, string>): Migration[] => {
25
+ const migrations = Object.entries(sources).map(([file, sql]) => {
26
+ const name = file
27
+ .split('/')
28
+ .pop()!
29
+ .replace(/\.sql$/, '');
30
+ const version = Number(/^(\d{4})-[a-z0-9-]+$/.exec(name)?.[1]);
31
+ if (!version) throw new Error(`Migration "${file}" should be named like 0003-what-it-does.sql`);
32
+ return { version, name, sql };
33
+ });
34
+ migrations.sort((a, b) => a.version - b.version);
35
+ migrations.forEach((migration, index) => {
36
+ if (migration.version !== index + 1) {
37
+ throw new Error(`Migrations should be numbered 1, 2, 3...: expected ${index + 1} before ${migration.name}`);
38
+ }
39
+ });
40
+ return migrations;
41
+ };
42
+
43
+ export const MIGRATIONS = toMigrations(files);
44
+
45
+ /**
46
+ * The database was updated by a newer EventCatalog. Features don't fall back to memory for this (changes would quietly
47
+ * stop being saved): they aren't available until EventCatalog is updated. Told by its code, as the dev server's
48
+ * integrations and the app load this module separately.
49
+ */
50
+ const DATABASE_TOO_NEW = 'EVENTCATALOG_DATABASE_TOO_NEW';
51
+ export const isDatabaseTooNew = (error: unknown) => (error as { code?: unknown } | null)?.code === DATABASE_TOO_NEW;
52
+
53
+ /**
54
+ * Brings a database up to date: runs the migrations it hasn't run yet, each in a transaction (all of it or none).
55
+ * Refuses a database that has run migrations this version doesn't know (made by a newer EventCatalog).
56
+ */
57
+ export const migrate = (database: Database, migrations: Migration[] = MIGRATIONS) => {
58
+ database.exec(SQL.createMigrationsTable);
59
+ const applied = new Set(
60
+ (database.prepare(SQL.appliedVersions).all() as { version: number }[]).map((row) => Number(row.version))
61
+ );
62
+ const latest = migrations.at(-1)?.version ?? 0;
63
+ const newer = [...applied].filter((version) => version > latest);
64
+ if (newer.length) {
65
+ throw Object.assign(
66
+ new Error(
67
+ `The EventCatalog database has been updated by a newer EventCatalog (migration ${Math.max(...newer)}; this version knows up to ${latest}). Update EventCatalog to use it.`
68
+ ),
69
+ { code: DATABASE_TOO_NEW }
70
+ );
71
+ }
72
+ const record = database.prepare(SQL.recordMigration);
73
+ for (const migration of migrations) {
74
+ if (applied.has(migration.version)) continue;
75
+ database.exec('BEGIN');
76
+ try {
77
+ database.exec(migration.sql);
78
+ record.run(migration.version, migration.name, Date.now());
79
+ database.exec('COMMIT');
80
+ } catch (error) {
81
+ database.exec('ROLLBACK');
82
+ throw new Error(`Could not run migration ${migration.name}: ${(error as Error).message}`);
83
+ }
84
+ }
85
+ };
@@ -0,0 +1,5 @@
1
+ -- Statements run as the database opens (see database.ts), each named by the `-- name:` line above it.
2
+
3
+ -- name: useWriteAheadLog
4
+ -- Readers don't wait for writers (set as the database opens: it can't be changed inside a migration's transaction)
5
+ PRAGMA journal_mode = WAL;
@@ -0,0 +1,12 @@
1
+ -- Studio's canvases: each one's whole Yjs document (Y.encodeStateAsUpdate), and when it last changed.
2
+ CREATE TABLE studio_canvases (
3
+ name TEXT PRIMARY KEY,
4
+ state BLOB NOT NULL,
5
+ updated_at INTEGER NOT NULL
6
+ );
7
+
8
+ -- Studio canvases that were deleted, so a browser that still has one open can't bring it back.
9
+ CREATE TABLE studio_deleted_canvases (
10
+ name TEXT PRIMARY KEY,
11
+ deleted_at INTEGER NOT NULL
12
+ );
@@ -0,0 +1,15 @@
1
+ -- The statements the migration runner runs (see migrations.ts), each named by the `-- name:` line above it. Its own
2
+ -- table is made here rather than in a migration: it records which migrations have run, so it's needed before any do.
3
+
4
+ -- name: createMigrationsTable
5
+ CREATE TABLE IF NOT EXISTS migrations (
6
+ version INTEGER PRIMARY KEY,
7
+ name TEXT NOT NULL,
8
+ applied_at INTEGER NOT NULL
9
+ );
10
+
11
+ -- name: appliedVersions
12
+ SELECT version FROM migrations;
13
+
14
+ -- name: recordMigration
15
+ INSERT INTO migrations (version, name, applied_at) VALUES (?, ?, ?);
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Statements kept in .sql files (./sql), each named by a `-- name: <name>` line above it. A file's statements are
3
+ * looked up by the names the code expects: a missing one is an error when the module loads, not when it's first run.
4
+ */
5
+ export const namedStatements = <Name extends string>(source: string, names: readonly Name[]): Record<Name, string> => {
6
+ const statements = new Map<string, string>();
7
+ let current: { name: string; lines: string[] } | undefined;
8
+ const finish = () => {
9
+ if (current) statements.set(current.name, current.lines.join('\n').trim());
10
+ };
11
+ for (const line of source.split('\n')) {
12
+ const name = /^--\s*name:\s*(\S+)\s*$/.exec(line)?.[1];
13
+ if (name) {
14
+ finish();
15
+ current = { name, lines: [] };
16
+ } else {
17
+ current?.lines.push(line);
18
+ }
19
+ }
20
+ finish();
21
+ return Object.fromEntries(
22
+ names.map((name) => {
23
+ const statement = statements.get(name);
24
+ if (!statement) throw new Error(`No SQL statement named "${name}"`);
25
+ return [name, statement];
26
+ })
27
+ ) as Record<Name, string>;
28
+ };
@@ -9,11 +9,16 @@ import {
9
9
  fitContainersAround,
10
10
  getCanvasMaps,
11
11
  moveNode,
12
- resizeNode,
12
+ placeNode,
13
+ setEdgeRoutes,
13
14
  setMeta,
14
15
  type Author,
15
16
  type CommentAnchor,
16
- } from './canvas-doc';
17
+ getAbsolutePosition,
18
+ sizeOf,
19
+ type LayoutResult,
20
+ getNodeName,
21
+ } from '@eventcatalog/visualiser/studio';
17
22
  import {
18
23
  describeNode,
19
24
  nodeCenter,
@@ -27,9 +32,6 @@ import {
27
32
  type NodeUpdate,
28
33
  } from './canvas-actions';
29
34
  import { getRelatedEdges } from './catalog';
30
- import { getAbsolutePosition, sizeOf } from './grouping';
31
- import type { LayoutResult } from './layout';
32
- import { getNodeName } from './node-types';
33
35
 
34
36
  /**
35
37
  * Agents work on a canvas like a person would: their cursor travels to where they're going, they drop one node,
@@ -292,13 +294,14 @@ export async function playLayout(stage: AgentStage, layout: LayoutResult) {
292
294
  hand.say('Done');
293
295
  }
294
296
 
295
- /** Moves nodes and resizes containers from a layout, in one change, and marks when it happened */
297
+ /**
298
+ * Moves nodes, resizes containers and routes connections from a layout, in one change, and marks when it
299
+ * happened. Connections the layout didn't route lose their old route (drawn as a plain step instead).
300
+ */
296
301
  export const applyLayout = (doc: Y.Doc, layout: LayoutResult) =>
297
302
  doc.transact(() => {
298
- layout.forEach(({ position, size }, id) => {
299
- moveNode(doc, id, position);
300
- if (size) resizeNode(doc, id, size);
301
- });
303
+ layout.nodes.forEach(({ position, size }, id) => placeNode(doc, id, position, size));
304
+ setEdgeRoutes(doc, layout.routes);
302
305
  setMeta(doc, { layoutAt: Date.now() });
303
306
  });
304
307
 
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Who an agent is, named after its client when it doesn't say, in its brand's colour: on the server (MCP tools) and
3
+ * in a chat's canvas view (which joins as the chat's agent). Their logos are in the visualiser's ClientLogos.
4
+ */
5
+ export type AgentIdentity = { name: string; color: string };
6
+
7
+ const AGENT_COLORS: Record<string, string> = {
8
+ ChatGPT: '#10a37f',
9
+ Codex: '#10a37f',
10
+ Claude: '#d97757',
11
+ 'Claude Code': '#d97757',
12
+ Cursor: '#111827',
13
+ };
14
+
15
+ /** Agents' clients, by what's in their user agent or host name (most specific first) */
16
+ const CLIENTS: [RegExp, string][] = [
17
+ [/claude[-_ ]?code/i, 'Claude Code'],
18
+ [/claude|anthropic/i, 'Claude'],
19
+ [/codex/i, 'Codex'],
20
+ [/openai|chatgpt/i, 'ChatGPT'],
21
+ [/cursor/i, 'Cursor'],
22
+ ];
23
+
24
+ /** Who the agent is, from the name it gives, else its client's user agent (or a chat's host name) */
25
+ export const getAgent = (agentName: string | undefined, client = ''): AgentIdentity => {
26
+ const name = agentName?.trim() || CLIENTS.find(([pattern]) => pattern.test(client))?.[1] || 'AI agent';
27
+ return { name, color: AGENT_COLORS[name] ?? '#8b5cf6' };
28
+ };
@@ -0,0 +1,219 @@
1
+ import { Hono, type Context } from 'hono';
2
+ import { z } from 'zod';
3
+ import { paginate } from '@features/tools/catalog-tools';
4
+ import { type CanvasContent, type CanvasStatus } from '@eventcatalog/visualiser/studio';
5
+ import { MAX_TITLE_LENGTH } from '../limits';
6
+ import { diagramLevelsSchema, indexCatalog, newCanvasEdgesSchema, nodeSpecsSchema, planCanvas } from '../canvas-actions';
7
+ import { getCatalogResources } from '../catalog-resources';
8
+ import { MAX_NAME_LENGTH } from '../identity';
9
+ import type { CanvasSummary, StudioRuntime } from '../server/runtime';
10
+ import type { SignedInUser } from '../server/sign-in';
11
+
12
+ /**
13
+ * The Studio API: canvases as a whole (listing, creating, reading and deleting them). What's on a canvas is changed
14
+ * over the collaboration connection, or by agents through the MCP tools, never here: they're live documents that
15
+ * people and agents edit together.
16
+ *
17
+ * GET /api/studio/canvases Canvases, most recently changed first (?pageSize=, ?cursor= for the next page)
18
+ * (not ones left empty and untitled: GET /:id still finds them)
19
+ * POST /api/studio/canvases Creates one: { "title"?: string, "createdBy"?: string, "nodes"?: [...],
20
+ * "edges"?: [...] }, starting with the nodes and edges given, if any (as the
21
+ * add_to_canvas MCP tool takes them: catalog resources or new components, x/y
22
+ * their centres, and only the connections in edges are made, each drawn
23
+ * along its "route" if given: { "points": [{x, y}, ...], "label"?: {x, y} }),
24
+ * and "levels" (L1 and L2 laid out, e.g. as a diagram shows them, by the
25
+ * nodes' refs), shown as given until what's on the canvas changes
26
+ * GET /api/studio/canvases/:id One canvas
27
+ * POST /api/studio/canvases/:id/copy Copies its design (nodes and connections, not comments or status) to a new
28
+ * draft: { "title"?: string, "createdBy"?: string }
29
+ * DELETE /api/studio/canvases/:id Deletes it for everyone (anyone who has it open is told), for good
30
+ *
31
+ * Errors are `{ "error": "..." }` with the HTTP status. With sign-in on, only signed-in people can use it (401
32
+ * otherwise), and canvases are created by whoever is signed in. Requests that change something (POST, DELETE) from
33
+ * outside a browser send `Content-Type: application/json`: Astro refuses ones with no content type that don't come
34
+ * from the catalog's own pages.
35
+ */
36
+ export const CANVASES_API_PATH = '/api/studio/canvases';
37
+
38
+ const CANVAS_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
39
+ const MAX_PAGE_SIZE = 100;
40
+
41
+ /** A canvas, as the API gives it */
42
+ export type ApiCanvas = {
43
+ id: string;
44
+ title: string | null;
45
+ status: CanvasStatus;
46
+ /** ISO 8601 */
47
+ createdAt: string | null;
48
+ /** Who started it (a person, or an agent) */
49
+ createdBy: string | null;
50
+ /** When anyone (a person, or an agent) last changed it (ISO 8601) */
51
+ updatedAt: string | null;
52
+ nodeCount: number;
53
+ edgeCount: number;
54
+ openComments: number;
55
+ /** Where people open it */
56
+ url: string;
57
+ };
58
+
59
+ export type CanvasesApiEnv = {
60
+ Bindings: {
61
+ runtime: StudioRuntime;
62
+ /** Who's signed in (sign-in on) */
63
+ signedInAs?: SignedInUser;
64
+ /** A canvas's page */
65
+ canvasUrl: (canvasId: string) => string;
66
+ };
67
+ };
68
+
69
+ const MAX_NODES = 1000;
70
+ const MAX_EDGES = 2000;
71
+
72
+ const NewCanvas = z.object({
73
+ title: z.string().trim().max(MAX_TITLE_LENGTH).optional(),
74
+ // Ignored when someone's signed in: it's them
75
+ createdBy: z.string().trim().max(MAX_NAME_LENGTH).optional(),
76
+ });
77
+ // A new canvas can start with nodes and edges; a copy starts with the original's
78
+ const NewCanvasWithContent = NewCanvas.extend({
79
+ nodes: nodeSpecsSchema.max(MAX_NODES).optional(),
80
+ edges: newCanvasEdgesSchema.max(MAX_EDGES).optional(),
81
+ levels: diagramLevelsSchema.optional(),
82
+ }).refine((canvas) => !canvas.edges?.length || canvas.nodes, {
83
+ message: 'Edges connect the nodes given with them: give nodes too',
84
+ path: ['edges'],
85
+ });
86
+ const ListQuery = z.object({
87
+ cursor: z.string().optional(),
88
+ pageSize: z.coerce.number().int().min(1).max(MAX_PAGE_SIZE).optional(),
89
+ });
90
+
91
+ const iso = (time?: number) => (time ? new Date(time).toISOString() : null);
92
+ const toApiCanvas = (canvas: CanvasSummary, canvasUrl: (canvasId: string) => string): ApiCanvas => ({
93
+ id: canvas.canvasId,
94
+ title: canvas.title ?? null,
95
+ status: canvas.status,
96
+ createdAt: iso(canvas.createdAt),
97
+ createdBy: canvas.createdBy ?? null,
98
+ updatedAt: iso(canvas.updatedAt),
99
+ nodeCount: canvas.nodeCount,
100
+ edgeCount: canvas.edgeCount,
101
+ openComments: canvas.openComments,
102
+ url: canvasUrl(canvas.canvasId),
103
+ });
104
+ const describeIssues = (error: z.ZodError) =>
105
+ error.issues.map((issue) => (issue.path.length ? `${issue.path.join('.')}: ${issue.message}` : issue.message)).join('; ');
106
+
107
+ type ApiContext = Context<CanvasesApiEnv>;
108
+ const noCanvas = (c: ApiContext, id: string) => c.json({ error: `No canvas "${id}"` }, 404);
109
+
110
+ type NewCanvasDetails = { title?: string; createdBy?: string };
111
+
112
+ /** The request's JSON body (or {} without one), or the response saying what's wrong with it */
113
+ const readJson = async (c: ApiContext): Promise<unknown> => {
114
+ // JSON only: a page on another site can send a form or plain text here without asking first, but not JSON
115
+ const body = await c.req.text();
116
+ if (body && !c.req.header('content-type')?.toLowerCase().startsWith('application/json')) {
117
+ return c.json({ error: 'Send the canvas as JSON (Content-Type: application/json)' }, 415);
118
+ }
119
+ try {
120
+ return body ? JSON.parse(body) : {};
121
+ } catch {
122
+ return c.json({ error: 'The body is not valid JSON' }, 400);
123
+ }
124
+ };
125
+
126
+ const detailsOf = (c: ApiContext, canvas: z.output<typeof NewCanvas>): NewCanvasDetails => ({
127
+ title: canvas.title || undefined,
128
+ // Whoever's signed in, if anyone
129
+ createdBy: c.env.signedInAs?.name ?? (canvas.createdBy || undefined),
130
+ });
131
+
132
+ /** A copy's details from the request (optional), or the response saying what's wrong with them */
133
+ const readCopy = async (c: ApiContext): Promise<NewCanvasDetails | Response> => {
134
+ const json = await readJson(c);
135
+ if (json instanceof Response) return json;
136
+ const parsed = NewCanvas.safeParse(json);
137
+ if (!parsed.success) return c.json({ error: describeIssues(parsed.error) }, 400);
138
+ return detailsOf(c, parsed.data);
139
+ };
140
+
141
+ /** A new canvas's details and what it starts with (all optional), or the response saying what's wrong with them */
142
+ const readNewCanvas = async (c: ApiContext): Promise<{ details: NewCanvasDetails; content?: CanvasContent } | Response> => {
143
+ const json = await readJson(c);
144
+ if (json instanceof Response) return json;
145
+ const parsed = NewCanvasWithContent.safeParse(json);
146
+ if (!parsed.success) return c.json({ error: describeIssues(parsed.error) }, 400);
147
+ const details = detailsOf(c, parsed.data);
148
+ if (!parsed.data.nodes) return { details };
149
+ const { resources, relations } = await getCatalogResources();
150
+ const { content, errors } = planCanvas(
151
+ parsed.data.nodes,
152
+ parsed.data.edges ?? [],
153
+ indexCatalog(resources, relations),
154
+ parsed.data.levels
155
+ );
156
+ if (errors.length) return c.json({ error: errors.join('; ') }, 400);
157
+ return { details, content };
158
+ };
159
+
160
+ /** The API, served under `basePath` (the catalog's base URL, then CANVASES_API_PATH) */
161
+ export const createCanvasesApi = (basePath: string) => {
162
+ const app = new Hono<CanvasesApiEnv>({ strict: false }).basePath(basePath);
163
+
164
+ app.get('/', (c) => {
165
+ const query = ListQuery.safeParse(c.req.query());
166
+ if (!query.success) return c.json({ error: describeIssues(query.error) }, 400);
167
+ const { runtime, canvasUrl } = c.env;
168
+ const page = paginate(runtime.listCanvases(), query.data.cursor, query.data.pageSize);
169
+ if ('error' in page) return c.json({ error: page.error }, 400);
170
+ return c.json({
171
+ canvases: page.items.map((canvas) => toApiCanvas(canvas, canvasUrl)),
172
+ totalCount: page.totalCount,
173
+ ...(page.nextCursor && { nextCursor: page.nextCursor }),
174
+ });
175
+ });
176
+
177
+ /** A canvas just made, as created */
178
+ const created = (c: ApiContext, canvasId: string) => {
179
+ c.header('Location', `${basePath}/${canvasId}`);
180
+ return c.json({ canvas: toApiCanvas(c.env.runtime.getCanvas(canvasId)!, c.env.canvasUrl) }, 201);
181
+ };
182
+
183
+ app.post('/', async (c) => {
184
+ const canvas = await readNewCanvas(c);
185
+ if (canvas instanceof Response) return canvas;
186
+ return created(c, await c.env.runtime.createCanvas(canvas.details, canvas.content));
187
+ });
188
+
189
+ app.post('/:id/copy', async (c) => {
190
+ const id = c.req.param('id');
191
+ if (!CANVAS_ID.test(id)) return noCanvas(c, id);
192
+ const details = await readCopy(c);
193
+ if (details instanceof Response) return details;
194
+ const copyId = await c.env.runtime.copyCanvas(id, details);
195
+ return copyId ? created(c, copyId) : noCanvas(c, id);
196
+ });
197
+
198
+ app.get('/:id', (c) => {
199
+ const id = c.req.param('id');
200
+ const canvas = CANVAS_ID.test(id) ? c.env.runtime.getCanvas(id) : undefined;
201
+ if (!canvas) return noCanvas(c, id);
202
+ return c.json({ canvas: toApiCanvas(canvas, c.env.canvasUrl) });
203
+ });
204
+
205
+ app.delete('/:id', (c) => {
206
+ const id = c.req.param('id');
207
+ if (!CANVAS_ID.test(id)) return noCanvas(c, id);
208
+ try {
209
+ if (!c.env.runtime.deleteCanvas(id)) return noCanvas(c, id);
210
+ } catch (error) {
211
+ console.error(`[studio] Could not delete canvas ${id}`, error);
212
+ return c.json({ error: `Could not delete the canvas: ${(error as Error).message}` }, 500);
213
+ }
214
+ return c.body(null, 204);
215
+ });
216
+
217
+ app.notFound((c) => c.json({ error: 'Not found' }, 404));
218
+ return app;
219
+ };
@@ -0,0 +1,25 @@
1
+ import type { APIRoute } from 'astro';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import { startStudio } from '../server/runtime';
4
+ import { getSignedInUser, isSignedIn } from '../server/sign-in';
5
+ import { CANVASES_API_PATH, createCanvasesApi } from './canvases-api';
6
+
7
+ // The Studio API (see canvases-api.ts)
8
+ const api = createCanvasesApi(buildUrl(CANVASES_API_PATH, true));
9
+
10
+ export const ALL: APIRoute = async ({ request, locals, url }) => {
11
+ let runtime: Awaited<ReturnType<typeof startStudio>>;
12
+ try {
13
+ runtime = await startStudio({ isSignedIn });
14
+ } catch (error) {
15
+ // Its storage can't be used (e.g. the database was updated by a newer EventCatalog)
16
+ return Response.json({ error: `Studio isn't available: ${(error as Error).message}` }, { status: 503 });
17
+ }
18
+ return api.fetch(request, {
19
+ runtime,
20
+ signedInAs: getSignedInUser(locals),
21
+ canvasUrl: (canvasId: string) => `${url.origin}${buildUrl(`/studio/${canvasId}`)}`,
22
+ });
23
+ };
24
+
25
+ export const prerender = false;