@eventcatalog/core 4.12.2 → 5.0.0-beta.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 (268) hide show
  1. package/LICENSE +226 -95
  2. package/NOTICE +30 -0
  3. package/README.md +3 -2
  4. package/dist/analytics/analytics.cjs +1 -1
  5. package/dist/analytics/analytics.js +2 -2
  6. package/dist/analytics/log-build.cjs +43 -16
  7. package/dist/analytics/log-build.d.cts +6 -5
  8. package/dist/analytics/log-build.d.ts +6 -5
  9. package/dist/analytics/log-build.js +4 -3
  10. package/dist/{chunk-U4YJSTGV.js → chunk-AYNZXUB5.js} +2 -10
  11. package/dist/{chunk-IVVM67LN.js → chunk-CR6AK5LR.js} +1 -1
  12. package/dist/{chunk-GTIC4R74.js → chunk-LR7AGRHN.js} +13 -16
  13. package/dist/chunk-TQLRG35T.js +203 -0
  14. package/dist/{chunk-WK4J6FP3.js → chunk-TWN43V4T.js} +1 -1
  15. package/dist/{chunk-ZW3MYAWF.js → chunk-WAIADKQE.js} +1 -1
  16. package/dist/{chunk-RPVA2SZY.js → chunk-ZHKEARLJ.js} +1 -1
  17. package/dist/constants.cjs +1 -1
  18. package/dist/constants.js +1 -1
  19. package/dist/eventcatalog.cjs +407 -291
  20. package/dist/eventcatalog.config.d.cts +2 -3
  21. package/dist/eventcatalog.config.d.ts +2 -3
  22. package/dist/eventcatalog.js +30 -93
  23. package/dist/federation/content-cache.d.cts +0 -5
  24. package/dist/federation/content-cache.d.ts +0 -5
  25. package/dist/federation/diagnostics.d.cts +0 -5
  26. package/dist/federation/diagnostics.d.ts +0 -5
  27. package/dist/federation/federate.cjs +0 -9
  28. package/dist/federation/federate.d.cts +0 -5
  29. package/dist/federation/federate.d.ts +0 -5
  30. package/dist/federation/federate.js +2 -3
  31. package/dist/federation/filesystem-source-provider.d.cts +0 -5
  32. package/dist/federation/filesystem-source-provider.d.ts +0 -5
  33. package/dist/federation/github-source-provider.d.cts +0 -5
  34. package/dist/federation/github-source-provider.d.ts +0 -5
  35. package/dist/federation/output-transaction.d.cts +0 -4
  36. package/dist/federation/output-transaction.d.ts +0 -4
  37. package/dist/federation/public-assets.d.cts +0 -5
  38. package/dist/federation/public-assets.d.ts +0 -5
  39. package/dist/federation/source-provider.d.cts +0 -5
  40. package/dist/federation/source-provider.d.ts +0 -5
  41. package/dist/federation/types.d.cts +0 -5
  42. package/dist/federation/types.d.ts +0 -5
  43. package/dist/generate.cjs +1 -1
  44. package/dist/generate.js +3 -3
  45. package/dist/license-C1y-56bb.d.cts +23 -0
  46. package/dist/license-C1y-56bb.d.ts +23 -0
  47. package/dist/runtime-dependencies/@eventcatalog__visualiser__layout.mjs +3 -0
  48. package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps.mjs +3 -0
  49. package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__react.mjs +3 -0
  50. package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__server.mjs +3 -0
  51. package/dist/runtime-dependencies/@modelcontextprotocol__sdk__types.js.mjs +3 -0
  52. package/dist/runtime-dependencies/manifest.json +12 -1
  53. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__graphql.mjs +3 -0
  54. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__json.mjs +3 -0
  55. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__markup.mjs +3 -0
  56. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__protobuf.mjs +3 -0
  57. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__yaml.mjs +3 -0
  58. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-dark.mjs +3 -0
  59. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-light.mjs +3 -0
  60. package/dist/utils/cli-logger.cjs +1 -1
  61. package/dist/utils/cli-logger.js +2 -2
  62. package/dist/utils/license-status.cjs +240 -0
  63. package/dist/utils/license-status.d.cts +28 -0
  64. package/dist/utils/license-status.d.ts +28 -0
  65. package/dist/utils/license-status.js +12 -0
  66. package/eventcatalog/astro.config.mjs +1 -1
  67. package/eventcatalog/integrations/eventcatalog-runtime.mjs +1 -1
  68. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +29 -19
  69. package/eventcatalog/src/components/ChatPanel/OfflineReply.tsx +74 -0
  70. package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +24 -28
  71. package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +16 -11
  72. package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +4 -218
  73. package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +27 -36
  74. package/eventcatalog/src/components/Header.astro +43 -58
  75. package/eventcatalog/src/components/Lists/PillListFlat.styles.css +17 -17
  76. package/eventcatalog/src/components/MDX/EntityMap/EntityMap.astro +1 -1
  77. package/eventcatalog/src/components/MDX/Flow/Flow.astro +4 -0
  78. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +14 -0
  79. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +49 -18
  80. package/eventcatalog/src/components/MDX/RemoteFile.astro +2 -24
  81. package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +59 -93
  82. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +1 -32
  83. package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +20 -67
  84. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -11
  85. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +11 -60
  86. package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +1 -3
  87. package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +0 -3
  88. package/eventcatalog/src/components/SchemaExplorer/VersionHistoryModal.tsx +2 -9
  89. package/eventcatalog/src/components/SchemaExplorer/parse-schema.ts +46 -0
  90. package/eventcatalog/src/components/SchemaExplorer/utils.ts +11 -0
  91. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +2 -9
  92. package/eventcatalog/src/components/Settings/LicenseSettings.tsx +288 -0
  93. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +3 -19
  94. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +85 -30
  95. package/eventcatalog/src/components/Settings/SettingsShared.tsx +7 -75
  96. package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +2 -2
  97. package/eventcatalog/src/components/TrialBadge.astro +82 -0
  98. package/eventcatalog/src/content.config.ts +9 -90
  99. package/eventcatalog/src/{enterprise → features}/ai/chat-api.ts +22 -34
  100. package/eventcatalog/src/{enterprise → features}/analytics/adapters/ga4.ts +0 -5
  101. package/eventcatalog/src/{enterprise → features}/analytics/adapters/gtm.ts +0 -5
  102. package/eventcatalog/src/{enterprise → features}/analytics/adapters/posthog.ts +0 -5
  103. package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsHead.astro +2 -4
  104. package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsTracker.astro +2 -4
  105. package/eventcatalog/src/{enterprise → features}/analytics/tracker.ts +0 -5
  106. package/eventcatalog/src/{enterprise → features}/api/catalog.ts +0 -5
  107. package/eventcatalog/src/{enterprise → features}/auth/[...auth].ts +0 -5
  108. package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware-auth.ts +0 -5
  109. package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware.ts +0 -5
  110. package/eventcatalog/src/{enterprise → features}/collections/custom-pages.ts +0 -5
  111. package/eventcatalog/src/{enterprise → features}/collections/index.ts +0 -5
  112. package/eventcatalog/src/{enterprise → features}/collections/resource-docs.ts +0 -5
  113. package/eventcatalog/src/{enterprise → features}/custom-documentation/collection.ts +0 -5
  114. package/eventcatalog/src/features/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
  115. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -5
  116. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +1 -6
  117. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NoResultsFound.tsx +0 -5
  118. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/index.tsx +1 -6
  119. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/types.ts +0 -5
  120. package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/index.astro → features/custom-documentation/components/CustomDocumentationPage.astro} +5 -5
  121. package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/badge-styles.ts +0 -5
  122. package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/custom-docs.ts +1 -6
  123. package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/docs-search.ts +0 -5
  124. package/eventcatalog/src/{enterprise → features}/custom-pages/routes.ts +0 -5
  125. package/eventcatalog/src/{enterprise → features}/directory/user-team-directory.ts +0 -5
  126. package/eventcatalog/src/{enterprise → features}/fields/field-extractor.ts +0 -5
  127. package/eventcatalog/src/{enterprise → features}/fields/field-indexer.ts +0 -5
  128. package/eventcatalog/src/{enterprise → features}/fields/fields-db.ts +0 -5
  129. package/eventcatalog/src/{enterprise → features}/fields/pages/api/fields.ts +1 -6
  130. package/eventcatalog/src/{enterprise → features}/fields/pages/fields.astro +1 -2
  131. package/eventcatalog/src/{enterprise → features}/integrations/eventcatalog-features.ts +17 -75
  132. package/eventcatalog/src/features/mcp/apps/architecture-diagram/links.ts +59 -0
  133. package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +299 -0
  134. package/eventcatalog/src/features/mcp/apps/architecture-diagram/shared.ts +14 -0
  135. package/eventcatalog/src/features/mcp/apps/architecture-diagram/view.tsx +454 -0
  136. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +432 -0
  137. package/eventcatalog/src/features/mcp/apps/mermaid-stub.ts +10 -0
  138. package/eventcatalog/src/features/mcp/apps/schema-viewer/schema-code.tsx +65 -0
  139. package/eventcatalog/src/features/mcp/apps/schema-viewer/shared.ts +23 -0
  140. package/eventcatalog/src/features/mcp/apps/schema-viewer/view.tsx +170 -0
  141. package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +98 -0
  142. package/eventcatalog/src/features/mcp/apps/shared/resource-types.ts +15 -0
  143. package/eventcatalog/src/features/mcp/apps/viewer/shared.ts +24 -0
  144. package/eventcatalog/src/features/mcp/apps/viewer/styles.css +25 -0
  145. package/eventcatalog/src/features/mcp/apps/viewer/view.tsx +59 -0
  146. package/eventcatalog/src/features/mcp/mcp-app-icons.ts +63 -0
  147. package/eventcatalog/src/features/mcp/mcp-apps.ts +160 -0
  148. package/eventcatalog/src/{enterprise → features}/mcp/mcp-auth.ts +0 -5
  149. package/eventcatalog/src/{enterprise → features}/mcp/mcp-scope.ts +7 -7
  150. package/eventcatalog/src/{enterprise → features}/mcp/mcp-scoped-tools.ts +47 -40
  151. package/eventcatalog/src/{enterprise → features}/mcp/mcp-server.ts +347 -34
  152. package/eventcatalog/src/{enterprise → features}/mcp/oauth-protected-resource.ts +0 -5
  153. package/eventcatalog/src/features/mcp/schema-viewer.ts +24 -0
  154. package/eventcatalog/src/{enterprise → features}/tools/catalog-tools.ts +133 -102
  155. package/eventcatalog/src/features/tools/index.ts +5 -0
  156. package/eventcatalog/src/{enterprise → features}/visualizer-layout/reset.ts +0 -5
  157. package/eventcatalog/src/{enterprise → features}/visualizer-layout/save.ts +0 -5
  158. package/eventcatalog/src/layouts/BaseLayout.astro +2 -2
  159. package/eventcatalog/src/layouts/Footer.astro +31 -39
  160. package/eventcatalog/src/layouts/SettingsLayout.astro +6 -6
  161. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +7 -37
  162. package/eventcatalog/src/{enterprise → pages}/api/schemas/[collection]/[id]/[version]/index.ts +0 -22
  163. package/eventcatalog/src/{enterprise → pages}/api/schemas/services/[id]/[version]/[specification]/index.ts +0 -19
  164. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +2 -6
  165. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -5
  166. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +2 -6
  167. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -5
  168. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].md.ts +2 -6
  169. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].mdx.ts +2 -6
  170. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +9 -5
  171. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +12 -0
  172. package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/root-index.astro → pages/docs/custom/index.astro} +1 -23
  173. package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +4 -9
  174. package/eventcatalog/src/pages/docs/llm/llms.txt.ts +4 -4
  175. package/eventcatalog/src/pages/docs/llm/schemas.txt.ts +0 -11
  176. package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +2 -2
  177. package/eventcatalog/src/pages/index.astro +2 -2
  178. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +0 -3
  179. package/eventcatalog/src/pages/schemas/explorer/index.astro +1 -4
  180. package/eventcatalog/src/pages/settings/assistant.astro +2 -4
  181. package/eventcatalog/src/pages/settings/license.astro +18 -0
  182. package/eventcatalog/src/pages/settings/llm-access.astro +1 -4
  183. package/eventcatalog/src/pages/settings/mcp.astro +33 -4
  184. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -2
  185. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +2 -45
  186. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -1
  187. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version].mermaid.ts +7 -109
  188. package/eventcatalog/src/pages/visualiser/_mermaid-route.ts +78 -0
  189. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/_index.data.ts +44 -0
  190. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -1
  191. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +56 -0
  192. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +3 -40
  193. package/eventcatalog/src/pages/visualiser/domains/[id]/[version].mermaid.ts +20 -0
  194. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/_index.data.ts +29 -0
  195. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +3 -38
  196. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +56 -0
  197. package/eventcatalog/src/pages/visualiser/systems/[id]/[version].mermaid.ts +20 -0
  198. package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +1 -1
  199. package/eventcatalog/src/stores/sidebar-store/builders/container.ts +1 -1
  200. package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +1 -1
  201. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +7 -32
  202. package/eventcatalog/src/stores/sidebar-store/builders/entity.ts +1 -1
  203. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +1 -1
  204. package/eventcatalog/src/stores/sidebar-store/builders/service.ts +2 -8
  205. package/eventcatalog/src/stores/sidebar-store/builders/system.ts +2 -12
  206. package/eventcatalog/src/stores/sidebar-store/custom-sidebar.ts +0 -10
  207. package/eventcatalog/src/stores/sidebar-store/state.ts +4 -6
  208. package/eventcatalog/src/styles/theme.css +22 -18
  209. package/eventcatalog/src/styles/themes/forest.css +8 -8
  210. package/eventcatalog/src/styles/themes/ocean.css +8 -8
  211. package/eventcatalog/src/styles/themes/sapphire.css +8 -8
  212. package/eventcatalog/src/styles/themes/sunset.css +8 -8
  213. package/eventcatalog/src/utils/clipboard.ts +4 -4
  214. package/eventcatalog/src/utils/collections/flow-step-schema.ts +117 -0
  215. package/eventcatalog/src/utils/collections/pointer-schema.ts +7 -0
  216. package/eventcatalog/src/utils/collections/resource-docs.ts +677 -14
  217. package/eventcatalog/src/utils/collections/schema-loader.ts +0 -5
  218. package/eventcatalog/src/utils/feature.ts +14 -23
  219. package/eventcatalog/src/utils/license.ts +114 -0
  220. package/eventcatalog/src/utils/node-graphs/architecture-diagram-types.ts +32 -0
  221. package/eventcatalog/src/utils/node-graphs/architecture-diagram.ts +84 -0
  222. package/eventcatalog/src/utils/node-graphs/catalog-force-graph.ts +1 -0
  223. package/eventcatalog/src/utils/node-graphs/channel-node-graph.ts +4 -25
  224. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +12 -39
  225. package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +11 -27
  226. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +679 -0
  227. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +3 -20
  228. package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +62 -4
  229. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +8 -23
  230. package/eventcatalog/src/utils/node-graphs/flow-lanes.ts +119 -0
  231. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +153 -45
  232. package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +28 -0
  233. package/eventcatalog/src/utils/node-graphs/layout-persistence.ts +3 -3
  234. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +16 -34
  235. package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +11 -25
  236. package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +18 -54
  237. package/eventcatalog/src/utils/node-graphs/system-levels-node-graph.ts +59 -0
  238. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +20 -80
  239. package/eventcatalog/src/utils/node-graphs/utils/utils.ts +1 -78
  240. package/eventcatalog/src/utils/trial.ts +36 -0
  241. package/eventcatalog/tsconfig.json +1 -1
  242. package/package.json +11 -11
  243. package/dist/chunk-FV56YFM4.js +0 -7
  244. package/dist/federation/entitlement.cjs +0 -31
  245. package/dist/federation/entitlement.d.cts +0 -12
  246. package/dist/federation/entitlement.d.ts +0 -12
  247. package/dist/federation/entitlement.js +0 -6
  248. package/dist/runtime-dependencies/dagre.mjs +0 -3
  249. package/eventcatalog/src/components/Settings/BillingSettingsForm.tsx +0 -265
  250. package/eventcatalog/src/enterprise/LICENSE +0 -57
  251. package/eventcatalog/src/enterprise/README.md +0 -5
  252. package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +0 -691
  253. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +0 -9
  254. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/[...path]/index.astro +0 -18
  255. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/feature.astro +0 -171
  256. package/eventcatalog/src/enterprise/feature.ts +0 -75
  257. package/eventcatalog/src/enterprise/tools/index.ts +0 -10
  258. package/eventcatalog/src/hooks/eventcatalog-visualizer.ts +0 -126
  259. package/eventcatalog/src/pages/settings/billing.astro +0 -17
  260. package/eventcatalog/src/pages/visualiser/domain-integrations/index.astro +0 -26
  261. package/eventcatalog/src/types/mcp-modules.d.ts +0 -67
  262. package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +0 -261
  263. package/eventcatalog/src/utils/node-graphs/export-node-graph.ts +0 -91
  264. /package/eventcatalog/src/{enterprise → features}/auth/error.astro +0 -0
  265. /package/eventcatalog/src/{enterprise → features}/auth/login.astro +0 -0
  266. /package/eventcatalog/src/{enterprise → features}/auth/unauthorized.astro +0 -0
  267. /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path]/_index.data.ts +0 -0
  268. /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path].mdx.ts +0 -0
@@ -38,7 +38,7 @@ import {
38
38
  SCHEMA_RELATIONSHIP_LABELS,
39
39
  } from './utils';
40
40
  import { createSchemaDetailsLoader, useSchemaDetails } from './useSchemaDetails';
41
- import { parseProtobufSchema } from '@utils/protobuf-schema';
41
+ import { parseSchemaForViewer } from './parse-schema';
42
42
  import type { SchemaItem, SchemaSourceInfo, SchemaRelationshipCollection, VersionDiff, Owner, Producer } from './types';
43
43
 
44
44
  const MESSAGE_TYPE_LABELS: Partial<Record<SchemaItem['collection'], string>> = {
@@ -310,7 +310,6 @@ interface SchemaDetailsPanelProps {
310
310
  availableVersions: SchemaItem[];
311
311
  selectedVersion: string | null;
312
312
  onVersionChange: (version: string) => void;
313
- apiAccessEnabled?: boolean;
314
313
  showOwners?: boolean;
315
314
  showProducersConsumers?: boolean;
316
315
  /** Tab slug from the URL, when the server could read it. Lets the first render show the right tab. */
@@ -324,7 +323,6 @@ export default function SchemaDetailsPanel({
324
323
  availableVersions,
325
324
  selectedVersion,
326
325
  onVersionChange,
327
- apiAccessEnabled = false,
328
326
  showOwners = true,
329
327
  showProducersConsumers = true,
330
328
  initialTab,
@@ -428,55 +426,14 @@ export default function SchemaDetailsPanel({
428
426
  }, [comparing, diffFromItem, diffToItem]);
429
427
  const selectedDiffs = selectedDiff ? [selectedDiff] : [];
430
428
 
431
- // Check if this is a JSON schema
432
- const parsedSchema = useMemo(() => {
433
- const isJSONSchema =
434
- message.schemaExtension?.toLowerCase() === 'json' && message.schemaContent && message.schemaContent.trim() !== '';
435
- if (!isJSONSchema) return null;
436
-
437
- try {
438
- const parsed = JSON.parse(message.schemaContent ?? '');
439
- if (!parsed.properties && !parsed.$schema && !parsed.type) {
440
- return null;
441
- }
442
- return parsed;
443
- } catch {
444
- return null;
445
- }
446
- }, [message.schemaContent, message.schemaExtension]);
447
-
448
- // Check if this is an Avro schema
449
- const parsedAvroSchema = useMemo(() => {
450
- const extLower = message.schemaExtension?.toLowerCase();
451
- const isAvroSchema =
452
- (extLower === 'avro' || extLower === 'avsc') && message.schemaContent && message.schemaContent.trim() !== '';
453
- if (!isAvroSchema) return null;
454
-
455
- try {
456
- const parsed = JSON.parse(message.schemaContent ?? '');
457
- if (!parsed.type) {
458
- return null;
459
- }
460
- return parsed;
461
- } catch {
462
- return null;
463
- }
464
- }, [message.schemaContent, message.schemaExtension]);
465
-
466
- // Check if this is a Protobuf schema. The extension falls back to the schema
467
- // format when the schema has no file path, so accept both 'proto' and 'protobuf'.
468
- const parsedProtoSchema = useMemo(() => {
469
- const extLower = message.schemaExtension?.toLowerCase();
470
- const isProtoSchema =
471
- (extLower === 'proto' || extLower === 'protobuf') && message.schemaContent && message.schemaContent.trim() !== '';
472
- if (!isProtoSchema) return null;
473
-
474
- try {
475
- return parseProtobufSchema(message.schemaContent ?? '');
476
- } catch {
477
- return null;
478
- }
479
- }, [message.schemaContent, message.schemaExtension]);
429
+ // Parse JSON Schema, Avro and Protobuf schemas for the Properties tab
430
+ const viewableSchema = useMemo(
431
+ () => parseSchemaForViewer(message.schemaExtension, message.schemaContent),
432
+ [message.schemaContent, message.schemaExtension]
433
+ );
434
+ const parsedSchema = viewableSchema.kind === 'json' ? viewableSchema.schema : null;
435
+ const parsedAvroSchema = viewableSchema.kind === 'avro' ? viewableSchema.schema : null;
436
+ const parsedProtoSchema = viewableSchema.kind === 'protobuf' ? viewableSchema.schema : null;
480
437
 
481
438
  const handleCopy = async () => {
482
439
  if (!message.schemaContent) return;
@@ -832,7 +789,7 @@ export default function SchemaDetailsPanel({
832
789
  <p className="text-sm">No schema content available</p>
833
790
  </div>
834
791
  ) : (
835
- <DiffViewer diffs={selectedDiffs} apiAccessEnabled={apiAccessEnabled} />
792
+ <DiffViewer diffs={selectedDiffs} />
836
793
  )}
837
794
  </div>
838
795
  </div>
@@ -843,12 +800,7 @@ export default function SchemaDetailsPanel({
843
800
  ) : activeTab === 'flows' && showFlowsTab ? (
844
801
  <SchemaFlows message={message} flows={flows} />
845
802
  ) : activeTab === 'api' ? (
846
- <ApiContentViewer
847
- message={message}
848
- onCopy={handleCopyCustom}
849
- copiedId={copiedId}
850
- apiAccessEnabled={apiAccessEnabled}
851
- />
803
+ <ApiContentViewer message={message} onCopy={handleCopyCustom} copiedId={copiedId} />
852
804
  ) : (
853
805
  <SchemaContentViewer
854
806
  message={message}
@@ -877,7 +829,6 @@ export default function SchemaDetailsPanel({
877
829
  onOpenChange={setIsDiffModalOpen}
878
830
  diffs={selectedDiffs}
879
831
  messageName={message.data.name}
880
- apiAccessEnabled={apiAccessEnabled}
881
832
  />
882
833
  <SchemaCodeModal
883
834
  isOpen={isCodeModalOpen}
@@ -44,10 +44,9 @@ function getGroupKey(item: SchemaItem): string {
44
44
 
45
45
  interface SchemaExplorerProps {
46
46
  schemas: SchemaItem[];
47
- apiAccessEnabled?: boolean;
48
47
  }
49
48
 
50
- export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: SchemaExplorerProps) {
49
+ export default function SchemaExplorer({ schemas }: SchemaExplorerProps) {
51
50
  const [searchQuery, setSearchQuery] = useState(() => {
52
51
  if (typeof window !== 'undefined') {
53
52
  const stored = localStorage.getItem('schemaRegistrySearchQuery');
@@ -594,7 +593,6 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
594
593
  availableVersions={availableVersions}
595
594
  selectedVersion={selectedVersion}
596
595
  onVersionChange={handleVersionChange}
597
- apiAccessEnabled={apiAccessEnabled}
598
596
  />
599
597
  ) : (
600
598
  <div className="flex h-full items-center justify-center">
@@ -5,7 +5,6 @@ import type { SchemaItem } from './types';
5
5
  interface SchemaPageViewerProps {
6
6
  message: SchemaItem;
7
7
  availableVersions: SchemaItem[];
8
- apiAccessEnabled?: boolean;
9
8
  showOwners?: boolean;
10
9
  showProducersConsumers?: boolean;
11
10
  /** Tab requested in the URL, resolved on the server to avoid a flash of the default tab. */
@@ -18,7 +17,6 @@ interface SchemaPageViewerProps {
18
17
  export default function SchemaPageViewer({
19
18
  message,
20
19
  availableVersions,
21
- apiAccessEnabled = false,
22
20
  showOwners = true,
23
21
  showProducersConsumers = true,
24
22
  initialTab,
@@ -38,7 +36,6 @@ export default function SchemaPageViewer({
38
36
  availableVersions={availableVersions}
39
37
  selectedVersion={message.data.version}
40
38
  onVersionChange={handleVersionChange}
41
- apiAccessEnabled={apiAccessEnabled}
42
39
  showOwners={showOwners}
43
40
  showProducersConsumers={showProducersConsumers}
44
41
  initialTab={initialTab}
@@ -8,16 +8,9 @@ interface VersionHistoryModalProps {
8
8
  onOpenChange: (open: boolean) => void;
9
9
  diffs: VersionDiff[];
10
10
  messageName: string;
11
- apiAccessEnabled?: boolean;
12
11
  }
13
12
 
14
- export default function VersionHistoryModal({
15
- isOpen,
16
- onOpenChange,
17
- diffs,
18
- messageName,
19
- apiAccessEnabled = false,
20
- }: VersionHistoryModalProps) {
13
+ export default function VersionHistoryModal({ isOpen, onOpenChange, diffs, messageName }: VersionHistoryModalProps) {
21
14
  return (
22
15
  <Dialog.Root open={isOpen} onOpenChange={onOpenChange}>
23
16
  <Dialog.Portal>
@@ -48,7 +41,7 @@ export default function VersionHistoryModal({
48
41
  {/* Content */}
49
42
  <div className="flex-1 overflow-y-auto p-6">
50
43
  {diffs.length > 0 ? (
51
- <DiffViewer diffs={diffs} apiAccessEnabled={apiAccessEnabled} />
44
+ <DiffViewer diffs={diffs} />
52
45
  ) : (
53
46
  <div className="flex items-center justify-center h-full">
54
47
  <p className="text-[rgb(var(--ec-page-text-muted))] text-center">No version comparison available</p>
@@ -0,0 +1,46 @@
1
+ import { parseProtobufSchema, type ProtobufSchema } from '@utils/protobuf-schema';
2
+
3
+ /** A schema, parsed for the viewer that shows its properties. Other formats are only shown as code. */
4
+ export type ViewableSchema =
5
+ | { kind: 'json'; schema: Record<string, any> }
6
+ | { kind: 'avro'; schema: Record<string, any> }
7
+ | { kind: 'protobuf'; schema: ProtobufSchema }
8
+ | { kind: 'code' };
9
+
10
+ const parseJson = (content: string) => {
11
+ try {
12
+ return JSON.parse(content);
13
+ } catch {
14
+ return undefined;
15
+ }
16
+ };
17
+
18
+ /**
19
+ * Parses a schema for the JSON Schema, Avro or Protobuf viewer, from its file extension.
20
+ * Used by the Schema Explorer and the MCP server's schema viewer, so both show the same schemas as properties.
21
+ */
22
+ export function parseSchemaForViewer(extension: string | undefined, content: string | undefined): ViewableSchema {
23
+ if (!content?.trim()) return { kind: 'code' };
24
+
25
+ switch (extension?.toLowerCase()) {
26
+ case 'json': {
27
+ const schema = parseJson(content);
28
+ return schema && (schema.properties || schema.$schema || schema.type) ? { kind: 'json', schema } : { kind: 'code' };
29
+ }
30
+ case 'avro':
31
+ case 'avsc': {
32
+ const schema = parseJson(content);
33
+ return schema?.type ? { kind: 'avro', schema } : { kind: 'code' };
34
+ }
35
+ // The extension falls back to the schema format when the schema has no file path, so accept both
36
+ case 'proto':
37
+ case 'protobuf':
38
+ try {
39
+ return { kind: 'protobuf', schema: parseProtobufSchema(content) };
40
+ } catch {
41
+ return { kind: 'code' };
42
+ }
43
+ default:
44
+ return { kind: 'code' };
45
+ }
46
+ }
@@ -113,6 +113,17 @@ export const getLanguageForHighlight = (extension?: string): string => {
113
113
  }
114
114
  };
115
115
 
116
+ /** Style of highlighted schema code, shared by the Schema tab and the MCP server's schema viewer */
117
+ export const SCHEMA_CODE_STYLE = {
118
+ margin: 0,
119
+ padding: '1.25rem',
120
+ borderRadius: 0,
121
+ fontSize: '0.8125rem',
122
+ lineHeight: '1.625',
123
+ background: 'transparent',
124
+ overflow: 'auto',
125
+ } as const;
126
+
116
127
  export const getSchemaTypeLabel = (extension?: string): string => {
117
128
  if (!extension) return 'JSON';
118
129
  const ext = extension.toLowerCase();
@@ -4,19 +4,18 @@ import { ExternalLink, MessageSquare, ServerCog, Wrench } from 'lucide-react';
4
4
  import { aiSettingsSchema } from '@utils/eventcatalog-config/config-schema';
5
5
  import { ReadOnlyBanner } from './ReadOnlyBanner';
6
6
  import { Row, cn } from './Row';
7
- import { ASSISTANT_CONFIGURATION_DOCS_URL, ASSISTANT_DOCS_URL, ToggleRow, UpgradeRequired } from './SettingsShared';
7
+ import { ASSISTANT_CONFIGURATION_DOCS_URL, ASSISTANT_DOCS_URL, ToggleRow } from './SettingsShared';
8
8
 
9
9
  interface Props {
10
10
  canEdit: boolean;
11
11
  initial: { chatEnabled: boolean; llmsTxtEnabled: boolean };
12
12
  chatAvailable: boolean;
13
- hasPlan: boolean;
14
13
  inSSR: boolean;
15
14
  hasChatConfigFile: boolean;
16
15
  apiBase: string;
17
16
  }
18
17
 
19
- export const AssistantSettingsForm = ({ canEdit, initial, chatAvailable, hasPlan, inSSR, hasChatConfigFile, apiBase }: Props) => {
18
+ export const AssistantSettingsForm = ({ canEdit, initial, chatAvailable, inSSR, hasChatConfigFile, apiBase }: Props) => {
20
19
  const [chatEnabled, setChatEnabled] = useState(initial.chatEnabled);
21
20
  const [pristine, setPristine] = useState(initial.chatEnabled);
22
21
  const [saving, setSaving] = useState(false);
@@ -97,12 +96,6 @@ export const AssistantSettingsForm = ({ canEdit, initial, chatAvailable, hasPlan
97
96
  {chatEnabled &&
98
97
  (chatAvailable ? (
99
98
  <ConfigurationRequired />
100
- ) : !hasPlan ? (
101
- <UpgradeRequired
102
- tier="Starter and Scale"
103
- blurb="The EventCatalog Assistant is part of our paid plans. Upgrade to give your team a built-in AI agent that answers questions about your architecture."
104
- docsUrl={ASSISTANT_DOCS_URL}
105
- />
106
99
  ) : !inSSR ? (
107
100
  <AssistantNeedsSSR />
108
101
  ) : !hasChatConfigFile ? (
@@ -0,0 +1,288 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { ArrowUpRight, Clock, TriangleAlert } from 'lucide-react';
3
+ import { Row, cn } from './Row';
4
+ import { getTrialStatus, LICENSE_FAQ_URL, LICENSE_REMINDER_DAYS, LICENSE_RENEW_URL, TRIAL_LENGTH_DAYS } from '@utils/trial';
5
+
6
+ /**
7
+ * The license status (see getLicenseStatus in @utils/license) with dates as unix ms, so it can be
8
+ * passed to the browser. Days left are counted there, so a prerendered page stays current.
9
+ */
10
+ export type LicenseProps =
11
+ | { state: 'none' }
12
+ | {
13
+ state: 'licensed' | 'expired';
14
+ org?: string;
15
+ licenseId?: string;
16
+ issuedAt?: number;
17
+ expiresAt?: number;
18
+ }
19
+ | { state: 'plan'; plan: 'scale' | 'starter' }
20
+ | { state: 'invalid'; reason: string };
21
+
22
+ const DAY_IN_MS = 24 * 60 * 60 * 1000;
23
+
24
+ // A fixed locale and time zone, so the browser renders the same dates as the server
25
+ const formatDate = (date?: Date | number) =>
26
+ date === undefined ? '—' : new Date(date).toLocaleDateString('en-GB', { dateStyle: 'long', timeZone: 'UTC' });
27
+ const formatDays = (days: number) => `${days} ${days === 1 ? 'day' : 'days'}`;
28
+
29
+ type Tone = 'success' | 'warning' | 'danger' | 'info' | 'neutral';
30
+
31
+ const PILL_TONES: Record<Tone, string> = {
32
+ success:
33
+ 'border-[rgb(var(--ec-badge-color-green-text)/0.3)] bg-[rgb(var(--ec-badge-color-green-background))] text-[rgb(var(--ec-badge-color-green-text))]',
34
+ warning:
35
+ 'border-[rgb(var(--ec-badge-color-amber-text)/0.3)] bg-[rgb(var(--ec-badge-color-amber-background))] text-[rgb(var(--ec-badge-color-amber-text))]',
36
+ danger:
37
+ 'border-[rgb(var(--ec-badge-color-red-text)/0.3)] bg-[rgb(var(--ec-badge-color-red-background))] text-[rgb(var(--ec-badge-color-red-text))]',
38
+ info: 'border-[rgb(var(--ec-accent)/0.3)] bg-[rgb(var(--ec-accent-subtle))] text-[rgb(var(--ec-accent))]',
39
+ neutral: 'border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] text-[rgb(var(--ec-page-text-muted))]',
40
+ };
41
+
42
+ const StatusPill = ({ tone, children }: { tone: Tone; children: React.ReactNode }) => (
43
+ <span
44
+ className={cn('inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-[11px] font-semibold', PILL_TONES[tone])}
45
+ >
46
+ <span className="h-1.5 w-1.5 rounded-full bg-current" aria-hidden />
47
+ {children}
48
+ </span>
49
+ );
50
+
51
+ type Detail = { label: string; value: React.ReactNode; mono?: boolean };
52
+
53
+ const DetailsTable = ({
54
+ title,
55
+ status,
56
+ details,
57
+ }: {
58
+ title: string;
59
+ status: { tone: Tone; label: string };
60
+ details: Detail[];
61
+ }) => (
62
+ <div className="overflow-hidden rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))]">
63
+ <div className="flex items-center justify-between gap-3 border-b border-[rgb(var(--ec-page-border))] px-4 py-3">
64
+ <p className="text-[13px] font-semibold text-[rgb(var(--ec-page-text))]">{title}</p>
65
+ <StatusPill tone={status.tone}>{status.label}</StatusPill>
66
+ </div>
67
+ <dl className="divide-y divide-[rgb(var(--ec-page-border))]">
68
+ {details.map((detail) => (
69
+ <div key={detail.label} className="grid grid-cols-[9rem_minmax(0,_1fr)] gap-4 px-4 py-2.5">
70
+ <dt className="text-[12px] text-[rgb(var(--ec-page-text-muted))]">{detail.label}</dt>
71
+ <dd
72
+ className={cn(
73
+ 'min-w-0 break-words text-[13px] text-[rgb(var(--ec-page-text))]',
74
+ detail.mono && 'font-mono text-[12px]'
75
+ )}
76
+ >
77
+ {detail.value}
78
+ </dd>
79
+ </div>
80
+ ))}
81
+ </dl>
82
+ </div>
83
+ );
84
+
85
+ // Verified when the page was rendered, but may have expired since
86
+ const isExpired = (license: LicenseProps, now: number) =>
87
+ license.state === 'expired' || (license.state === 'licensed' && license.expiresAt !== undefined && license.expiresAt <= now);
88
+
89
+ const PLAN_NAMES = { scale: 'EventCatalog Scale', starter: 'EventCatalog Starter' };
90
+
91
+ // Days left on a license that's about to expire, or undefined
92
+ const getDaysLeft = (license: LicenseProps, now: number) => {
93
+ if (license.state !== 'licensed' || license.expiresAt === undefined) return;
94
+ const daysLeft = Math.max(0, Math.ceil((license.expiresAt - now) / DAY_IN_MS));
95
+ return daysLeft < LICENSE_REMINDER_DAYS ? daysLeft : undefined;
96
+ };
97
+
98
+ /**
99
+ * A callout below the license once it's about to expire, or has expired, so it's hard to miss.
100
+ */
101
+ const LicenseNotice = ({ license, now }: { license: LicenseProps; now: number }) => {
102
+ const expired = isExpired(license, now);
103
+ const daysLeft = getDaysLeft(license, now);
104
+ if (!expired && daysLeft === undefined) return null;
105
+
106
+ const expiresAt = license.state === 'licensed' || license.state === 'expired' ? license.expiresAt : undefined;
107
+ const Icon = expired ? TriangleAlert : Clock;
108
+ return (
109
+ <div
110
+ role="alert"
111
+ className={cn(
112
+ 'flex gap-3 rounded-lg border p-4',
113
+ expired
114
+ ? 'border-[rgb(var(--ec-badge-color-red-text)/0.3)] bg-[rgb(var(--ec-badge-color-red-background))] text-[rgb(var(--ec-badge-color-red-text))]'
115
+ : 'border-[rgb(var(--ec-badge-color-amber-text)/0.3)] bg-[rgb(var(--ec-badge-color-amber-background))] text-[rgb(var(--ec-badge-color-amber-text))]'
116
+ )}
117
+ >
118
+ <Icon className="mt-0.5 h-4 w-4 shrink-0" aria-hidden />
119
+ <div className="space-y-1">
120
+ <p className="text-[13px] font-semibold">
121
+ {expired ? 'Your commercial license has expired' : `Your commercial license expires in ${formatDays(daysLeft!)}`}
122
+ </p>
123
+ <p className="text-[13px] opacity-90">
124
+ {expired
125
+ ? `It expired on ${formatDate(expiresAt)}. Renew it to keep using EventCatalog commercially.`
126
+ : `It expires on ${formatDate(expiresAt)}. Renew it before then to keep using EventCatalog commercially.`}
127
+ </p>
128
+ <div className="flex flex-wrap items-center gap-3 pt-2">
129
+ <a
130
+ href={LICENSE_RENEW_URL}
131
+ target="_blank"
132
+ rel="noreferrer"
133
+ className="inline-flex items-center gap-1.5 rounded-md bg-[rgb(var(--ec-page-text))] px-3.5 py-1.5 text-[13px] font-medium text-[rgb(var(--ec-page-bg))] shadow-sm transition-opacity hover:opacity-85"
134
+ >
135
+ Renew license
136
+ <ArrowUpRight className="h-3.5 w-3.5" aria-hidden />
137
+ </a>
138
+ <a
139
+ href={LICENSE_FAQ_URL}
140
+ target="_blank"
141
+ rel="noreferrer"
142
+ className="text-[13px] font-medium underline underline-offset-2 hover:opacity-80"
143
+ >
144
+ License FAQ
145
+ </a>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ );
150
+ };
151
+
152
+ const LicenseTable = ({ license, now }: { license: LicenseProps; now: number }) => {
153
+ if (license.state === 'plan') {
154
+ return (
155
+ <DetailsTable
156
+ title={PLAN_NAMES[license.plan]}
157
+ status={{ tone: 'success', label: 'Active' }}
158
+ details={[{ label: 'License key', value: `EVENTCATALOG_${license.plan.toUpperCase()}_LICENSE_KEY`, mono: true }]}
159
+ />
160
+ );
161
+ }
162
+ const expired = isExpired(license, now);
163
+ if (license.state === 'licensed' && !expired) {
164
+ const daysLeft = Math.max(0, Math.ceil(((license.expiresAt ?? now) - now) / DAY_IN_MS));
165
+ const expiringSoon = daysLeft < LICENSE_REMINDER_DAYS;
166
+ return (
167
+ <DetailsTable
168
+ title="Commercial license"
169
+ status={expiringSoon ? { tone: 'warning', label: 'Expires soon' } : { tone: 'success', label: 'Active' }}
170
+ details={[
171
+ { label: 'Licensed to', value: license.org || '—' },
172
+ { label: 'License ID', value: license.licenseId || '—', mono: true },
173
+ { label: 'Issued', value: formatDate(license.issuedAt) },
174
+ { label: 'Expires', value: formatDate(license.expiresAt) },
175
+ { label: 'Time left', value: formatDays(daysLeft) },
176
+ ]}
177
+ />
178
+ );
179
+ }
180
+ if ((license.state === 'licensed' || license.state === 'expired') && expired) {
181
+ return (
182
+ <DetailsTable
183
+ title="Commercial license"
184
+ status={{ tone: 'danger', label: 'Expired' }}
185
+ details={[
186
+ { label: 'Licensed to', value: license.org || '—' },
187
+ { label: 'License ID', value: license.licenseId || '—', mono: true },
188
+ { label: 'Issued', value: formatDate(license.issuedAt) },
189
+ { label: 'Expired', value: formatDate(license.expiresAt) },
190
+ ]}
191
+ />
192
+ );
193
+ }
194
+ if (license.state === 'invalid') {
195
+ return (
196
+ <DetailsTable
197
+ title="Commercial license"
198
+ status={{ tone: 'warning', label: 'Not verified' }}
199
+ details={[
200
+ { label: 'File', value: 'license.jwt', mono: true },
201
+ { label: 'Problem', value: `It could not be verified: ${license.reason}.` },
202
+ ]}
203
+ />
204
+ );
205
+ }
206
+ return null;
207
+ };
208
+
209
+ const TrialTable = ({ trialStartedAt, now }: { trialStartedAt?: number; now: number }) => {
210
+ const trial = getTrialStatus(trialStartedAt, now);
211
+ if (!trial) {
212
+ return (
213
+ <DetailsTable
214
+ title="EventCatalog trial"
215
+ status={{ tone: 'neutral', label: 'Not started' }}
216
+ details={[
217
+ {
218
+ label: 'Start date',
219
+ value: 'No trial start date (tsd) in eventcatalog.config.js.',
220
+ },
221
+ ]}
222
+ />
223
+ );
224
+ }
225
+ const startedAt = trial.endsAt.getTime() - TRIAL_LENGTH_DAYS * DAY_IN_MS;
226
+ return (
227
+ <DetailsTable
228
+ title="EventCatalog trial"
229
+ status={trial.ended ? { tone: 'warning', label: 'Ended' } : { tone: 'info', label: 'Active' }}
230
+ details={[
231
+ { label: 'Length', value: formatDays(TRIAL_LENGTH_DAYS) },
232
+ { label: 'Started', value: formatDate(startedAt) },
233
+ { label: trial.ended ? 'Ended' : 'Ends', value: formatDate(trial.endsAt) },
234
+ ...(trial.ended ? [] : [{ label: 'Time left', value: formatDays(trial.daysLeft) }]),
235
+ ]}
236
+ />
237
+ );
238
+ };
239
+
240
+ interface Props {
241
+ license: LicenseProps;
242
+ /** The trial start date (`tsd` in eventcatalog.config.js), unix ms */
243
+ trialStartedAt?: number;
244
+ /** When the page was rendered, unix ms: the first render matches the server's, then it counts from now */
245
+ renderedAt: number;
246
+ }
247
+
248
+ export const LicenseSettings = ({ license, trialStartedAt, renderedAt }: Props) => {
249
+ const [now, setNow] = useState(renderedAt);
250
+ useEffect(() => setNow(Date.now()), []);
251
+
252
+ return (
253
+ <div className="divide-y divide-[rgb(var(--ec-page-border))]">
254
+ <Row
255
+ title="License"
256
+ description="EventCatalog is licensed under the Business Source License 1.1. Your license is read from the license.jwt file in the root of your catalog."
257
+ canEdit={false}
258
+ dirty={false}
259
+ >
260
+ <div className="space-y-4">
261
+ <LicenseTable license={license} now={now} />
262
+ <LicenseNotice license={license} now={now} />
263
+ {/* The trial applies until there's a valid license or plan */}
264
+ {license.state !== 'plan' && (license.state !== 'licensed' || isExpired(license, now)) && (
265
+ <TrialTable trialStartedAt={trialStartedAt} now={now} />
266
+ )}
267
+ </div>
268
+ </Row>
269
+
270
+ <Row
271
+ title="Learn more"
272
+ description="Who can use EventCatalog for free, and when you need a commercial license."
273
+ canEdit={false}
274
+ dirty={false}
275
+ >
276
+ <a
277
+ href={LICENSE_FAQ_URL}
278
+ target="_blank"
279
+ rel="noreferrer"
280
+ className="inline-flex items-center gap-1.5 rounded-md bg-[rgb(var(--ec-page-text))] px-4 py-2 text-[13px] font-medium text-[rgb(var(--ec-page-bg))] shadow-sm transition-opacity hover:opacity-85"
281
+ >
282
+ Read the license FAQ
283
+ <ArrowUpRight className="h-3.5 w-3.5" aria-hidden />
284
+ </a>
285
+ </Row>
286
+ </div>
287
+ );
288
+ };
@@ -4,27 +4,18 @@ import { Bot, FileText } from 'lucide-react';
4
4
  import { aiSettingsSchema } from '@utils/eventcatalog-config/config-schema';
5
5
  import { ReadOnlyBanner } from './ReadOnlyBanner';
6
6
  import { Row } from './Row';
7
- import { ToggleRow, UpgradeRequired, UrlPanel } from './SettingsShared';
7
+ import { ToggleRow, UrlPanel } from './SettingsShared';
8
8
 
9
9
  interface Props {
10
10
  canEdit: boolean;
11
11
  initial: { llmsTxtEnabled: boolean; chatEnabled: boolean };
12
- hasScalePlan: boolean;
13
12
  apiBase: string;
14
13
  llmsTxtUrl: string;
15
14
  llmsFullTxtUrl: string;
16
15
  schemasTxtUrl: string;
17
16
  }
18
17
 
19
- export const LlmAccessSettingsForm = ({
20
- canEdit,
21
- initial,
22
- hasScalePlan,
23
- apiBase,
24
- llmsTxtUrl,
25
- llmsFullTxtUrl,
26
- schemasTxtUrl,
27
- }: Props) => {
18
+ export const LlmAccessSettingsForm = ({ canEdit, initial, apiBase, llmsTxtUrl, llmsFullTxtUrl, schemasTxtUrl }: Props) => {
28
19
  const [llmsTxtEnabled, setLlmsTxtEnabled] = useState(initial.llmsTxtEnabled);
29
20
  const [pristine, setPristine] = useState(initial.llmsTxtEnabled);
30
21
  const [saving, setSaving] = useState(false);
@@ -108,14 +99,7 @@ export const LlmAccessSettingsForm = ({
108
99
  canEdit={false}
109
100
  dirty={false}
110
101
  >
111
- {hasScalePlan ? (
112
- <SchemasTxtAvailable url={schemasTxtUrl} />
113
- ) : (
114
- <UpgradeRequired
115
- tier="Scale"
116
- blurb="The schema index is a Scale-plan feature. Upgrade to publish a machine-readable catalogue of your schemas alongside llms.txt."
117
- />
118
- )}
102
+ <SchemasTxtAvailable url={schemasTxtUrl} />
119
103
  </Row>
120
104
  </form>
121
105
  );