@eventcatalog/core 5.0.0-beta.9 → 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 (460) hide show
  1. package/LICENSE +13 -12
  2. package/README.md +5 -5
  3. package/dist/analytics/analytics.cjs +1 -1
  4. package/dist/analytics/analytics.js +2 -2
  5. package/dist/analytics/log-build.cjs +91 -44
  6. package/dist/analytics/log-build.d.cts +2 -2
  7. package/dist/analytics/log-build.d.ts +2 -2
  8. package/dist/analytics/log-build.js +6 -5
  9. package/dist/analytics/studio-usage.cjs +90 -0
  10. package/dist/analytics/studio-usage.d.cts +5 -0
  11. package/dist/analytics/studio-usage.d.ts +5 -0
  12. package/dist/analytics/studio-usage.js +10 -0
  13. package/dist/catalog-runtime.cjs +1 -1
  14. package/dist/{chunk-RFIXKATC.js → chunk-4G7FSRPN.js} +35 -42
  15. package/dist/{chunk-AWOO63ME.js → chunk-AD7CL772.js} +11 -4
  16. package/dist/chunk-CA6WCQ2T.js +54 -0
  17. package/dist/{chunk-GAHKCOQM.js → chunk-JZN4RSMF.js} +1 -1
  18. package/dist/{chunk-JQMYHZWI.js → chunk-NEAVAFSJ.js} +16 -8
  19. package/dist/{chunk-4CFZUHGG.js → chunk-NIVST4WY.js} +1 -1
  20. package/dist/{chunk-ENAG6UH7.js → chunk-NKNOXQ62.js} +1 -6
  21. package/dist/{chunk-ZEY2XUJN.js → chunk-OX6TSVHY.js} +6 -6
  22. package/dist/{chunk-36RYTYT5.js → chunk-PD7KTSYN.js} +1 -1
  23. package/dist/{chunk-EUNQJO3J.js → chunk-RE7UTPWH.js} +1 -1
  24. package/dist/chunk-S5GWAUG5.js +29 -0
  25. package/dist/{chunk-TZVDMWQX.js → chunk-YQGRMDRB.js} +4 -2
  26. package/dist/constants.cjs +1 -1
  27. package/dist/constants.js +1 -1
  28. package/dist/docs/api/02-config.md +57 -7
  29. package/dist/docs/development/00-why-eventcatalog.md +11 -11
  30. package/dist/docs/development/01-fundamentals.md +20 -13
  31. package/dist/docs/development/01-getting-started/configuration-overview.md +2 -2
  32. package/dist/docs/development/01-getting-started/installation.md +9 -1
  33. package/dist/docs/development/_getting-started.mdx +1 -1
  34. package/dist/docs/development/ask-your-architecture/01-intro.md +5 -5
  35. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/01-what-is-eventcatalog-assistant.md +0 -4
  36. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/02-configuration.md +15 -3
  37. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/03-bring-your-own-tools.md +0 -3
  38. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/_category_.json +1 -1
  39. package/dist/docs/development/ask-your-architecture/02-llms.txt.md +1 -1
  40. package/dist/docs/development/ask-your-architecture/{05-skills/01-introduction.md → 03-install-skills.md} +57 -7
  41. package/dist/docs/development/ask-your-architecture/03-mcp-server/_category_.json +1 -1
  42. package/dist/docs/development/ask-your-architecture/03-mcp-server/getting-started.md +86 -33
  43. package/dist/docs/development/ask-your-architecture/03-mcp-server/introduction.md +14 -4
  44. package/dist/docs/development/ask-your-architecture/03-schemas.txt.md +1 -1
  45. package/dist/docs/development/ask-your-architecture/04-agents/_category_.json +1 -1
  46. package/dist/docs/development/authentication/01-introduction.md +2 -23
  47. package/dist/docs/development/authentication/02-enabling-authentication.md +0 -20
  48. package/dist/docs/development/authentication/07-rbac-middleware.md +0 -2
  49. package/dist/docs/development/authentication/providers/03-setting-up-github.md +0 -2
  50. package/dist/docs/development/authentication/providers/03a-setting-up-google.md +0 -2
  51. package/dist/docs/development/authentication/providers/04-setting-up-azure-ad.md +0 -2
  52. package/dist/docs/development/authentication/providers/05-setting-up-okta.md +0 -3
  53. package/dist/docs/development/authentication/providers/06-setting-up-auth0.md +0 -2
  54. package/dist/docs/development/bring-your-own-documentation/01-introduction.md +0 -4
  55. package/dist/docs/development/bring-your-own-documentation/custom-pages/01-introduction.md +0 -3
  56. package/dist/docs/development/bring-your-own-documentation/custom-pages/02-adding-custom-docs.md +0 -17
  57. package/dist/docs/development/bring-your-own-documentation/custom-pages/03-components.md +0 -4
  58. package/dist/docs/development/bring-your-own-documentation/custom-pages/04-owners.md +0 -2
  59. package/dist/docs/development/bring-your-own-documentation/resource-docs/01-introduction.md +1 -3
  60. package/dist/docs/development/bring-your-own-documentation/resource-docs/02-adding-resource-docs.md +1 -4
  61. package/dist/docs/development/bring-your-own-documentation/resource-docs/03-categories.md +0 -2
  62. package/dist/docs/development/bring-your-own-documentation/resource-docs/04-versioning.md +1 -3
  63. package/dist/docs/development/components/components/11-flow.md +17 -0
  64. package/dist/docs/development/components/components/15-nodegraph.md +43 -10
  65. package/dist/docs/development/components/components/18-remote-schema.md +1 -4
  66. package/dist/docs/development/components/custom-components/07-reference.md +14 -0
  67. package/dist/docs/development/customization/02-themes.md +0 -5
  68. package/dist/docs/development/customization/03-search.md +1 -1
  69. package/dist/docs/development/customization/05-custom-pages-and-api-routes/01-introduction.md +0 -2
  70. package/dist/docs/development/customization/05-custom-pages-and-api-routes/04-reference.md +7 -1
  71. package/dist/docs/development/customization/05-resource-sidebar.md +1 -1
  72. package/dist/docs/development/customization/09-embed-eventcatalog.md +20 -25
  73. package/dist/docs/development/deployment/hosting-options.md +7 -2
  74. package/dist/docs/development/developer-tools/eventcatalog-linter/how-to/05-fix-common-problems.md +16 -0
  75. package/dist/docs/development/developer-tools/eventcatalog-linter/reference/03-rules.md +31 -1
  76. package/dist/docs/development/developer-tools/eventcatalog-linter/reference/05-supported-resources.md +1 -1
  77. package/dist/docs/development/governance/architecture-change-detection/01-introduction.md +0 -10
  78. package/dist/docs/development/governance/architecture-change-detection/06-pipeline-gates.md +0 -4
  79. package/dist/docs/development/guides/97-architecture-graph.md +1 -1
  80. package/dist/docs/development/guides/99-adding-analytics.md +0 -7
  81. package/dist/docs/development/guides/domains/03-model-subdomains.md +2 -2
  82. package/dist/docs/development/guides/domains/04-add-resources-to-domains/01-add-systems-to-domains.md +3 -1
  83. package/dist/docs/development/guides/domains/04-add-resources-to-domains/02-add-services-to-domains.md +5 -1
  84. package/dist/docs/development/guides/domains/04-add-resources-to-domains/03-add-messages-to-domains.md +2 -2
  85. package/dist/docs/development/guides/domains/04-add-resources-to-domains/05-add-entities-to-domains.md +1 -1
  86. package/dist/docs/development/guides/domains/04-add-resources-to-domains/06-domain-resources-page.md +40 -0
  87. package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-diagram.md +89 -0
  88. package/dist/docs/development/guides/domains/06-visualize-domains/_category_.json +1 -2
  89. package/dist/docs/development/guides/domains/09-reference.md +4 -4
  90. package/dist/docs/development/guides/owners/automated-teams-and-users/create-your-own-connector.md +0 -2
  91. package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-github.md +0 -3
  92. package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-microsoft-entra.md +0 -2
  93. package/dist/docs/development/guides/resources/adrs/03-linking-resources.md +8 -0
  94. package/dist/docs/development/guides/resources/adrs/06-reference.md +4 -4
  95. package/dist/docs/development/guides/resources/agents/11-reference.md +1 -1
  96. package/dist/docs/development/guides/resources/data/04-reference.md +1 -1
  97. package/dist/docs/development/guides/resources/data-products/07-reference.md +1 -1
  98. package/dist/docs/development/guides/resources/entities/05-entity-maps.md +1 -1
  99. package/dist/docs/development/guides/resources/entities/06-reference.md +2 -2
  100. package/dist/docs/development/guides/resources/flows/01-introduction.md +11 -1
  101. package/dist/docs/development/guides/resources/flows/03-model-flow-steps.md +65 -6
  102. package/dist/docs/development/guides/resources/flows/05-explore-flows.md +112 -0
  103. package/dist/docs/development/guides/resources/flows/06-reference.md +25 -4
  104. package/dist/docs/development/guides/resources/messages/01-what-are-messages.md +19 -0
  105. package/dist/docs/development/guides/resources/messages/04-message-channels/01-introduction.md +16 -0
  106. package/dist/docs/development/guides/resources/messages/04-message-channels/05-reference.md +2 -1
  107. package/dist/docs/development/guides/resources/messages/10-reference.md +6 -3
  108. package/dist/docs/development/guides/resources/schemas/04-explore-schemas/01-schema-explorer.md +2 -2
  109. package/dist/docs/development/guides/resources/schemas/04-explore-schemas/02-fields-explorer.md +0 -9
  110. package/dist/docs/development/guides/resources/schemas/05-schema-api.md +0 -3
  111. package/dist/docs/development/guides/resources/schemas/06-schema-mcp.md +11 -3
  112. package/dist/docs/development/guides/resources/services/04-add-resources-to-services/03-add-entities-to-services.md +1 -1
  113. package/dist/docs/development/guides/resources/services/05-resources-page.md +50 -0
  114. package/dist/docs/development/guides/resources/services/08-reference.md +2 -1
  115. package/dist/docs/development/guides/systems/01-introduction.md +1 -1
  116. package/dist/docs/development/guides/systems/02-create-system.md +2 -2
  117. package/dist/docs/development/guides/systems/03-add-resources-to-systems.md +35 -9
  118. package/dist/docs/development/guides/systems/04-model-relationships-and-actors.md +5 -3
  119. package/dist/docs/development/guides/systems/05-system-context-maps.md +39 -22
  120. package/dist/docs/development/guides/systems/06-reference.md +4 -4
  121. package/dist/docs/development/license/01-license-file.md +151 -0
  122. package/dist/docs/development/license/_category_.json +12 -0
  123. package/dist/docs/development/license-keys/_category_.json +3 -3
  124. package/dist/docs/development/license-keys/integrations.md +7 -37
  125. package/dist/docs/development/license-keys/license-validation.md +4 -0
  126. package/dist/docs/development/license-keys/overview.md +5 -1
  127. package/dist/docs/development/license-keys/plans.md +4 -2
  128. package/dist/docs/development/studio/01-introduction.md +60 -0
  129. package/dist/docs/development/studio/02-create-a-canvas.md +103 -0
  130. package/dist/docs/development/studio/03-set-up-persistent-storage.md +59 -0
  131. package/dist/docs/development/studio/04-collaborate-on-a-canvas.md +78 -0
  132. package/dist/docs/development/studio/05-connect-your-agent.md +102 -0
  133. package/dist/docs/development/studio/06-run-studio-in-production.md +54 -0
  134. package/dist/docs/development/studio/07-reference.md +294 -0
  135. package/dist/docs/development/studio/_category_.json +12 -0
  136. package/dist/docs/development/upgrading/v5.md +345 -0
  137. package/dist/docs/federation/00-overview.md +2 -8
  138. package/dist/docs/federation/01-first-federation.md +6 -18
  139. package/dist/docs/federation/explanation/how-it-works.md +0 -4
  140. package/dist/docs/federation/explanation/lockfile-and-cache.md +0 -4
  141. package/dist/docs/federation/explanation/mvp-status-and-feedback.md +0 -4
  142. package/dist/docs/federation/explanation/ownership-and-references.md +0 -4
  143. package/dist/docs/federation/how-to/configure-github-sources.md +6 -5
  144. package/dist/docs/federation/how-to/configure-validation-rules.md +0 -4
  145. package/dist/docs/federation/how-to/run-in-ci.md +2 -9
  146. package/dist/docs/federation/how-to/share-assets-and-components.md +0 -4
  147. package/dist/docs/federation/how-to/use-local-sources.md +0 -4
  148. package/dist/docs/federation/legacy-federation/00-introduction.md +4 -22
  149. package/dist/docs/federation/legacy-federation/01-installation.md +7 -58
  150. package/dist/docs/federation/legacy-federation/02-plugin-configuration.md +3 -21
  151. package/dist/docs/federation/legacy-federation/03-examples.md +3 -5
  152. package/dist/docs/federation/legacy-federation/04-configuration.md +3 -8
  153. package/dist/docs/federation/legacy-federation/05-setup-team-catalog.md +3 -6
  154. package/dist/docs/federation/reference/cli.md +2 -8
  155. package/dist/docs/federation/reference/configuration.md +0 -4
  156. package/dist/docs/federation/reference/diagnostic-rules.md +0 -5
  157. package/dist/docs/federation/reference/generated-output.md +0 -4
  158. package/dist/docs/federation/reference/supported-content.md +0 -4
  159. package/dist/docs/federation/reference/troubleshooting.md +0 -14
  160. package/dist/docs/plugins/02-generators.md +1 -1
  161. package/dist/docs/plugins/amazon-apigateway/00-intro.md +3 -28
  162. package/dist/docs/plugins/amazon-apigateway/01-installation.md +4 -56
  163. package/dist/docs/plugins/amazon-apigateway/02-plugin-configuration.md +1 -6
  164. package/dist/docs/plugins/apicurio/00-intro.md +2 -31
  165. package/dist/docs/plugins/apicurio/01-installation.md +2 -26
  166. package/dist/docs/plugins/apicurio/02-plugin-configuration.md +5 -13
  167. package/dist/docs/plugins/apicurio/03-features.md +1 -3
  168. package/dist/docs/plugins/asyncapi/00-intro.md +2 -28
  169. package/dist/docs/plugins/asyncapi/01-installation.md +3 -54
  170. package/dist/docs/plugins/asyncapi/02-plugin-configuration.md +2 -1
  171. package/dist/docs/plugins/aws-glue-registry/00-intro.md +4 -32
  172. package/dist/docs/plugins/aws-glue-registry/00a-installation.md +3 -53
  173. package/dist/docs/plugins/azure-schema-registry/00-intro.md +4 -32
  174. package/dist/docs/plugins/azure-schema-registry/01-installation.md +6 -33
  175. package/dist/docs/plugins/azure-schema-registry/02-plugin-configuration.md +1 -14
  176. package/dist/docs/plugins/azure-schema-registry/04-examples.md +0 -2
  177. package/dist/docs/plugins/backstage/00-overview.md +1 -7
  178. package/dist/docs/plugins/backstage/01-get-started.md +6 -15
  179. package/dist/docs/plugins/backstage/06-configuration.md +2 -8
  180. package/dist/docs/plugins/confluent-schema-registry/00-intro.md +2 -29
  181. package/dist/docs/plugins/confluent-schema-registry/01-installation.md +2 -26
  182. package/dist/docs/plugins/eventbridge/00-intro.md +0 -4
  183. package/dist/docs/plugins/eventbridge/00a-installation.md +1 -87
  184. package/dist/docs/plugins/eventbridge/03-api.md +2 -20
  185. package/dist/docs/plugins/github/00-intro.md +0 -31
  186. package/dist/docs/plugins/github/01-installation.md +2 -34
  187. package/dist/docs/plugins/graphql/00-intro.md +0 -30
  188. package/dist/docs/plugins/graphql/01-installation.md +1 -53
  189. package/dist/docs/plugins/graphql/02-plugin-configuration.md +0 -1
  190. package/dist/docs/plugins/hookdeck/01-intro.md +1 -1
  191. package/dist/docs/plugins/openapi/00-intro.md +0 -30
  192. package/dist/docs/plugins/openapi/01-installation.md +1 -57
  193. package/dist/docs/plugins/openapi/02-plugin-configuration.md +0 -5
  194. package/dist/docs/plugins/openapi/03-features.md +0 -4
  195. package/dist/eventcatalog-config-file-utils.cjs +34 -41
  196. package/dist/eventcatalog-config-file-utils.d.cts +56 -58
  197. package/dist/eventcatalog-config-file-utils.d.ts +56 -58
  198. package/dist/eventcatalog-config-file-utils.js +1 -1
  199. package/dist/eventcatalog.cjs +340 -249
  200. package/dist/eventcatalog.config.d.cts +18 -15
  201. package/dist/eventcatalog.config.d.ts +18 -15
  202. package/dist/eventcatalog.js +51 -33
  203. package/dist/features.cjs +36 -49
  204. package/dist/features.d.cts +1 -3
  205. package/dist/features.d.ts +1 -3
  206. package/dist/features.js +4 -6
  207. package/dist/federation/federate.cjs +37 -44
  208. package/dist/federation/federate.js +5 -5
  209. package/dist/federation/source-provider.js +2 -2
  210. package/dist/generate.cjs +37 -42
  211. package/dist/generate.js +4 -4
  212. package/dist/resolve-catalog-dependencies.cjs +34 -41
  213. package/dist/resolve-catalog-dependencies.js +2 -2
  214. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
  215. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
  216. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
  217. package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
  218. package/dist/runtime-dependencies/manifest.json +5 -1
  219. package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
  220. package/dist/utils/child-process-signals.cjs +53 -0
  221. package/dist/utils/child-process-signals.d.cts +19 -0
  222. package/dist/utils/child-process-signals.d.ts +19 -0
  223. package/dist/utils/child-process-signals.js +6 -0
  224. package/dist/utils/cli-logger.cjs +1 -1
  225. package/dist/utils/cli-logger.js +2 -2
  226. package/dist/utils/license-status.cjs +11 -4
  227. package/dist/utils/license-status.d.cts +3 -2
  228. package/dist/utils/license-status.d.ts +3 -2
  229. package/dist/utils/license-status.js +1 -1
  230. package/eventcatalog/astro.config.mjs +21 -1
  231. package/eventcatalog/integrations/config-loader.mjs +56 -58
  232. package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
  233. package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
  234. package/eventcatalog/integrations/storage.mjs +20 -0
  235. package/eventcatalog/integrations/studio-server.mjs +4 -1
  236. package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
  237. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
  238. package/eventcatalog/src/components/Homepage/CatalogDashboard.astro +342 -0
  239. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +60 -4
  240. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
  241. package/eventcatalog/src/components/NavigationProgress.astro +7 -0
  242. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +2 -0
  243. package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +2 -0
  244. package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -0
  245. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -0
  246. package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
  247. package/eventcatalog/src/components/Search/SearchModal.tsx +2 -10
  248. package/eventcatalog/src/components/Search/search-utils.ts +26 -0
  249. package/eventcatalog/src/components/Seo.astro +5 -1
  250. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +53 -48
  251. package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +183 -178
  252. package/eventcatalog/src/components/Settings/LicenseSettings.tsx +140 -31
  253. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +40 -35
  254. package/eventcatalog/src/components/Settings/LogoUpload.tsx +1 -1
  255. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +9 -8
  256. package/eventcatalog/src/components/Settings/Row.tsx +7 -4
  257. package/eventcatalog/src/components/Settings/SettingsShared.tsx +3 -3
  258. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +37 -76
  259. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
  260. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +122 -1
  261. package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
  262. package/eventcatalog/src/components/TrialBadge.astro +20 -9
  263. package/eventcatalog/src/content.config.ts +19 -2
  264. package/eventcatalog/src/features/auth/error.astro +4 -2
  265. package/eventcatalog/src/features/auth/login.astro +2 -1
  266. package/eventcatalog/src/features/auth/middleware/middleware-auth.ts +21 -1
  267. package/eventcatalog/src/features/auth/unauthorized.astro +1 -1
  268. package/eventcatalog/src/features/fields/pages/fields.astro +1 -1
  269. package/eventcatalog/src/features/integrations/eventcatalog-features.ts +13 -7
  270. package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
  271. package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +3 -3
  272. package/eventcatalog/src/features/mcp/apps/canvas/styles.css +3 -1
  273. package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +7 -5
  274. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +123 -98
  275. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +118 -101
  276. package/eventcatalog/src/features/mcp/mcp-server.ts +20 -4
  277. package/eventcatalog/src/features/server/start.ts +25 -0
  278. package/eventcatalog/src/features/storage/database.ts +88 -0
  279. package/eventcatalog/src/features/storage/migrations.ts +85 -0
  280. package/eventcatalog/src/features/storage/sql/database.sql +5 -0
  281. package/eventcatalog/src/features/storage/sql/migrations/0001-studio-canvases.sql +12 -0
  282. package/eventcatalog/src/features/storage/sql/migrations.sql +15 -0
  283. package/eventcatalog/src/features/storage/sql.ts +28 -0
  284. package/eventcatalog/src/features/studio/agent-choreography.ts +13 -10
  285. package/eventcatalog/src/features/studio/agents.ts +28 -0
  286. package/eventcatalog/src/features/studio/api/canvases-api.ts +219 -0
  287. package/eventcatalog/src/features/studio/api/canvases.ts +25 -0
  288. package/eventcatalog/src/features/studio/api/client.ts +40 -0
  289. package/eventcatalog/src/features/studio/canvas-actions.ts +160 -34
  290. package/eventcatalog/src/features/studio/canvas-preview.ts +1 -2
  291. package/eventcatalog/src/features/studio/catalog.ts +16 -14
  292. package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +274 -105
  293. package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +15 -14
  294. package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +272 -119
  295. package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +1 -2
  296. package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +65 -0
  297. package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
  298. package/eventcatalog/src/features/studio/components/JoinForm.tsx +101 -26
  299. package/eventcatalog/src/features/studio/components/LeftPanel.tsx +122 -230
  300. package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
  301. package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
  302. package/eventcatalog/src/features/studio/components/Presence.tsx +52 -45
  303. package/eventcatalog/src/features/studio/components/ShareDialog.tsx +277 -141
  304. package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
  305. package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +1314 -385
  306. package/eventcatalog/src/features/studio/components/StudioNotice.astro +24 -0
  307. package/eventcatalog/src/features/studio/document-name.ts +7 -0
  308. package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
  309. package/eventcatalog/src/features/studio/hooks/presence-sender.ts +19 -2
  310. package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +9 -3
  311. package/eventcatalog/src/features/studio/hooks/use-comments.ts +2 -2
  312. package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +8 -3
  313. package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +244 -32
  314. package/eventcatalog/src/features/studio/identity.ts +25 -1
  315. package/eventcatalog/src/features/studio/limits.ts +2 -0
  316. package/eventcatalog/src/features/studio/pages/[id].astro +42 -16
  317. package/eventcatalog/src/features/studio/pages/index.astro +596 -373
  318. package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +12 -15
  319. package/eventcatalog/src/features/studio/server/canvas-mcp.ts +8 -23
  320. package/eventcatalog/src/features/studio/server/runtime.ts +150 -46
  321. package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
  322. package/eventcatalog/src/features/studio/server/storage.ts +53 -73
  323. package/eventcatalog/src/features/studio/webmcp-relay/LICENSE +21 -0
  324. package/eventcatalog/src/features/studio/webmcp-relay/README.md +5 -0
  325. package/eventcatalog/src/features/studio/webmcp-relay/embed.js +2 -0
  326. package/eventcatalog/src/features/studio/webmcp-relay/widget.html +10 -0
  327. package/eventcatalog/src/features/studio/webmcp-relay/widget.js +1 -0
  328. package/eventcatalog/src/features/tools/catalog-tools.ts +3 -1
  329. package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
  330. package/eventcatalog/src/layouts/SettingsLayout.astro +2 -2
  331. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +3 -2
  332. package/eventcatalog/src/pages/_index.astro +5 -342
  333. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +2 -3
  334. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +0 -7
  335. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +3 -1
  336. package/eventcatalog/src/pages/diagrams/[id]/[version]/_index.data.ts +0 -7
  337. package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +1 -0
  338. package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +1 -0
  339. package/eventcatalog/src/pages/directory/[type]/_index.data.ts +5 -7
  340. package/eventcatalog/src/pages/directory/[type]/index.astro +3 -1
  341. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -7
  342. package/eventcatalog/src/pages/discover/[type]/index.astro +3 -1
  343. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +0 -7
  344. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -0
  345. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +0 -7
  346. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -0
  347. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +0 -7
  348. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +3 -1
  349. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/_[filename].data.ts +0 -7
  350. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +0 -7
  351. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -0
  352. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +1 -0
  353. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/_[...filename].data.ts +0 -4
  354. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/_index.data.ts +0 -7
  355. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/index.astro +1 -0
  356. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +3 -1
  357. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/_[filename].data.ts +0 -7
  358. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
  359. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +2 -3
  360. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +0 -7
  361. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +1 -0
  362. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +1 -0
  363. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/_[filename].data.ts +0 -7
  364. package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +0 -7
  365. package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +2 -1
  366. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/_index.data.ts +0 -7
  367. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +1 -0
  368. package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +0 -7
  369. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +1 -0
  370. package/eventcatalog/src/pages/docs/custom/[...path]/_index.data.ts +0 -7
  371. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +1 -0
  372. package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +1 -1
  373. package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +1 -0
  374. package/eventcatalog/src/pages/docs/services/[id]/asyncapi/[filename].astro +1 -1
  375. package/eventcatalog/src/pages/docs/services/[id]/changelog/index.astro +1 -1
  376. package/eventcatalog/src/pages/docs/services/[id]/graphql/[filename].astro +1 -1
  377. package/eventcatalog/src/pages/docs/services/[id]/spec/[filename].astro +1 -1
  378. package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +0 -7
  379. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +1 -0
  380. package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +0 -7
  381. package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -0
  382. package/eventcatalog/src/pages/index.astro +4 -2
  383. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +0 -7
  384. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +9 -1
  385. package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +0 -7
  386. package/eventcatalog/src/pages/schemas/explorer/index.astro +4 -2
  387. package/eventcatalog/src/pages/settings/license.astro +9 -1
  388. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/_index.data.ts +0 -7
  389. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/index.astro +1 -0
  390. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +0 -7
  391. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/_index.data.ts +0 -7
  392. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +1 -0
  393. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/_index.data.ts +0 -7
  394. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -0
  395. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -0
  396. package/eventcatalog/src/pages/visualiser/[type]/[id]/_index.data.ts +38 -0
  397. package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +18 -41
  398. package/eventcatalog/src/pages/visualiser/designs/[id]/_index.data.ts +0 -7
  399. package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -1
  400. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +0 -7
  401. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -0
  402. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +1 -0
  403. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +0 -7
  404. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +1 -0
  405. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +0 -7
  406. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +1 -0
  407. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +1 -0
  408. package/eventcatalog/src/types/react-syntax-highlighter.d.ts +10 -0
  409. package/eventcatalog/src/utils/collections/flows.ts +20 -7
  410. package/eventcatalog/src/utils/collections/resource-owners.ts +8 -2
  411. package/eventcatalog/src/utils/collections/resources.ts +2 -0
  412. package/eventcatalog/src/utils/collections/util.ts +8 -4
  413. package/eventcatalog/src/utils/git.ts +11 -0
  414. package/eventcatalog/src/utils/homepage-dashboard.ts +143 -0
  415. package/eventcatalog/src/utils/license.ts +1 -1
  416. package/eventcatalog/src/utils/link-validation.ts +25 -19
  417. package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +3 -1
  418. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
  419. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +4 -2
  420. package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +20 -1
  421. package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
  422. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
  423. package/eventcatalog/src/utils/page-loaders/hybrid-page.ts +4 -15
  424. package/eventcatalog/src/utils/page-title.ts +15 -0
  425. package/eventcatalog/src/utils/syntax-highlighter-renderer.ts +64 -0
  426. package/eventcatalog/src/utils/trial.ts +13 -0
  427. package/package.json +11 -11
  428. package/dist/docs/development/ask-your-architecture/05-skills/02-installation.md +0 -60
  429. package/dist/docs/development/ask-your-architecture/05-skills/_category_.json +0 -11
  430. package/dist/docs/development/ask-your-architecture/06-slack-integration/01-introduction.md +0 -63
  431. package/dist/docs/development/ask-your-architecture/06-slack-integration/02-slack-app-setup.md +0 -154
  432. package/dist/docs/development/ask-your-architecture/06-slack-integration/03-installation.md +0 -169
  433. package/dist/docs/development/ask-your-architecture/06-slack-integration/04-deployment.md +0 -236
  434. package/dist/docs/development/ask-your-architecture/06-slack-integration/05-usage.md +0 -140
  435. package/dist/docs/development/ask-your-architecture/06-slack-integration/06-troubleshooting.md +0 -268
  436. package/dist/docs/development/ask-your-architecture/06-slack-integration/_category_.json +0 -13
  437. package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-integration-map.md +0 -40
  438. package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +0 -3
  439. package/eventcatalog/src/features/studio/canvas-doc.ts +0 -409
  440. package/eventcatalog/src/features/studio/clipboard.ts +0 -97
  441. package/eventcatalog/src/features/studio/components/CanvasControls.tsx +0 -154
  442. package/eventcatalog/src/features/studio/components/Comments.tsx +0 -770
  443. package/eventcatalog/src/features/studio/components/ContainerChooser.tsx +0 -145
  444. package/eventcatalog/src/features/studio/components/DragGhost.tsx +0 -115
  445. package/eventcatalog/src/features/studio/components/Picture.tsx +0 -21
  446. package/eventcatalog/src/features/studio/components/PropertiesPanel.tsx +0 -212
  447. package/eventcatalog/src/features/studio/components/canvas-nodes.tsx +0 -255
  448. package/eventcatalog/src/features/studio/components/icons.ts +0 -53
  449. package/eventcatalog/src/features/studio/components/status.ts +0 -51
  450. package/eventcatalog/src/features/studio/edges.ts +0 -56
  451. package/eventcatalog/src/features/studio/flow-state.ts +0 -92
  452. package/eventcatalog/src/features/studio/grouping.ts +0 -226
  453. package/eventcatalog/src/features/studio/layout.ts +0 -42
  454. package/eventcatalog/src/features/studio/levels.ts +0 -282
  455. package/eventcatalog/src/features/studio/node-types.ts +0 -205
  456. package/eventcatalog/src/features/studio/pages/new.astro +0 -24
  457. package/eventcatalog/src/features/studio/pages/wake.ts +0 -15
  458. package/eventcatalog/src/features/studio/placement.ts +0 -197
  459. package/eventcatalog/src/features/studio/studio.css +0 -273
  460. package/dist/{chunk-A2RZR3U4.js → chunk-6K7XZAYI.js} +3 -3
@@ -0,0 +1,5 @@
1
+ # WebMCP local relay (browser files)
2
+
3
+ `embed.js`, `widget.html` and `widget.js` are the browser files of [`@mcp-b/webmcp-local-relay`](https://github.com/WebMCP-org/npm-packages/tree/main/packages/webmcp-local-relay) **5.1.0** (MIT, see `LICENSE`), copied as published. Studio serves them at `/webmcp-relay/*` so a canvas can hand its WebMCP tools to desktop MCP clients running `npx -y @mcp-b/webmcp-local-relay@5.1.0`.
4
+
5
+ They're copied rather than installed because the package's Node dependencies (which EventCatalog doesn't run) pin vulnerable versions of `@modelcontextprotocol/core` and `zod`. When moving to a new relay version, copy its `dist/browser` files here and update the version in `ConnectAgentDialog.tsx`.
@@ -0,0 +1,2 @@
1
+ (function(){function e(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function t(t){if(!e(t))return!1;let n=Object.getPrototypeOf(t);return n===Object.prototype||n===null}function n(e,r=new WeakSet){if(e===null||typeof e==`string`||typeof e==`boolean`)return!0;if(typeof e==`number`)return Number.isFinite(e);if(typeof e!=`object`||r.has(e))return!1;r.add(e);try{return(Array.isArray(e)?e:t(e)?Object.values(e):null)?.every(e=>n(e,r))??!1}catch{return!1}finally{r.delete(e)}}function r(e){return n(e)?e:void 0}function i(t){return e(t)&&Array.isArray(t.content)}function a(e){if(typeof e==`string`)return e;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function o(e){if(i(e))return e;let t=r(e);return{content:[{type:`text`,text:a(e)}],...t===void 0?{}:{structuredContent:t},isError:!1}}function s(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function c(){return crypto.randomUUID()}let l=`[data-webmcp-relay]`,u=`__webmcp_relay_tab_id`,d=null,f;function p(){return document.currentScript instanceof HTMLScriptElement?document.currentScript:null}let m=p(),h=m?m.hasAttribute(`data-debug`):!1;function g(...e){h&&console.warn(`[webmcp-relay-embed]`,...e)}function _(){try{let e=sessionStorage.getItem(u);if(e)return e}catch(e){g(`sessionStorage read failed, tab ID will not persist:`,e)}let e=c();try{sessionStorage.setItem(u,e)}catch(e){g(`sessionStorage write failed:`,e)}return e}function v(e){if(!e?.src)throw Error(`The relay embed script must be loaded from a URL`);return new URL(`widget.html`,e.src).href}function y(e){let t=v(e),n=e?.getAttribute(`data-relay-id`)||void 0,r=e?.getAttribute(`data-relay-workspace`)||void 0,i=e?.getAttribute(`data-request-timeout`)||void 0;return{autoConnect:e?.getAttribute(`data-auto-connect`)!==`false`,relayHost:e?.getAttribute(`data-relay-host`)||`127.0.0.1`,relayPort:e?.getAttribute(`data-relay-port`)||`9333`,...n?{relayId:n}:{},...r?{relayWorkspace:r}:{},...i?{requestTimeout:i}:{},tabId:_(),widgetUrl:t,widgetOrigin:new URL(t).origin}}function b(e){return s(e)?e:(e!=null&&g(`Tool invocation args must be an object, got`,typeof e),{})}function x(e){let t;if(e.inputSchema!==void 0)if(typeof e.inputSchema==`string`)try{t=JSON.parse(e.inputSchema)}catch{return console.warn(`[webmcp-relay-embed] Tool "${e.name}" was not relayed because its input schema is malformed.`),null}else t=e.inputSchema;return{name:e.name,...e.title===void 0?{}:{title:e.title},description:e.description,...t===void 0?{}:{inputSchema:t},...e.annotations===void 0?{}:{annotations:e.annotations}}}function S(e){if(e===null)return{isError:!0,content:[{type:`text`,text:`Tool execution interrupted by navigation`}]};let t;try{t=JSON.parse(e)}catch{t=e}return s(t)&&t.resultType===`input_required`?{isError:!0,content:[{type:`text`,text:`The WebMCP local relay cannot forward MCP input_required results. Multi-round tool flows require direct McpServer registration.`}]}:o(t)}function C(e){return!!(e&&`executeTool`in e&&typeof e.executeTool==`function`)}function w(){let e=document.modelContext;return C(e)?e:void 0}async function T(){let e=w();return e?(await e.getTools()).map(x).filter(e=>e!==null):[]}async function E(e,t){let n=w();if(!n)throw Error(`No executable WebMCP runtime found on this page`);let r=(await n.getTools()).find(t=>t.name===e);if(!r)throw Error(`Tool not found: ${e}`);return S(await n.executeTool(r,JSON.stringify(t)))}let D=!1,O=0,k=null,A=``;function j(e){if(typeof e!=`object`||!e)return JSON.stringify(e)??`undefined`;if(Array.isArray(e))return`[${e.map(j).join(`,`)}]`;let t=e;return`{${Object.keys(t).sort().map(e=>`${JSON.stringify(e)}:${j(t[e])}`).join(`,`)}}`}function M(e){return e.map(j).sort().join(`
2
+ `)}function N(){D=!1;let e=O;T().then(t=>{if(e!==O)return;let n=M(t);n===A||!d||(A=n,d.postMessage({type:`webmcp.tools.changed`,tools:t},f.widgetOrigin))}).catch(e=>{g(`Failed to sync tool changes:`,e)})}function P(){O++,!D&&(D=!0,setTimeout(N,0))}function F(){k||(k=setInterval(P,2e3))}function I(){try{let e=document.modelContext;return e?(e.addEventListener(`toolchange`,P),!0):!1}catch(e){return g(`addEventListener on modelContext threw:`,e),!1}}function L(){if(F(),P(),I())return;let e=0,t=100,n=()=>{setTimeout(()=>{if(e++,!I()){if(e>=40){g(`Could not subscribe to tool changes after 40 retries. Dynamic tool updates will rely on polling.`);return}t=Math.min(Math.round(t*1.5),1e3),n()}},t)};n()}function R(e,t,n){!e||typeof e!=`object`||!(`postMessage`in e)||e.postMessage(n,t)}function z(e){return!s(e)||typeof e.requestId!=`string`||typeof e.type!=`string`?null:{requestId:e.requestId,type:e.type,toolName:e.toolName,args:e.args}}function B(e,t){T().then(n=>{R(t.source,t.origin,{type:`webmcp.tools.list.response`,requestId:e.requestId,tools:n})}).catch(n=>{g(`Failed to list tools:`,n),R(t.source,t.origin,{type:`webmcp.tools.list.response`,requestId:e.requestId,tools:[],error:`Failed to list tools: ${n instanceof Error?n.message:String(n)}`})})}function V(e,t){E(String(e.toolName??``),b(e.args)).then(n=>{R(t.source,t.origin,{type:`webmcp.tools.invoke.response`,requestId:e.requestId,result:s(n)?n:{}})}).catch(n=>{R(t.source,t.origin,{type:`webmcp.tools.invoke.error`,requestId:e.requestId,error:String(n instanceof Error?n.message:n)})})}async function H(e){if(document.querySelector(l))return;let t=new URLSearchParams;t.set(`tabId`,e.tabId),t.set(`hostOrigin`,window.location.origin);let n=new URL(window.location.href);n.search=``,n.hash=``,t.set(`hostUrl`,n.href),t.set(`hostTitle`,document.title||``),t.set(`relayHost`,e.relayHost),t.set(`relayPort`,e.relayPort),t.set(`autoConnect`,e.autoConnect?`true`:`false`),e.relayId&&t.set(`relayId`,e.relayId),e.relayWorkspace&&t.set(`relayWorkspace`,e.relayWorkspace),e.requestTimeout&&t.set(`requestTimeout`,e.requestTimeout);let r=await fetch(e.widgetUrl);if(!r.ok)throw Error(`Widget HTML request failed with status ${String(r.status)}`);let i=await r.text(),a=`<script>window.__WEBMCP_RELAY_CONFIG=${JSON.stringify(Object.fromEntries(t))};<\/script>`,o=URL.createObjectURL(new Blob([i.replace(`</head>`,`${a}</head>`)],{type:`text/html`}));e.widgetOrigin=window.location.origin;let s=document.createElement(`iframe`);s.src=o,s.style.display=`none`,s.setAttribute(`aria-hidden`,`true`),s.setAttribute(`data-webmcp-relay`,`1`),s.setAttribute(`allow`,`loopback-network; local-network; local-network-access`),document.body.appendChild(s),d=s.contentWindow,s.addEventListener(`load`,()=>{d=s.contentWindow,URL.revokeObjectURL(o)}),s.addEventListener(`error`,()=>{console.error(`[webmcp-relay-embed] Failed to load relay widget iframe from:`,s.src,`-- WebMCP tools will NOT be relayed. Check network connectivity and widget URL.`),URL.revokeObjectURL(o)})}if(!document.querySelector(l)){try{f=y(m)}catch(e){throw console.error(`[webmcp-relay-embed] Failed to initialize relay configuration:`,e),e}window.addEventListener(`message`,e=>{if(e.origin!==f.widgetOrigin||!d||e.source!==d)return;let t=e.data;if(s(t)&&t.type===`webmcp.reload`){window.location.reload();return}let n=z(e.data);if(n){if(n.type===`webmcp.tools.list.request`){B(n,e);return}n.type===`webmcp.tools.invoke.request`&&V(n,e)}});let e=()=>{H(f).catch(e=>{console.error(`[webmcp-relay-embed] Failed to inject relay widget:`,e)})};document.body?e():document.addEventListener(`DOMContentLoaded`,e,{once:!0}),L(),document.addEventListener(`visibilitychange`,()=>{document.visibilityState===`visible`&&d&&d.postMessage({type:`webmcp.connect`},f.widgetOrigin)})}})();
@@ -0,0 +1,10 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>WebMCP Relay Widget</title>
6
+ </head>
7
+ <body>
8
+ <script>(function(){let e=new Set([`127.0.0.1`,`localhost`,`::1`,`[::1]`]),t=9333;function n(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function r(t){return e.has(t)}function i(){return crypto.randomUUID()}function a(e){return String(e).replace(/[\r\n]/g,``)}function o(e,t){try{e.readyState===WebSocket.OPEN&&e.send(t)}catch(e){console.warn(`[webmcp-relay] Failed to send message:`,e)}}function s(e){return`__webmcp_relay_endpoint:${[e.hostOrigin,e.relayId??``,e.workspace??``].map(e=>encodeURIComponent(e)).join(`:`)}`}let c=[1e4,2e4,3e4];function l(e=window.location.search){let n=new URLSearchParams(e),a=globalThis.__WEBMCP_RELAY_CONFIG;function o(e){return n.get(e)??a?.[e]??null}let s=o(`hostOrigin`);if(!s)return null;let c=o(`hostUrl`)||s,l=o(`hostTitle`)||``,u=o(`tabId`)||i(),d=o(`relayHost`)||`127.0.0.1`,f=o(`relayPort`),p=f&&f.length>0?Number(f):t,m=o(`autoConnect`)!==`false`,h=o(`relayId`)||void 0,g=o(`relayWorkspace`)||void 0,_=o(`requestTimeout`),v=_&&_.length>0?Number(_):6e4;return r(d)?!Number.isInteger(p)||p<1||p>65535?(console.error(`[webmcp-relay-widget] relayPort must be an integer between 1 and 65535, got:`,f),null):!Number.isInteger(v)||v<1?(console.error(`[webmcp-relay-widget] requestTimeout must be a positive integer (ms), got:`,_),null):{autoConnect:m,hostOrigin:s,hostTitle:l,hostUrl:c,relayHostHint:d,relayPortHint:p,...h?{relayId:h}:{},...g?{relayWorkspace:g}:{},requestTimeoutMs:v,tabId:u}:(console.error(`[webmcp-relay-widget] relayHost must be a loopback address, got:`,d),null)}function u(e){return!n(e)||typeof e.requestId!=`string`||typeof e.type!=`string`?null:{requestId:e.requestId,type:e.type,tools:e.tools,result:e.result,error:e.error}}function d(){let e=l();if(!e){console.warn(`[webmcp-relay-widget] Missing required hostOrigin parameter. Widget will not start.`);return}b(e)}function f(e){return!n(e)||e.type!==`server-hello`||e.service!==`webmcp-local-relay`||e.version!==1||typeof e.host!=`string`||typeof e.instanceId!=`string`||typeof e.port!=`number`?null:{type:`server-hello`,service:`webmcp-local-relay`,version:1,host:e.host,instanceId:e.instanceId,port:e.port,...typeof e.label==`string`?{label:e.label}:{},...typeof e.relayId==`string`?{relayId:e.relayId}:{},...typeof e.workspace==`string`?{workspace:e.workspace}:{}}}function p(e){return!n(e)||e.type!==`hello/rejected`||typeof e.message!=`string`||typeof e.reason!=`string`?null:{type:`hello/rejected`,message:e.message,reason:e.reason}}function m(e){return s({hostOrigin:e.hostOrigin,...e.relayId?{relayId:e.relayId}:{},...e.relayWorkspace?{workspace:e.relayWorkspace}:{}})}function h(e){if(typeof sessionStorage>`u`)return null;try{let t=sessionStorage.getItem(m(e));if(!t)return null;let n=JSON.parse(t);return typeof n.host!=`string`||n.host.length===0||typeof n.port!=`number`||!Number.isInteger(n.port)||n.port<1||n.port>65535?null:{host:n.host,port:n.port}}catch{return null}}function g(e,t){if(!(typeof sessionStorage>`u`))try{sessionStorage.setItem(m(e),JSON.stringify({host:t.host,port:t.port}))}catch{}}function _(e){if(!(typeof sessionStorage>`u`))try{sessionStorage.removeItem(m(e))}catch{}}function v(e){let n=h(e),r=new Set,i=[],a=(e,t)=>{if(!Number.isInteger(t)||t<1||t>65535)return;let n=`${e}:${String(t)}`;r.has(n)||(r.add(n),i.push({host:e,port:t}))};e.relayPortHint!==void 0&&a(e.relayHostHint,e.relayPortHint),n&&a(n.host,n.port);for(let e of[`127.0.0.1`,`[::1]`])for(let n=t;n<=9348;n+=1)a(e,n);return i}async function y(e){let t=`ws://${e.host.includes(`:`)&&!e.host.startsWith(`[`)?`[${e.host}]`:e.host}:${String(e.port)}`;return new Promise(n=>{let r=!1,i=new WebSocket(t,[`webmcp-discovery.v1`,`webmcp.v1`]),a=e=>{if(!r){if(r=!0,clearTimeout(l),i.removeEventListener(`close`,s),i.removeEventListener(`error`,o),i.removeEventListener(`message`,c),e===null)try{i.close()}catch{}n(e)}},o=()=>{a(null)},s=()=>{a(null)},c=t=>{let n;try{n=JSON.parse(String(t.data))}catch{return}let r=f(n);r&&a({endpoint:{hello:r,host:e.host,port:e.port},socket:i})},l=setTimeout(()=>{a(null)},1200);i.addEventListener(`close`,s,{once:!0}),i.addEventListener(`error`,o,{once:!0}),i.addEventListener(`message`,c)})}function b(e){let t=new Map,r=null,s=null,l=!1,d=null,m=null,b=`idle`,x=0,S=null,C=e=>{for(let[n,r]of t)clearTimeout(r.timeoutId),t.delete(n),r.reject(Error(e))};function w(n,r){let a=i();return new Promise((i,o)=>{let s=setTimeout(()=>{t.delete(a),o(Error(`Host response timeout: ${n}`))},e.requestTimeoutMs);t.set(a,{resolve:i,reject:o,timeoutId:s,responseType:`${n}.response`,errorType:`${n}.error`}),window.parent.postMessage({type:`${n}.request`,requestId:a,...r},e.hostOrigin)})}let T=(t,i)=>{let c=[],u=()=>{d&&(clearTimeout(d),d=null)},h=()=>{o(t,JSON.stringify({type:`tools/list`,tools:c}))};m&&(clearTimeout(m),m=null),r=i,s=t,x=0,l=!1,b=`idle`,t.addEventListener(`message`,s=>{let c;try{c=JSON.parse(String(s.data))}catch(e){console.warn(`[webmcp-relay-widget] Failed to parse relay message:`,e);return}let d=f(c);if(d){r={hello:d,host:i.host,port:i.port};return}if(n(c)&&c.type===`hello/accepted`){u(),l=!0,g(e,i),h();return}let m=p(c);if(m){u(),l=!1,_(e),window.parent.postMessage({type:`webmcp.relay.rejected`,host:i.host,port:i.port,message:m.message,reason:m.reason},e.hostOrigin),console.error(`[webmcp-relay-widget] Relay rejected browser hello:`,m.reason,m.message);try{t.close(1008,m.message)}catch{}return}if(!n(c)||typeof c.type!=`string`)return;let v=c;if(v.type===`ping`){o(t,JSON.stringify({type:`pong`}));return}if(v.type===`reload`){window.parent.postMessage({type:`webmcp.reload`},e.hostOrigin);return}if(v.type!==`invoke`){console.debug(`[webmcp-relay-widget] Ignoring unrecognized message type:`,a(v.type));return}w(`webmcp.tools.invoke`,{toolName:v.toolName,args:n(v.args)?v.args:{}}).then(e=>{o(t,JSON.stringify({type:`result`,callId:v.callId,result:e.result}))}).catch(e=>{o(t,JSON.stringify({type:`result`,callId:v.callId,result:{isError:!0,content:[{type:`text`,text:String(e instanceof Error?e.message:e)}]}}))})}),t.addEventListener(`close`,()=>{s===t&&(l=!1,s=null,u(),C(`WebSocket connection lost`),O())},{once:!0}),t.addEventListener(`error`,e=>{console.warn(`[webmcp-relay-widget] WebSocket error:`,e);try{t.close()}catch(e){console.warn(`[webmcp-relay-widget] Error closing socket after error:`,e)}}),w(`webmcp.tools.list`,{}).then(n=>{c=Array.isArray(n.tools)?n.tools:[],o(t,JSON.stringify({type:`hello`,tabId:e.tabId,origin:e.hostOrigin,title:e.hostTitle||document.referrer||`Unknown page`,url:e.hostUrl})),d=setTimeout(()=>{d=null,!(s!==t||t.readyState!==WebSocket.OPEN||l)&&(console.warn(`[webmcp-relay-widget] Relay did not acknowledge browser hello`),t.close(4e3,`Browser hello was not acknowledged`))},1e3)}).catch(e=>{console.warn(`[webmcp-relay-widget] Hello handshake failed:`,e);try{t.close()}catch{}})},E=async t=>{let n=await y({host:t.host,port:t.port});if(!n)return!1;let r=n.endpoint;return e.relayId&&r.hello.relayId!==e.relayId||e.relayWorkspace&&r.hello.workspace!==e.relayWorkspace?(n.socket.close(),!1):(T(n.socket,r),!0)},D=async()=>{b=`discovering`;try{for(let t of v(e))if(await E(t))return!0;return!1}finally{b===`discovering`&&(b=`idle`)}},O=()=>{if(!r||m)return;let e={host:r.host,port:r.port},t=Math.round(500*(.85+Math.random()*.3));m=setTimeout(()=>{m=null,E(e).then(e=>{e||k()})},t)},k=()=>{if(m)return;let e=c[x];if(e===void 0){M();return}m=setTimeout(()=>{m=null,D().then(e=>{e||(x+=1,k())})},e)},A=()=>{document.visibilityState===`visible`&&b===`dormant`&&P()},j=()=>{document.removeEventListener(`visibilitychange`,A),S!==null&&(clearInterval(S),S=null)},M=()=>{b!==`dormant`&&(b=`dormant`,m&&(clearTimeout(m),m=null),document.addEventListener(`visibilitychange`,A),S=setInterval(()=>{N()},12e4))},N=async()=>{if(b!==`dormant`)return;let t=new Set,n=[],r=(e,r)=>{let i=`${e}:${String(r)}`;t.has(i)||(t.add(i),n.push({host:e,port:r}))};e.relayPortHint!==void 0&&r(e.relayHostHint,e.relayPortHint);let i=h(e);if(i&&r(i.host,i.port),n.length!==0){b=`discovering`,j();for(let e of n)if(await E(e)){x=0;return}M()}},P=()=>{j(),x=0,D().then(e=>{e||M()})};window.addEventListener(`message`,r=>{if(r.source!==window.parent||r.origin!==e.hostOrigin)return;let i=r.data;if(n(i)&&i.type===`webmcp.tools.changed`){s&&l&&o(s,JSON.stringify({type:`tools/changed`,tools:Array.isArray(i.tools)?i.tools:[]}));return}if(n(i)&&i.type===`webmcp.connect`){b===`dormant`?P():!s&&b!==`discovering`&&D();return}let a=u(i);if(!a)return;let c=t.get(a.requestId);if(c){if(a.type===c.responseType){clearTimeout(c.timeoutId),t.delete(a.requestId),c.resolve(a);return}a.type===c.errorType&&(clearTimeout(c.timeoutId),t.delete(a.requestId),c.reject(Error(String(a.error||`Unknown host error`))))}}),e.autoConnect&&D().then(e=>{e||k()})}d()})();</script>
9
+ </body>
10
+ </html>
@@ -0,0 +1 @@
1
+ (function(){let e=new Set([`127.0.0.1`,`localhost`,`::1`,`[::1]`]),t=9333;function n(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function r(t){return e.has(t)}function i(){return crypto.randomUUID()}function a(e){return String(e).replace(/[\r\n]/g,``)}function o(e,t){try{e.readyState===WebSocket.OPEN&&e.send(t)}catch(e){console.warn(`[webmcp-relay] Failed to send message:`,e)}}function s(e){return`__webmcp_relay_endpoint:${[e.hostOrigin,e.relayId??``,e.workspace??``].map(e=>encodeURIComponent(e)).join(`:`)}`}let c=[1e4,2e4,3e4];function l(e=window.location.search){let n=new URLSearchParams(e),a=globalThis.__WEBMCP_RELAY_CONFIG;function o(e){return n.get(e)??a?.[e]??null}let s=o(`hostOrigin`);if(!s)return null;let c=o(`hostUrl`)||s,l=o(`hostTitle`)||``,u=o(`tabId`)||i(),d=o(`relayHost`)||`127.0.0.1`,f=o(`relayPort`),p=f&&f.length>0?Number(f):t,m=o(`autoConnect`)!==`false`,h=o(`relayId`)||void 0,g=o(`relayWorkspace`)||void 0,_=o(`requestTimeout`),v=_&&_.length>0?Number(_):6e4;return r(d)?!Number.isInteger(p)||p<1||p>65535?(console.error(`[webmcp-relay-widget] relayPort must be an integer between 1 and 65535, got:`,f),null):!Number.isInteger(v)||v<1?(console.error(`[webmcp-relay-widget] requestTimeout must be a positive integer (ms), got:`,_),null):{autoConnect:m,hostOrigin:s,hostTitle:l,hostUrl:c,relayHostHint:d,relayPortHint:p,...h?{relayId:h}:{},...g?{relayWorkspace:g}:{},requestTimeoutMs:v,tabId:u}:(console.error(`[webmcp-relay-widget] relayHost must be a loopback address, got:`,d),null)}function u(e){return!n(e)||typeof e.requestId!=`string`||typeof e.type!=`string`?null:{requestId:e.requestId,type:e.type,tools:e.tools,result:e.result,error:e.error}}function d(){let e=l();if(!e){console.warn(`[webmcp-relay-widget] Missing required hostOrigin parameter. Widget will not start.`);return}b(e)}function f(e){return!n(e)||e.type!==`server-hello`||e.service!==`webmcp-local-relay`||e.version!==1||typeof e.host!=`string`||typeof e.instanceId!=`string`||typeof e.port!=`number`?null:{type:`server-hello`,service:`webmcp-local-relay`,version:1,host:e.host,instanceId:e.instanceId,port:e.port,...typeof e.label==`string`?{label:e.label}:{},...typeof e.relayId==`string`?{relayId:e.relayId}:{},...typeof e.workspace==`string`?{workspace:e.workspace}:{}}}function p(e){return!n(e)||e.type!==`hello/rejected`||typeof e.message!=`string`||typeof e.reason!=`string`?null:{type:`hello/rejected`,message:e.message,reason:e.reason}}function m(e){return s({hostOrigin:e.hostOrigin,...e.relayId?{relayId:e.relayId}:{},...e.relayWorkspace?{workspace:e.relayWorkspace}:{}})}function h(e){if(typeof sessionStorage>`u`)return null;try{let t=sessionStorage.getItem(m(e));if(!t)return null;let n=JSON.parse(t);return typeof n.host!=`string`||n.host.length===0||typeof n.port!=`number`||!Number.isInteger(n.port)||n.port<1||n.port>65535?null:{host:n.host,port:n.port}}catch{return null}}function g(e,t){if(!(typeof sessionStorage>`u`))try{sessionStorage.setItem(m(e),JSON.stringify({host:t.host,port:t.port}))}catch{}}function _(e){if(!(typeof sessionStorage>`u`))try{sessionStorage.removeItem(m(e))}catch{}}function v(e){let n=h(e),r=new Set,i=[],a=(e,t)=>{if(!Number.isInteger(t)||t<1||t>65535)return;let n=`${e}:${String(t)}`;r.has(n)||(r.add(n),i.push({host:e,port:t}))};e.relayPortHint!==void 0&&a(e.relayHostHint,e.relayPortHint),n&&a(n.host,n.port);for(let e of[`127.0.0.1`,`[::1]`])for(let n=t;n<=9348;n+=1)a(e,n);return i}async function y(e){let t=`ws://${e.host.includes(`:`)&&!e.host.startsWith(`[`)?`[${e.host}]`:e.host}:${String(e.port)}`;return new Promise(n=>{let r=!1,i=new WebSocket(t,[`webmcp-discovery.v1`,`webmcp.v1`]),a=e=>{if(!r){if(r=!0,clearTimeout(l),i.removeEventListener(`close`,s),i.removeEventListener(`error`,o),i.removeEventListener(`message`,c),e===null)try{i.close()}catch{}n(e)}},o=()=>{a(null)},s=()=>{a(null)},c=t=>{let n;try{n=JSON.parse(String(t.data))}catch{return}let r=f(n);r&&a({endpoint:{hello:r,host:e.host,port:e.port},socket:i})},l=setTimeout(()=>{a(null)},1200);i.addEventListener(`close`,s,{once:!0}),i.addEventListener(`error`,o,{once:!0}),i.addEventListener(`message`,c)})}function b(e){let t=new Map,r=null,s=null,l=!1,d=null,m=null,b=`idle`,x=0,S=null,C=e=>{for(let[n,r]of t)clearTimeout(r.timeoutId),t.delete(n),r.reject(Error(e))};function w(n,r){let a=i();return new Promise((i,o)=>{let s=setTimeout(()=>{t.delete(a),o(Error(`Host response timeout: ${n}`))},e.requestTimeoutMs);t.set(a,{resolve:i,reject:o,timeoutId:s,responseType:`${n}.response`,errorType:`${n}.error`}),window.parent.postMessage({type:`${n}.request`,requestId:a,...r},e.hostOrigin)})}let T=(t,i)=>{let c=[],u=()=>{d&&(clearTimeout(d),d=null)},h=()=>{o(t,JSON.stringify({type:`tools/list`,tools:c}))};m&&(clearTimeout(m),m=null),r=i,s=t,x=0,l=!1,b=`idle`,t.addEventListener(`message`,s=>{let c;try{c=JSON.parse(String(s.data))}catch(e){console.warn(`[webmcp-relay-widget] Failed to parse relay message:`,e);return}let d=f(c);if(d){r={hello:d,host:i.host,port:i.port};return}if(n(c)&&c.type===`hello/accepted`){u(),l=!0,g(e,i),h();return}let m=p(c);if(m){u(),l=!1,_(e),window.parent.postMessage({type:`webmcp.relay.rejected`,host:i.host,port:i.port,message:m.message,reason:m.reason},e.hostOrigin),console.error(`[webmcp-relay-widget] Relay rejected browser hello:`,m.reason,m.message);try{t.close(1008,m.message)}catch{}return}if(!n(c)||typeof c.type!=`string`)return;let v=c;if(v.type===`ping`){o(t,JSON.stringify({type:`pong`}));return}if(v.type===`reload`){window.parent.postMessage({type:`webmcp.reload`},e.hostOrigin);return}if(v.type!==`invoke`){console.debug(`[webmcp-relay-widget] Ignoring unrecognized message type:`,a(v.type));return}w(`webmcp.tools.invoke`,{toolName:v.toolName,args:n(v.args)?v.args:{}}).then(e=>{o(t,JSON.stringify({type:`result`,callId:v.callId,result:e.result}))}).catch(e=>{o(t,JSON.stringify({type:`result`,callId:v.callId,result:{isError:!0,content:[{type:`text`,text:String(e instanceof Error?e.message:e)}]}}))})}),t.addEventListener(`close`,()=>{s===t&&(l=!1,s=null,u(),C(`WebSocket connection lost`),O())},{once:!0}),t.addEventListener(`error`,e=>{console.warn(`[webmcp-relay-widget] WebSocket error:`,e);try{t.close()}catch(e){console.warn(`[webmcp-relay-widget] Error closing socket after error:`,e)}}),w(`webmcp.tools.list`,{}).then(n=>{c=Array.isArray(n.tools)?n.tools:[],o(t,JSON.stringify({type:`hello`,tabId:e.tabId,origin:e.hostOrigin,title:e.hostTitle||document.referrer||`Unknown page`,url:e.hostUrl})),d=setTimeout(()=>{d=null,!(s!==t||t.readyState!==WebSocket.OPEN||l)&&(console.warn(`[webmcp-relay-widget] Relay did not acknowledge browser hello`),t.close(4e3,`Browser hello was not acknowledged`))},1e3)}).catch(e=>{console.warn(`[webmcp-relay-widget] Hello handshake failed:`,e);try{t.close()}catch{}})},E=async t=>{let n=await y({host:t.host,port:t.port});if(!n)return!1;let r=n.endpoint;return e.relayId&&r.hello.relayId!==e.relayId||e.relayWorkspace&&r.hello.workspace!==e.relayWorkspace?(n.socket.close(),!1):(T(n.socket,r),!0)},D=async()=>{b=`discovering`;try{for(let t of v(e))if(await E(t))return!0;return!1}finally{b===`discovering`&&(b=`idle`)}},O=()=>{if(!r||m)return;let e={host:r.host,port:r.port},t=Math.round(500*(.85+Math.random()*.3));m=setTimeout(()=>{m=null,E(e).then(e=>{e||k()})},t)},k=()=>{if(m)return;let e=c[x];if(e===void 0){M();return}m=setTimeout(()=>{m=null,D().then(e=>{e||(x+=1,k())})},e)},A=()=>{document.visibilityState===`visible`&&b===`dormant`&&P()},j=()=>{document.removeEventListener(`visibilitychange`,A),S!==null&&(clearInterval(S),S=null)},M=()=>{b!==`dormant`&&(b=`dormant`,m&&(clearTimeout(m),m=null),document.addEventListener(`visibilitychange`,A),S=setInterval(()=>{N()},12e4))},N=async()=>{if(b!==`dormant`)return;let t=new Set,n=[],r=(e,r)=>{let i=`${e}:${String(r)}`;t.has(i)||(t.add(i),n.push({host:e,port:r}))};e.relayPortHint!==void 0&&r(e.relayHostHint,e.relayPortHint);let i=h(e);if(i&&r(i.host,i.port),n.length!==0){b=`discovering`,j();for(let e of n)if(await E(e)){x=0;return}M()}},P=()=>{j(),x=0,D().then(e=>{e||M()})};window.addEventListener(`message`,r=>{if(r.source!==window.parent||r.origin!==e.hostOrigin)return;let i=r.data;if(n(i)&&i.type===`webmcp.tools.changed`){s&&l&&o(s,JSON.stringify({type:`tools/changed`,tools:Array.isArray(i.tools)?i.tools:[]}));return}if(n(i)&&i.type===`webmcp.connect`){b===`dormant`?P():!s&&b!==`discovering`&&D();return}let a=u(i);if(!a)return;let c=t.get(a.requestId);if(c){if(a.type===c.responseType){clearTimeout(c.timeoutId),t.delete(a.requestId),c.resolve(a);return}a.type===c.errorType&&(clearTimeout(c.timeoutId),t.delete(a.requestId),c.reject(Error(String(a.error||`Unknown host error`))))}}),e.autoConnect&&D().then(e=>{e||k()})}d()})();
@@ -49,7 +49,9 @@ const stripLikeC4Comments = (content: string) => content.replace(/\/\*[\s\S]*?\*
49
49
  const parseLikeC4Views = (content: string, filePath: string): LikeC4View[] => {
50
50
  const contentWithoutComments = stripLikeC4Comments(content);
51
51
  const viewDeclarationPattern =
52
- /\b(?:(dynamic|deployment)\s+)?view(?:\s+([A-Za-z_][\w.-]*))?(?:\s+of\s+[A-Za-z_][\w.-]*(?:\.[A-Za-z_][\w.-]*)*)?\s*\{/g;
52
+ // `of` names an element, dotted or not (`[\w.-]*` takes the dots: a separate group for each dotted part made the
53
+ // pattern backtrack heavily on a long dotted name without its `{`)
54
+ /\b(?:(dynamic|deployment)\s+)?view(?:\s+([A-Za-z_][\w.-]*))?(?:\s+of\s+[A-Za-z_][\w.-]*)?\s*\{/g;
53
55
  const views: LikeC4View[] = [];
54
56
  let match: RegExpExecArray | null;
55
57
 
@@ -6,12 +6,12 @@ import NavigationProgress from '../components/NavigationProgress.astro';
6
6
  import config from '@config';
7
7
 
8
8
  interface Props {
9
- title: string;
9
+ /** The page's own title; the catalog's title follows it (the homepage has none) */
10
+ title?: string;
10
11
  description?: string;
11
- ogTitle?: string;
12
12
  }
13
13
 
14
- const { title, description, ogTitle } = Astro.props;
14
+ const { title, description } = Astro.props;
15
15
  const catalogTheme = config.theme || 'default';
16
16
  ---
17
17
 
@@ -50,7 +50,7 @@ const catalogTheme = config.theme || 'default';
50
50
  document.addEventListener('astro:page-load', applyTheme);
51
51
  })();
52
52
  </script>
53
- <SEO title={title} description={description} ogTitle={ogTitle} />
53
+ <SEO title={title} description={description} />
54
54
  <AnalyticsHead />
55
55
  <slot name="head" />
56
56
  </head>
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  import VerticalSideBarLayout from './VerticalSideBarLayout.astro';
3
3
  import { buildUrl } from '@utils/url-builder';
4
- import { Settings, Server, Bot, FileText, BadgeCheck } from 'lucide-react';
4
+ import { Settings, Server, Bot, ScanText, BadgeCheck } from 'lucide-react';
5
5
 
6
6
  export type SettingsSection = 'general' | 'mcp' | 'assistant' | 'llm-access' | 'license';
7
7
 
@@ -55,7 +55,7 @@ const groups: SectionGroup[] = [
55
55
  id: 'llm-access',
56
56
  label: 'LLM Access',
57
57
  href: buildUrl('/settings/llm-access'),
58
- icon: FileText,
58
+ icon: ScanText,
59
59
  },
60
60
  ],
61
61
  },
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  interface Props {
3
- title: string;
3
+ /** The page's own title; the catalog's title follows it (the homepage has none) */
4
+ title?: string;
4
5
  sidebar?: boolean;
5
6
  description?: string;
6
7
  showNestedSideBar?: boolean;
@@ -430,7 +431,7 @@ const { title, description, showNestedSideBar = true, showHeader = true, reduced
430
431
  const verticalNavAutoCollapsePaths = [buildUrl('/discover', true), buildUrl('/docs', true)];
431
432
  ---
432
433
 
433
- <BaseLayout title={`EventCatalog | ${title}`} description={description} ogTitle={title}>
434
+ <BaseLayout title={title} description={description}>
434
435
  <Fragment slot="head">
435
436
  <script is:inline define:vars={{ verticalNavAutoCollapsePaths }}>
436
437
  (() => {
@@ -1,358 +1,21 @@
1
1
  ---
2
- import { buildUrl } from '@utils/url-builder';
3
- import config from '@config';
4
-
5
- import { getCollection } from 'astro:content';
6
2
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
7
- import { BookOpenText, Workflow, TableProperties, BookUser, Code2, FileJson, ArrowUpRight, ArrowRight, Plus } from 'lucide-react';
3
+ import CatalogDashboard from '@components/Homepage/CatalogDashboard.astro';
8
4
 
9
5
  const { showNestedSideBar = true } = Astro.props;
10
-
11
- // Lightweight data fetch: only raw collections, no hydration.
12
- const [allDomains, allServices, allEvents, allCommands, allQueries, allFlows] = await Promise.all([
13
- getCollection('domains'),
14
- getCollection('services'),
15
- getCollection('events'),
16
- getCollection('commands'),
17
- getCollection('queries'),
18
- getCollection('flows'),
19
- ]);
20
-
21
- const isCurrentVersion = (item: { data: { hidden?: boolean }; filePath?: string }) =>
22
- item.data.hidden !== true && !item.filePath?.includes('versioned');
23
-
24
- const domains = allDomains.filter(isCurrentVersion);
25
- const services = allServices.filter(isCurrentVersion);
26
- const events = allEvents.filter(isCurrentVersion);
27
- const commands = allCommands.filter(isCurrentVersion);
28
- const queries = allQueries.filter(isCurrentVersion);
29
- const messages = [...events, ...commands, ...queries];
30
- const flows = allFlows.filter(isCurrentVersion);
31
-
32
- const getDefaultUrl = (route: string, defaultValue: string) => {
33
- if (domains.length > 0) return buildUrl(`/${route}/domains/${domains[0].data.id}/${domains[0].data.version}`);
34
- if (services.length > 0) return buildUrl(`/${route}/services/${services[0].data.id}/${services[0].data.version}`);
35
- if (flows.length > 0) return buildUrl(`/${route}/flows/${flows[0].data.id}/${flows[0].data.version}`);
36
- return buildUrl(defaultValue);
37
- };
38
-
39
- interface StatTile {
40
- label: string;
41
- count: number;
42
- href: string;
43
- emptyHref: string;
44
- tone: string; // CSS color expression — drives accent rail + count gradient
45
- }
46
-
47
- const statTiles: StatTile[] = [
48
- {
49
- label: 'Domains',
50
- count: domains.length,
51
- href: buildUrl('/discover/domains'),
52
- emptyHref: 'https://www.eventcatalog.dev/docs/domains',
53
- tone: '250 204 21', // amber-400
54
- },
55
- {
56
- label: 'Services',
57
- count: services.length,
58
- href: buildUrl('/discover/services'),
59
- emptyHref: 'https://www.eventcatalog.dev/docs/services',
60
- tone: '244 114 182', // pink-400
61
- },
62
- {
63
- label: 'Messages',
64
- count: messages.length,
65
- href: buildUrl('/discover/events'),
66
- emptyHref: 'https://www.eventcatalog.dev/docs/messages',
67
- tone: '167 139 250', // violet-400
68
- },
69
- {
70
- label: 'Flows',
71
- count: flows.length,
72
- href: buildUrl('/discover/flows'),
73
- emptyHref: 'https://www.eventcatalog.dev/docs/flows',
74
- tone: '94 234 212', // teal-300
75
- },
76
- ];
77
-
78
- interface ExploreCard {
79
- title: string;
80
- description: string;
81
- icon: any;
82
- href: string;
83
- external?: boolean;
84
- /** When true, renders as the lead "feature" card with extra width and CTA styling. */
85
- feature?: boolean;
86
- tone: string; // RGB triple for the icon tile
87
- }
88
-
89
- const exploreCards: ExploreCard[] = [
90
- {
91
- title: 'Documentation',
92
- description: 'Browse every domain, service, message, and flow your teams have published.',
93
- icon: BookOpenText,
94
- href: getDefaultUrl('docs', 'domains'),
95
- feature: true,
96
- tone: '96 165 250', // blue-400
97
- },
98
- {
99
- title: 'Visualizer',
100
- description: 'See how services connect — message flows across your architecture.',
101
- icon: Workflow,
102
- href: getDefaultUrl('visualiser', 'domains'),
103
- tone: '167 139 250', // violet-400
104
- },
105
- {
106
- title: 'Discover',
107
- description: 'Search every event, service, agent, and team across the catalog.',
108
- icon: TableProperties,
109
- href: buildUrl('/discover/events'),
110
- tone: '94 234 212', // teal-300
111
- },
112
- {
113
- title: 'Schema Explorer',
114
- description: 'Track schema evolution, compare versions, and catch breaking changes.',
115
- icon: FileJson,
116
- href: buildUrl('/schemas/explorer'),
117
- tone: '250 204 21', // amber-400
118
- },
119
- {
120
- title: 'Team Directory',
121
- description: 'Find owners, on-call contacts, and the team behind every service.',
122
- icon: BookUser,
123
- href: buildUrl('/directory/users'),
124
- tone: '251 146 60', // orange-400
125
- },
126
- {
127
- title: 'API & SDK',
128
- description: 'Programmatic access — query and manage your catalog with a typed SDK.',
129
- icon: Code2,
130
- href: 'https://www.eventcatalog.dev/docs/sdk',
131
- external: true,
132
- tone: '129 140 248', // indigo-400
133
- },
134
- ];
135
6
  ---
136
7
 
137
- <VerticalSideBarLayout title="EventCatalog" showNestedSideBar={showNestedSideBar}>
138
- <div class="ec-home min-h-screen">
139
- <!-- Hero -->
140
- <header class="ec-hero">
141
- <div class="text-[11px] font-semibold uppercase tracking-[0.18em] text-[rgb(var(--ec-accent))]">Catalog</div>
142
- <div class="mt-3 flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
143
- <div>
144
- <h1 class="text-[28px] font-semibold leading-[1.1] tracking-tight text-[rgb(var(--ec-page-text))] md:text-[32px]">
145
- {config?.organizationName || 'EventCatalog'}
146
- </h1>
147
- <p class="mt-2 max-w-2xl text-[14px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]">
148
- {config.tagline || 'Explore and understand your event-driven architecture.'}
149
- </p>
150
- </div>
151
- <div class="flex items-center gap-2">
152
- <a
153
- href={getDefaultUrl('docs', 'domains')}
154
- class="ec-btn-primary inline-flex items-center gap-1.5 rounded-md bg-[rgb(var(--ec-page-bg))] border border-[rgb(var(--ec-page-border))] px-3.5 py-2 text-[12.5px] font-semibold text-[rgb(var(--ec-page-text-muted))] transition-colors hover:border-[rgb(var(--ec-accent)/0.5)] hover:text-[rgb(var(--ec-accent))]"
155
- >
156
- Explore Catalog
157
- <ArrowRight className="h-3.5 w-3.5" />
158
- </a>
159
- </div>
160
- </div>
161
- </header>
162
-
163
- <div class="ec-divider"></div>
164
-
165
- <!-- Stat strip -->
166
- <section class="ec-stats">
167
- {
168
- statTiles.map((tile) => (
169
- <a
170
- href={tile.count > 0 ? tile.href : tile.emptyHref}
171
- target={tile.count === 0 ? '_blank' : undefined}
172
- rel={tile.count === 0 ? 'noreferrer' : undefined}
173
- class="ec-stat group"
174
- style={`--tone: ${tile.tone};`}
175
- >
176
- <div class="flex items-baseline justify-between gap-2">
177
- <span class="text-[11px] font-medium uppercase tracking-[0.14em] text-[rgb(var(--tone))]">{tile.label}</span>
178
- {tile.count > 0 ? (
179
- <ArrowUpRight className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))] transition-transform duration-200 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-[rgb(var(--ec-accent))]" />
180
- ) : (
181
- <Plus className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))] transition-colors group-hover:text-[rgb(var(--ec-accent))]" />
182
- )}
183
- </div>
184
- <div class="mt-3 flex items-baseline gap-2">
185
- <span class="font-mono text-[34px] font-semibold leading-none tracking-tight text-[rgb(var(--ec-page-text))]">
186
- {tile.count}
187
- </span>
188
- {tile.count === 0 && <span class="text-[12px] text-[rgb(var(--ec-page-text-muted))]">— add some</span>}
189
- </div>
190
- </a>
191
- ))
192
- }
193
- </section>
194
-
195
- <!-- Eyebrow + Explore grid -->
196
- <section class="mt-12">
197
- <div class="ec-section-eyebrow">
198
- <span class="text-[11px] font-semibold uppercase tracking-[0.18em] text-[rgb(var(--ec-accent))]">Explore</span>
199
- <span class="ec-section-rule"></span>
200
- <span class="font-mono text-[11px] text-[rgb(var(--ec-page-text-muted)/0.7)]">{exploreCards.length} sections</span>
201
- </div>
202
-
203
- <div class="ec-explore-grid mt-4">
204
- {
205
- exploreCards.map((card) => (
206
- <a
207
- href={card.href}
208
- target={card.external ? '_blank' : undefined}
209
- rel={card.external ? 'noreferrer' : undefined}
210
- class:list={['ec-card group', card.feature ? 'ec-card--feature' : '']}
211
- style={`--tone: ${card.tone};`}
212
- >
213
- <div class="flex items-start justify-between gap-3">
214
- <div class="ec-card-icon">
215
- <card.icon className="h-4 w-4" />
216
- </div>
217
- <ArrowUpRight className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))] transition-transform duration-200 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-[rgb(var(--ec-accent))]" />
218
- </div>
219
- <h3 class="mt-4 text-[15px] font-semibold tracking-tight text-[rgb(var(--ec-page-text))]">{card.title}</h3>
220
- <p class="mt-1.5 text-[13px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]">{card.description}</p>
221
- </a>
222
- ))
223
- }
224
- </div>
225
- </section>
8
+ <VerticalSideBarLayout showNestedSideBar={showNestedSideBar}>
9
+ <div class="ec-home">
10
+ <CatalogDashboard />
226
11
  </div>
227
12
  </VerticalSideBarLayout>
228
13
 
229
14
  <style is:global>
230
15
  .ec-home {
231
- /* Negate the layout wrapper's horizontal padding so the homepage controls its own. */
16
+ /* The layout pads its content: the homepage sets its own, wider spacing */
232
17
  margin-left: calc(var(--ec-app-content-padding-left, 5rem) * -1);
233
18
  margin-right: calc(var(--ec-app-content-padding-right, 5rem) * -1);
234
19
  padding: 2rem 2rem 0;
235
20
  }
236
- .ec-hero {
237
- padding-bottom: 1.5rem;
238
- }
239
- .ec-divider {
240
- height: 1px;
241
- background: linear-gradient(
242
- to right,
243
- transparent,
244
- rgb(var(--ec-page-border)) 12%,
245
- rgb(var(--ec-page-border)) 88%,
246
- transparent
247
- );
248
- margin: 0.25rem 0 1.5rem;
249
- }
250
- .ec-stats {
251
- display: grid;
252
- grid-template-columns: repeat(2, minmax(0, 1fr));
253
- gap: 0.75rem;
254
- }
255
- @media (min-width: 768px) {
256
- .ec-stats {
257
- grid-template-columns: repeat(4, minmax(0, 1fr));
258
- }
259
- }
260
- .ec-stat {
261
- position: relative;
262
- display: flex;
263
- flex-direction: column;
264
- overflow: hidden;
265
- border: 1px solid rgb(var(--ec-page-border));
266
- border-radius: 0.75rem;
267
- background:
268
- radial-gradient(80% 100% at 0% 0%, rgb(var(--tone) / 0.05), transparent 60%), rgb(var(--ec-card-bg, var(--ec-page-bg)));
269
- padding: 1rem 1.1rem 1.1rem;
270
- transition:
271
- border-color 200ms,
272
- transform 200ms,
273
- box-shadow 200ms;
274
- text-decoration: none;
275
- }
276
- .ec-stat:hover {
277
- border-color: rgb(var(--ec-accent) / 0.5);
278
- transform: translateY(-1px);
279
- }
280
-
281
- .ec-section-eyebrow {
282
- display: flex;
283
- align-items: center;
284
- gap: 0.75rem;
285
- }
286
- .ec-section-rule {
287
- flex: 1;
288
- height: 1px;
289
- background: linear-gradient(to right, rgb(var(--ec-accent) / 0.4), rgb(var(--ec-page-border)) 30%);
290
- }
291
-
292
- /* Explore grid: bordered cells with breathing room between them. */
293
- .ec-explore-grid {
294
- display: grid;
295
- grid-template-columns: repeat(1, minmax(0, 1fr));
296
- gap: 1rem;
297
- }
298
- @media (min-width: 640px) {
299
- .ec-explore-grid {
300
- grid-template-columns: repeat(2, minmax(0, 1fr));
301
- }
302
- }
303
- @media (min-width: 1024px) {
304
- .ec-explore-grid {
305
- grid-template-columns: repeat(3, minmax(0, 1fr));
306
- }
307
- }
308
-
309
- .ec-card {
310
- position: relative;
311
- display: flex;
312
- flex-direction: column;
313
- padding: 1.5rem 1.5rem 1.4rem;
314
- text-decoration: none;
315
- border: 1px solid rgb(var(--ec-page-border));
316
- border-radius: 0.875rem;
317
- background: rgb(var(--ec-card-bg, var(--ec-page-bg)));
318
- transition:
319
- background 200ms,
320
- border-color 200ms;
321
- min-height: 9.5rem;
322
- }
323
- .ec-card:hover {
324
- background: rgb(var(--ec-page-bg) / 0.4);
325
- border-color: rgb(var(--ec-accent) / 0.5);
326
- }
327
-
328
- .ec-card--feature {
329
- background:
330
- radial-gradient(60% 90% at 0% 0%, rgb(var(--tone) / 0.07), transparent 60%), rgb(var(--ec-card-bg, var(--ec-page-bg)));
331
- }
332
- .ec-card--feature:hover {
333
- background: radial-gradient(60% 90% at 0% 0%, rgb(var(--ec-accent) / 0.12), transparent 60%), rgb(var(--ec-page-bg) / 0.4);
334
- }
335
-
336
- .ec-card-icon {
337
- display: inline-flex;
338
- height: 2.25rem;
339
- width: 2.25rem;
340
- align-items: center;
341
- justify-content: center;
342
- border-radius: 0.5rem;
343
- background: rgb(var(--tone) / 0.12);
344
- color: rgb(var(--tone));
345
- transition:
346
- background 200ms,
347
- color 200ms;
348
- }
349
- .ec-card:hover .ec-card-icon {
350
- background: rgb(var(--ec-accent) / 0.2);
351
- color: rgb(var(--ec-accent));
352
- }
353
- .ec-card--feature .ec-card-icon {
354
- height: 2.5rem;
355
- width: 2.5rem;
356
- border-radius: 0.625rem;
357
- }
358
21
  </style>
@@ -68,10 +68,9 @@ describe('architecture page redirects', () => {
68
68
  it('returns not found for resources without an architecture page', async () => {
69
69
  mocks.isSSR.mockReturnValue(true);
70
70
 
71
+ // Nothing found: the page answers with the 404 page
71
72
  await expect(
72
73
  Page.getData({ params: { type: 'events', id: 'order-created', version: '1.0.0' }, props: {} } as any)
73
- ).rejects.toMatchObject({
74
- status: 404,
75
- });
74
+ ).resolves.toBeUndefined();
76
75
  });
77
76
  });
@@ -61,11 +61,4 @@ export class Page extends HybridPage {
61
61
 
62
62
  return { type, data: { id, name: match.item.data.name, version }, redirectPath: match.redirectPath };
63
63
  }
64
-
65
- protected static createNotFoundResponse(): Response {
66
- return new Response(null, {
67
- status: 404,
68
- statusText: 'Documentation not found',
69
- });
70
- }
71
64
  }
@@ -9,7 +9,9 @@ import { Page } from './_index.data';
9
9
  export const prerender = Page.prerender;
10
10
  export const getStaticPaths = Page.getStaticPaths;
11
11
 
12
- const { data, redirectPath } = await Page.getData(Astro);
12
+ const pageData = await Page.getData(Astro);
13
+ if (!pageData) return Astro.rewrite('/404');
14
+ const { data, redirectPath } = pageData;
13
15
  const redirectUrl = buildUrl(redirectPath);
14
16
 
15
17
  if (isSSR()) {
@@ -47,11 +47,4 @@ export class Page extends HybridPage {
47
47
  allVersions,
48
48
  };
49
49
  }
50
-
51
- protected static createNotFoundResponse(): Response {
52
- return new Response(null, {
53
- status: 404,
54
- statusText: 'Diagram not found',
55
- });
56
- }
57
50
  }
@@ -10,6 +10,7 @@ export const prerender = Page.prerender;
10
10
  export const getStaticPaths = Page.getStaticPaths;
11
11
 
12
12
  const props = await Page.getData(Astro);
13
+ if (!props) return Astro.rewrite('/404');
13
14
  const { Content } = await render(props);
14
15
 
15
16
  const currentVersion = props.data.version;
@@ -15,6 +15,7 @@ export const prerender = Page.prerender;
15
15
  export const getStaticPaths = Page.getStaticPaths;
16
16
 
17
17
  const props = await Page.getData(Astro);
18
+ if (!props) return Astro.rewrite('/404');
18
19
  const { Content, headings } = await render(props);
19
20
 
20
21
  const pageTitle = `Diagram | ${props.data.name}`;
@@ -45,6 +45,11 @@ export class Page extends HybridPage {
45
45
  teams: getTeams,
46
46
  };
47
47
 
48
+ // An unknown type (e.g. a mistyped URL) has no directory page
49
+ if (!Object.hasOwn(loaders, type)) {
50
+ return null;
51
+ }
52
+
48
53
  // Get all items of the specified type
49
54
  const items = await loaders[type as keyof typeof loaders]();
50
55
 
@@ -53,11 +58,4 @@ export class Page extends HybridPage {
53
58
  data: items,
54
59
  };
55
60
  }
56
-
57
- protected static createNotFoundResponse(): Response {
58
- return new Response(null, {
59
- status: 404,
60
- statusText: 'Directory type not found',
61
- });
62
- }
63
61
  }
@@ -7,7 +7,9 @@ import { Page } from './_index.data';
7
7
  export const prerender = Page.prerender;
8
8
  export const getStaticPaths = Page.getStaticPaths;
9
9
 
10
- const { type, data } = await Page.getData(Astro);
10
+ const pageData = await Page.getData(Astro);
11
+ if (!pageData) return Astro.rewrite('/404');
12
+ const { type, data } = pageData;
11
13
 
12
14
  function mapToItem(i: any) {
13
15
  return {
@@ -81,6 +81,11 @@ export class Page extends HybridPage {
81
81
  'data-products': getDataProducts,
82
82
  };
83
83
 
84
+ // An unknown type (e.g. a mistyped URL) has no discover page
85
+ if (!Object.hasOwn(loaders, type)) {
86
+ return null;
87
+ }
88
+
84
89
  // @ts-ignore
85
90
  const items = await loaders[type]();
86
91
 
@@ -89,11 +94,4 @@ export class Page extends HybridPage {
89
94
  data: items,
90
95
  };
91
96
  }
92
-
93
- protected static createNotFoundResponse(): Response {
94
- return new Response(null, {
95
- status: 404,
96
- statusText: 'Collection type not found',
97
- });
98
- }
99
97
  }
@@ -27,7 +27,9 @@ import { Page } from './_index.data';
27
27
  export const prerender = Page.prerender;
28
28
  export const getStaticPaths = Page.getStaticPaths;
29
29
 
30
- const { type, data } = await Page.getData(Astro);
30
+ const pageData = await Page.getData(Astro);
31
+ if (!pageData) return Astro.rewrite('/404');
32
+ const { type, data } = pageData;
31
33
 
32
34
  const events = await getEvents();
33
35
  const queries = await getQueries();