@eventcatalog/core 4.12.0-beta.3 → 4.12.0-beta.5

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.
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(analytics_exports);
36
36
  var import_os = __toESM(require("os"), 1);
37
37
 
38
38
  // package.json
39
- var version = "4.12.0-beta.3";
39
+ var version = "4.12.0-beta.5";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-GGPT4I3K.js";
4
- import "../chunk-AVRFMQJX.js";
3
+ } from "../chunk-YTT7Z7QA.js";
4
+ import "../chunk-4BZILEBA.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -146,7 +146,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
146
146
  var import_os = __toESM(require("os"), 1);
147
147
 
148
148
  // package.json
149
- var version = "4.12.0-beta.3";
149
+ var version = "4.12.0-beta.5";
150
150
 
151
151
  // src/constants.ts
152
152
  var VERSION = version;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-5MBYZHYS.js";
3
+ } from "../chunk-UVFZAJCT.js";
4
4
  import "../chunk-ZAZHAVKB.js";
5
- import "../chunk-GGPT4I3K.js";
6
- import "../chunk-AVRFMQJX.js";
5
+ import "../chunk-YTT7Z7QA.js";
6
+ import "../chunk-4BZILEBA.js";
7
7
  import "../chunk-JE6RX7SJ.js";
8
8
  export {
9
9
  log_build_default as default
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "4.12.0-beta.3";
2
+ var version = "4.12.0-beta.5";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-AVRFMQJX.js";
3
+ } from "./chunk-4BZILEBA.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-TAGBLT3L.js";
3
+ } from "./chunk-5U3IKG4U.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-ZAZHAVKB.js";
6
6
  import {
7
7
  raiseEvent
8
- } from "./chunk-GGPT4I3K.js";
8
+ } from "./chunk-YTT7Z7QA.js";
9
9
  import {
10
10
  getEventCatalogConfigFile,
11
11
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-AVRFMQJX.js";
3
+ } from "./chunk-4BZILEBA.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import os from "os";
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "4.12.0-beta.3";
28
+ var version = "4.12.0-beta.5";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-AVRFMQJX.js";
3
+ } from "./chunk-4BZILEBA.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -151,7 +151,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
151
151
  var import_picocolors = __toESM(require("picocolors"), 1);
152
152
 
153
153
  // package.json
154
- var version = "4.12.0-beta.3";
154
+ var version = "4.12.0-beta.5";
155
155
 
156
156
  // src/constants.ts
157
157
  var VERSION = version;
@@ -1,11 +1,11 @@
1
+ import {
2
+ log_build_default
3
+ } from "./chunk-UVFZAJCT.js";
4
+ import "./chunk-ZAZHAVKB.js";
1
5
  import {
2
6
  runMigrations
3
7
  } from "./chunk-XUAF2H54.js";
4
8
  import "./chunk-CA4U2JP7.js";
5
- import {
6
- log_build_default
7
- } from "./chunk-5MBYZHYS.js";
8
- import "./chunk-ZAZHAVKB.js";
9
9
  import {
10
10
  FederationConflictError,
11
11
  FederationDiagnosticError,
@@ -14,14 +14,14 @@ import {
14
14
  import "./chunk-WRNH5C3U.js";
15
15
  import "./chunk-5EPNFDT5.js";
16
16
  import "./chunk-A2RZR3U4.js";
17
+ import "./chunk-SDZQJTJW.js";
18
+ import "./chunk-352FGP6W.js";
17
19
  import "./chunk-R7Z5ALYI.js";
18
20
  import {
19
21
  getFederationDiagnosticCounts,
20
22
  getVisibleFederationDiagnostics
21
23
  } from "./chunk-JJPB6EOZ.js";
22
24
  import "./chunk-FV56YFM4.js";
23
- import "./chunk-SDZQJTJW.js";
24
- import "./chunk-352FGP6W.js";
25
25
  import {
26
26
  getProjectOutDir,
27
27
  isAuthEnabled,
@@ -30,10 +30,10 @@ import {
30
30
  } from "./chunk-3SJDIENM.js";
31
31
  import {
32
32
  generate
33
- } from "./chunk-56TJHDS2.js";
33
+ } from "./chunk-IDSVEUSL.js";
34
34
  import {
35
35
  logger
36
- } from "./chunk-TAGBLT3L.js";
36
+ } from "./chunk-5U3IKG4U.js";
37
37
  import {
38
38
  resolve_catalog_dependencies_default
39
39
  } from "./chunk-EEZXGNF6.js";
@@ -47,7 +47,7 @@ import {
47
47
  import {
48
48
  watch
49
49
  } from "./chunk-U63GDPPY.js";
50
- import "./chunk-GGPT4I3K.js";
50
+ import "./chunk-YTT7Z7QA.js";
51
51
  import {
52
52
  getAstroConfigPath
53
53
  } from "./chunk-VIJJ7JKH.js";
@@ -62,7 +62,7 @@ import {
62
62
  } from "./chunk-SAN4U2WU.js";
63
63
  import {
64
64
  VERSION
65
- } from "./chunk-AVRFMQJX.js";
65
+ } from "./chunk-4BZILEBA.js";
66
66
  import {
67
67
  getEventCatalogConfigFile,
68
68
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -6,11 +6,11 @@ import {
6
6
  import "../chunk-WRNH5C3U.js";
7
7
  import "../chunk-5EPNFDT5.js";
8
8
  import "../chunk-A2RZR3U4.js";
9
+ import "../chunk-SDZQJTJW.js";
10
+ import "../chunk-352FGP6W.js";
9
11
  import "../chunk-R7Z5ALYI.js";
10
12
  import "../chunk-JJPB6EOZ.js";
11
13
  import "../chunk-FV56YFM4.js";
12
- import "../chunk-SDZQJTJW.js";
13
- import "../chunk-352FGP6W.js";
14
14
  import "../chunk-JE6RX7SJ.js";
15
15
  export {
16
16
  FederationConflictError,
package/dist/generate.cjs CHANGED
@@ -112,7 +112,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
112
112
  var import_picocolors = __toESM(require("picocolors"), 1);
113
113
 
114
114
  // package.json
115
- var version = "4.12.0-beta.3";
115
+ var version = "4.12.0-beta.5";
116
116
 
117
117
  // src/constants.ts
118
118
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-56TJHDS2.js";
4
- import "./chunk-TAGBLT3L.js";
5
- import "./chunk-AVRFMQJX.js";
3
+ } from "./chunk-IDSVEUSL.js";
4
+ import "./chunk-5U3IKG4U.js";
5
+ import "./chunk-4BZILEBA.js";
6
6
  import "./chunk-JE6RX7SJ.js";
7
7
  export {
8
8
  generate
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(cli_logger_exports);
36
36
  var import_picocolors = __toESM(require("picocolors"), 1);
37
37
 
38
38
  // package.json
39
- var version = "4.12.0-beta.3";
39
+ var version = "4.12.0-beta.5";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  logger
3
- } from "../chunk-TAGBLT3L.js";
4
- import "../chunk-AVRFMQJX.js";
3
+ } from "../chunk-5U3IKG4U.js";
4
+ import "../chunk-4BZILEBA.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -34,7 +34,7 @@ import preprocessExpressiveCodeConfig from './integrations/expressive-code-confi
34
34
  import catalogAssets from './integrations/catalog-assets.mjs';
35
35
  import runtimeDependencies from './integrations/runtime-dependencies.mjs';
36
36
  import { getRuntimePaths } from './integrations/runtime-paths.mjs';
37
- import { clientDependencies } from './integrations/client-dependencies.mjs';
37
+ import { collectClientDependencies } from './integrations/client-dependencies.mjs';
38
38
 
39
39
  const projectDirectory = process.env.PROJECT_DIR || process.cwd();
40
40
  const { runtimeDirectory } = getRuntimePaths(projectDirectory, process.env.CATALOG_DIR);
@@ -219,7 +219,7 @@ export default defineConfig({
219
219
  },
220
220
  optimizeDeps: {
221
221
  exclude: [],
222
- include: clientDependencies,
222
+ include: collectClientDependencies(),
223
223
  },
224
224
  },
225
225
  });
@@ -1,27 +1,126 @@
1
- // Core's browser components live in node_modules in an installed catalog. Vite
2
- // skips discovering dependencies imported from there, so explicitly pre-bundle
3
- // the graph and chat entrypoints, including their nested CommonJS dependencies.
4
- export const clientDependencies = [
5
- '@eventcatalog/visualiser',
6
- '@xyflow/react',
7
- '@ai-sdk/react',
8
- 'ai',
9
- 'lucide-react',
10
- '@heroicons/react/24/outline',
11
- '@heroicons/react/24/solid',
12
- '@heroicons/react/20/solid',
13
- '@headlessui/react',
14
- '@nanostores/react',
15
- 'nanostores',
16
- 'react',
17
- 'react-dom',
18
- 'semver',
19
- 'diff',
20
- 'diff2html',
21
- // ArchitectureGraph embeds also need these ready before the first request.
22
- // Discovering them mid-session can invalidate already-loaded chunks.
23
- 'd3-force',
24
- 'd3-selection',
25
- 'd3-zoom',
26
- 'd3-drag',
27
- ];
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getRuntimeAliases, packageDirectory } from './eventcatalog-runtime.mjs';
4
+
5
+ // In an installed catalog Core's browser components live in node_modules, and
6
+ // Vite never discovers dependencies imported from there. Anything it serves
7
+ // unoptimized reaches the browser raw, so a CommonJS package anywhere in the
8
+ // tree (e.g. react-markdown > hast-util-to-jsx-runtime > style-to-js) breaks
9
+ // hydration. Astro's own crawl (vitefu) only covers Core's direct CommonJS
10
+ // dependencies. Collect every dependency Core's browser code imports instead,
11
+ // so Vite pre-bundles each one together with its nested dependencies.
12
+ //
13
+ // Entrypoints are React components and processed <script> blocks in .astro
14
+ // files. Local and aliased JavaScript/TypeScript imports are followed. Like the
15
+ // server dependency scan this matches literal imports rather than parsing, so
16
+ // commented-out imports can over-include; computed specifiers are not found.
17
+
18
+ // Always needed by React islands, even before a component imports them directly.
19
+ const baseDependencies = ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime', 'react/jsx-dev-runtime'];
20
+
21
+ const scriptExtensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs'];
22
+ const typeOnlyImport = /\b(?:import|export)\s+type\s+[^'";]*?\bfrom\s*['"][^'"]+['"]/g;
23
+ const importSpecifier = /\b(?:from\s*|import\s*(?:\(\s*)?)['"]([^'"]+)['"]/g;
24
+ const astroScript = /<script\b([^>]*)>([\s\S]*?)<\/script>/g;
25
+
26
+ const packageName = (specifier) =>
27
+ specifier
28
+ .split('/')
29
+ .slice(0, specifier.startsWith('@') ? 2 : 1)
30
+ .join('/');
31
+
32
+ const isTestFile = (file) => /\.(?:test|spec)\.[cm]?[jt]sx?$/.test(file) || file.split(path.sep).includes('__tests__');
33
+
34
+ function resolveFile(file) {
35
+ const candidates = [
36
+ file,
37
+ ...scriptExtensions.map((extension) => file + extension),
38
+ ...scriptExtensions.map((extension) => path.join(file, `index${extension}`)),
39
+ ];
40
+ return candidates.find(
41
+ (candidate) =>
42
+ scriptExtensions.includes(path.extname(candidate)) && fs.existsSync(candidate) && fs.statSync(candidate).isFile()
43
+ );
44
+ }
45
+
46
+ function findPackageJson(name, fromDirectory) {
47
+ for (let directory = fromDirectory; ; directory = path.dirname(directory)) {
48
+ const file = path.join(directory, 'node_modules', name, 'package.json');
49
+ if (fs.existsSync(file)) return JSON.parse(fs.readFileSync(file, 'utf-8'));
50
+ if (path.dirname(directory) === directory) return;
51
+ }
52
+ }
53
+
54
+ // Astro excludes its framework packages (those built on astro) from
55
+ // pre-bundling because they ship raw .astro files. Match its detection.
56
+ function isAstroPackage(name, coreDirectory) {
57
+ const pkg = findPackageJson(name, coreDirectory);
58
+ return name === 'astro' || Boolean(pkg?.dependencies?.astro || pkg?.peerDependencies?.astro);
59
+ }
60
+
61
+ function listFiles(directory) {
62
+ return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
63
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') return [];
64
+ const file = path.join(directory, entry.name);
65
+ return entry.isDirectory() ? listFiles(file) : [file];
66
+ });
67
+ }
68
+
69
+ export function collectClientDependencies(coreDirectory = packageDirectory) {
70
+ const { dependencies = {} } = JSON.parse(fs.readFileSync(path.join(coreDirectory, '../package.json'), 'utf-8'));
71
+ // Only Core's own source aliases matter here; catalog-owned aliases point at
72
+ // the user's project, which Vite already scans normally.
73
+ const aliases = getRuntimeAliases({ projectDirectory: coreDirectory, runtimeDirectory: coreDirectory, coreDirectory }).filter(
74
+ ({ replacement }) => replacement.startsWith(path.join(coreDirectory, 'src'))
75
+ );
76
+ const resolveAlias = (specifier) => {
77
+ for (const { find, replacement } of aliases) {
78
+ if (find instanceof RegExp) {
79
+ if (find.test(specifier)) return specifier.replace(find, replacement);
80
+ } else if (specifier === find || specifier.startsWith(`${find}/`)) {
81
+ return replacement + specifier.slice(find.length);
82
+ }
83
+ }
84
+ };
85
+
86
+ const found = new Set(baseDependencies);
87
+ const visited = new Set();
88
+ const queue = [];
89
+
90
+ const scan = (code, importer) => {
91
+ for (const [, specifier] of code.replace(typeOnlyImport, '').matchAll(importSpecifier)) {
92
+ // Vite owns query imports (for example ?raw assets) and stylesheets.
93
+ if (/[?#]/.test(specifier) || /\.(?:css|scss|sass|less)$/.test(specifier)) continue;
94
+ const local = specifier.startsWith('.') ? path.resolve(path.dirname(importer), specifier) : resolveAlias(specifier);
95
+ if (local !== undefined) {
96
+ const file = resolveFile(local);
97
+ if (file && !visited.has(file)) queue.push(file);
98
+ } else if (Object.hasOwn(dependencies, packageName(specifier))) {
99
+ found.add(specifier);
100
+ }
101
+ }
102
+ };
103
+
104
+ for (const file of listFiles(path.join(coreDirectory, 'src'))) {
105
+ if (isTestFile(file)) continue;
106
+ if (/\.[jt]sx$/.test(file)) {
107
+ queue.push(file);
108
+ } else if (file.endsWith('.astro')) {
109
+ for (const [, attributes, code] of fs.readFileSync(file, 'utf-8').matchAll(astroScript)) {
110
+ // Inline, external and data scripts are not processed by Vite.
111
+ if (/\bis:inline\b|\bsrc\s*=|\btype\s*=\s*['"]?(?!module)/.test(attributes)) continue;
112
+ scan(code, file);
113
+ }
114
+ }
115
+ }
116
+
117
+ while (queue.length > 0) {
118
+ const file = queue.pop();
119
+ if (visited.has(file) || isTestFile(file)) continue;
120
+ visited.add(file);
121
+ scan(fs.readFileSync(file, 'utf-8'), file);
122
+ }
123
+
124
+ const astroPackages = new Set([...found].map(packageName).filter((name) => isAstroPackage(name, coreDirectory)));
125
+ return [...found].filter((specifier) => !astroPackages.has(packageName(specifier))).sort();
126
+ }
@@ -847,8 +847,10 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
847
847
 
848
848
  return (
849
849
  <>
850
- {/* Keyframes for fade-in animation - using constant to avoid re-injection */}
851
- <style>{CHAT_PANEL_STYLES}</style>
850
+ {/* Keyframes for fade-in animation - using constant to avoid re-injection.
851
+ Injected raw: React 18's server renderer escapes the `>` selectors in
852
+ text children, which the client doesn't, causing a hydration mismatch. */}
853
+ <style dangerouslySetInnerHTML={{ __html: CHAT_PANEL_STYLES }} />
852
854
 
853
855
  {/* Panel - hidden when fullscreen modal is open */}
854
856
  {!isFullscreen && (
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useRef, useMemo } from 'react';
1
+ import { useState, useEffect, useRef, useMemo, useId } from 'react';
2
2
 
3
3
  interface JSONSchemaViewerProps {
4
4
  schema: any;
@@ -293,7 +293,8 @@ const NestedVariantSelector = ({
293
293
  const SchemaProperty = ({ name, details, isRequired, level, isListItem = false, expand }: SchemaPropertyProps) => {
294
294
  const [isExpanded, setIsExpanded] = useState(expand);
295
295
  const [selectedVariantIndex, setSelectedVariantIndex] = useState(0);
296
- const contentId = useRef(`prop-${name}-${level}-${Math.random().toString(36).substring(2, 7)}`).current;
296
+ // useId keeps the server and client IDs identical during hydration.
297
+ const contentId = `prop-${name}-${level}-${useId()}`;
297
298
 
298
299
  useEffect(() => {
299
300
  setIsExpanded(expand);
@@ -4,7 +4,16 @@
4
4
  */
5
5
 
6
6
  import type { APIContext } from 'astro';
7
- import { convertToModelMessages, stepCountIs, streamText, tool, type LanguageModel, type ModelMessage, type UIMessage } from 'ai';
7
+ import {
8
+ convertToModelMessages,
9
+ createUIMessageStreamResponse,
10
+ isStepCount,
11
+ streamText,
12
+ toUIMessageStream,
13
+ tool,
14
+ type LanguageModel,
15
+ type UIMessage,
16
+ } from 'ai';
8
17
  import { join } from 'node:path';
9
18
  import { isEventCatalogScaleEnabled, isEventCatalogStarterEnabled } from '@utils/feature';
10
19
  import { getCollection, getEntry } from 'astro:content';
@@ -211,204 +220,198 @@ export const POST = async ({ request }: APIContext<{ question: string; messages:
211
220
  const referrer = request.headers.get('referer');
212
221
 
213
222
  try {
214
- const result = await streamText({
215
- model,
216
- system: getBaseSystemPrompt(referrer ?? ''),
217
- messages: await convertToModelMessages(messages),
218
- temperature: modelConfiguration?.temperature ?? 0.7,
219
- stopWhen: stepCountIs(5),
220
- // maxTokens: 4000, // Increased to handle large tool results
221
- onError: (error) => {
222
- console.error('[Chat] On error', error);
223
- },
224
- // maxOutputTokens: 40000,
225
- // tools: tools,
226
- tools: {
227
- getResources: tool({
228
- description: toolDescriptions.getResources,
229
- inputSchema: z.object({
230
- collection: collectionSchema.describe('The collection to get the resources from'),
231
- }),
232
- execute: async ({ collection }) => {
233
- const result = await getResourcesImpl({ collection });
234
- if ('error' in result) return result;
235
- return result.resources;
236
- },
223
+ const tools = {
224
+ getResources: tool({
225
+ description: toolDescriptions.getResources,
226
+ inputSchema: z.object({
227
+ collection: collectionSchema.describe('The collection to get the resources from'),
237
228
  }),
238
- getResource: tool({
239
- description: toolDescriptions.getResource,
240
- inputSchema: z.object({
241
- collection: collectionSchema.describe('The collection to get the resource from'),
242
- id: z.string().describe('The id of the resource to get'),
243
- version: z.string().describe('The version of the resource to get'),
244
- }),
245
- execute: async ({ collection, id, version }) => {
246
- return await getResourceImpl({ collection, id, version });
247
- },
229
+ execute: async ({ collection }) => {
230
+ const result = await getResourcesImpl({ collection });
231
+ if ('error' in result) return result;
232
+ return result.resources;
233
+ },
234
+ }),
235
+ getResource: tool({
236
+ description: toolDescriptions.getResource,
237
+ inputSchema: z.object({
238
+ collection: collectionSchema.describe('The collection to get the resource from'),
239
+ id: z.string().describe('The id of the resource to get'),
240
+ version: z.string().describe('The version of the resource to get'),
248
241
  }),
249
- getProducersAndConsumersFromSchema: tool({
250
- description: 'Use this tool to get the producers and consumers for a schema by its id and version',
251
- inputSchema: z.object({
252
- collection: messageCollectionSchema.describe('The collection to get the producers and consumers from'),
253
- id: z.string().describe('The id of the message to get the producers and consumers for'),
254
- version: z.string().describe('The version of the message to get the producers and consumers for'),
255
- }),
256
- execute: async ({ collection, id, version }) => {
257
- const resource = await getEntry(collection as any, `${id}-${version}`);
258
- const producers = resource.data.producers || [];
259
- const consumers = resource.data.consumers || [];
260
- return {
261
- producers,
262
- consumers,
263
- };
264
- },
242
+ execute: async ({ collection, id, version }) => {
243
+ return await getResourceImpl({ collection, id, version });
244
+ },
245
+ }),
246
+ getProducersAndConsumersFromSchema: tool({
247
+ description: 'Use this tool to get the producers and consumers for a schema by its id and version',
248
+ inputSchema: z.object({
249
+ collection: messageCollectionSchema.describe('The collection to get the producers and consumers from'),
250
+ id: z.string().describe('The id of the message to get the producers and consumers for'),
251
+ version: z.string().describe('The version of the message to get the producers and consumers for'),
265
252
  }),
266
- getMessagesProducedOrConsumedByResource: tool({
267
- description: toolDescriptions.getMessagesProducedOrConsumedByResource,
268
- inputSchema: z.object({
269
- resourceId: z.string().describe('The id of the resource to get the messages produced or consumed for'),
270
- resourceVersion: z.string().describe('The version of the resource to get the messages produced or consumed for'),
271
- resourceCollection: resourceCollectionSchema
272
- .describe('The collection of the resource to get the messages produced or consumed for')
273
- .default('services'),
274
- }),
275
- execute: async ({ resourceId, resourceVersion, resourceCollection }) => {
276
- return await getMessagesImpl({ resourceId, resourceVersion, resourceCollection });
277
- },
253
+ execute: async ({ collection, id, version }) => {
254
+ const resource = await getEntry(collection as any, `${id}-${version}`);
255
+ const producers = resource.data.producers || [];
256
+ const consumers = resource.data.consumers || [];
257
+ return {
258
+ producers,
259
+ consumers,
260
+ };
261
+ },
262
+ }),
263
+ getMessagesProducedOrConsumedByResource: tool({
264
+ description: toolDescriptions.getMessagesProducedOrConsumedByResource,
265
+ inputSchema: z.object({
266
+ resourceId: z.string().describe('The id of the resource to get the messages produced or consumed for'),
267
+ resourceVersion: z.string().describe('The version of the resource to get the messages produced or consumed for'),
268
+ resourceCollection: resourceCollectionSchema
269
+ .describe('The collection of the resource to get the messages produced or consumed for')
270
+ .default('services'),
278
271
  }),
279
- getProducerAndConsumerForMessage: tool({
280
- description: 'Use this tool to get the producers and consumers for a message by its id and version',
281
- inputSchema: z.object({
282
- messageId: z.string().describe('The id of the message to get the producers and consumers for'),
283
- messageVersion: z.string().describe('The version of the message to get the producers and consumers for'),
284
- messageCollection: messageCollectionSchema
285
- .describe('The collection of the message to get the producers and consumers for')
286
- .default('events'),
287
- }),
288
- execute: async ({ messageId, messageVersion, messageCollection }) => {
289
- const services = await getCollection('services');
290
- const message = await getEntry(messageCollection as any, `${messageId}-${messageVersion}`);
291
- const consumers = await getProducersOfMessage(services, message as any);
292
- return consumers;
293
- },
272
+ execute: async ({ resourceId, resourceVersion, resourceCollection }) => {
273
+ return await getMessagesImpl({ resourceId, resourceVersion, resourceCollection });
274
+ },
275
+ }),
276
+ getProducerAndConsumerForMessage: tool({
277
+ description: 'Use this tool to get the producers and consumers for a message by its id and version',
278
+ inputSchema: z.object({
279
+ messageId: z.string().describe('The id of the message to get the producers and consumers for'),
280
+ messageVersion: z.string().describe('The version of the message to get the producers and consumers for'),
281
+ messageCollection: messageCollectionSchema
282
+ .describe('The collection of the message to get the producers and consumers for')
283
+ .default('events'),
294
284
  }),
295
- getConsumersOfMessage: tool({
296
- description: 'Use this tool to get the consumers for a message by its id and version',
297
- inputSchema: z.object({
298
- messageId: z.string().describe('The id of the message to get the consumers for'),
299
- messageVersion: z.string().describe('The version of the message to get the consumers for'),
300
- messageCollection: messageCollectionSchema
301
- .describe('The collection of the message to get the consumers for')
302
- .default('events'),
303
- }),
304
- execute: async ({ messageId, messageVersion, messageCollection }) => {
305
- const services = await getCollection('services');
306
- const message = await getEntry(messageCollection as any, `${messageId}-${messageVersion}`);
307
- const consumers = await getConsumersOfMessage(services, message as any);
308
- return consumers;
309
- },
285
+ execute: async ({ messageId, messageVersion, messageCollection }) => {
286
+ const services = await getCollection('services');
287
+ const message = await getEntry(messageCollection as any, `${messageId}-${messageVersion}`);
288
+ const consumers = await getProducersOfMessage(services, message as any);
289
+ return consumers;
290
+ },
291
+ }),
292
+ getConsumersOfMessage: tool({
293
+ description: 'Use this tool to get the consumers for a message by its id and version',
294
+ inputSchema: z.object({
295
+ messageId: z.string().describe('The id of the message to get the consumers for'),
296
+ messageVersion: z.string().describe('The version of the message to get the consumers for'),
297
+ messageCollection: messageCollectionSchema
298
+ .describe('The collection of the message to get the consumers for')
299
+ .default('events'),
310
300
  }),
311
- getSchemaForResource: tool({
312
- description: toolDescriptions.getSchemaForResource,
313
- inputSchema: z.object({
314
- resourceId: z.string().describe('The id of the resource to get the schema for'),
315
- resourceVersion: z.string().describe('The version of the resource to get the schema for'),
316
- resourceCollection: resourceCollectionSchema
317
- .describe('The collection of the resource to get the schema for')
318
- .default('services'),
319
- }),
320
- execute: async ({ resourceId, resourceVersion, resourceCollection }) => {
321
- return await getSchemaImpl({ resourceId, resourceVersion, resourceCollection });
322
- },
301
+ execute: async ({ messageId, messageVersion, messageCollection }) => {
302
+ const services = await getCollection('services');
303
+ const message = await getEntry(messageCollection as any, `${messageId}-${messageVersion}`);
304
+ const consumers = await getConsumersOfMessage(services, message as any);
305
+ return consumers;
306
+ },
307
+ }),
308
+ getSchemaForResource: tool({
309
+ description: toolDescriptions.getSchemaForResource,
310
+ inputSchema: z.object({
311
+ resourceId: z.string().describe('The id of the resource to get the schema for'),
312
+ resourceVersion: z.string().describe('The version of the resource to get the schema for'),
313
+ resourceCollection: resourceCollectionSchema
314
+ .describe('The collection of the resource to get the schema for')
315
+ .default('services'),
323
316
  }),
324
- getDataProductInputs: tool({
325
- description: toolDescriptions.getDataProductInputs,
326
- inputSchema: z.object({
327
- dataProductId: z.string().describe('The id of the data product to get the inputs for'),
328
- dataProductVersion: z.string().describe('The version of the data product to get the inputs for'),
329
- }),
330
- execute: async ({ dataProductId, dataProductVersion }) => {
331
- return await getDataProductInputsImpl({ dataProductId, dataProductVersion });
332
- },
317
+ execute: async ({ resourceId, resourceVersion, resourceCollection }) => {
318
+ return await getSchemaImpl({ resourceId, resourceVersion, resourceCollection });
319
+ },
320
+ }),
321
+ getDataProductInputs: tool({
322
+ description: toolDescriptions.getDataProductInputs,
323
+ inputSchema: z.object({
324
+ dataProductId: z.string().describe('The id of the data product to get the inputs for'),
325
+ dataProductVersion: z.string().describe('The version of the data product to get the inputs for'),
333
326
  }),
334
- getDataProductOutputs: tool({
335
- description: toolDescriptions.getDataProductOutputs,
336
- inputSchema: z.object({
337
- dataProductId: z.string().describe('The id of the data product to get the outputs for'),
338
- dataProductVersion: z.string().describe('The version of the data product to get the outputs for'),
339
- }),
340
- execute: async ({ dataProductId, dataProductVersion }) => {
341
- return await getDataProductOutputsImpl({ dataProductId, dataProductVersion });
342
- },
327
+ execute: async ({ dataProductId, dataProductVersion }) => {
328
+ return await getDataProductInputsImpl({ dataProductId, dataProductVersion });
329
+ },
330
+ }),
331
+ getDataProductOutputs: tool({
332
+ description: toolDescriptions.getDataProductOutputs,
333
+ inputSchema: z.object({
334
+ dataProductId: z.string().describe('The id of the data product to get the outputs for'),
335
+ dataProductVersion: z.string().describe('The version of the data product to get the outputs for'),
343
336
  }),
344
- getArchitectureDiagramAsMermaid: tool({
345
- description: toolDescriptions.getArchitectureDiagramAsMermaid,
346
- inputSchema: z.object({
347
- resourceId: z.string().describe('The id of the resource to get the architecture diagram for'),
348
- resourceVersion: z.string().describe('The version of the resource to get the architecture diagram for'),
349
- resourceCollection: visualiserCollectionSchema
350
- .describe(
351
- 'The collection of the resource (events, commands, queries, services, domains, systems, flows, containers, data-products)'
352
- )
353
- .default('services'),
354
- }),
355
- execute: async ({ resourceId, resourceVersion, resourceCollection }) => {
356
- return await getArchitectureDiagramImpl({ resourceId, resourceVersion, resourceCollection });
357
- },
337
+ execute: async ({ dataProductId, dataProductVersion }) => {
338
+ return await getDataProductOutputsImpl({ dataProductId, dataProductVersion });
339
+ },
340
+ }),
341
+ getArchitectureDiagramAsMermaid: tool({
342
+ description: toolDescriptions.getArchitectureDiagramAsMermaid,
343
+ inputSchema: z.object({
344
+ resourceId: z.string().describe('The id of the resource to get the architecture diagram for'),
345
+ resourceVersion: z.string().describe('The version of the resource to get the architecture diagram for'),
346
+ resourceCollection: visualiserCollectionSchema
347
+ .describe(
348
+ 'The collection of the resource (events, commands, queries, services, domains, systems, flows, containers, data-products)'
349
+ )
350
+ .default('services'),
358
351
  }),
359
- getCustomDocs: tool({
360
- description: toolDescriptions.getCustomDocs,
361
- inputSchema: z.object({
362
- cursor: z.string().optional().describe('Pagination cursor from previous response'),
363
- search: z.string().optional().describe('Search term to filter docs by title, id, or summary (case-insensitive)'),
364
- }),
365
- execute: async ({ cursor, search }) => {
366
- return await getCustomDocsImpl({ cursor, search });
367
- },
352
+ execute: async ({ resourceId, resourceVersion, resourceCollection }) => {
353
+ return await getArchitectureDiagramImpl({ resourceId, resourceVersion, resourceCollection });
354
+ },
355
+ }),
356
+ getCustomDocs: tool({
357
+ description: toolDescriptions.getCustomDocs,
358
+ inputSchema: z.object({
359
+ cursor: z.string().optional().describe('Pagination cursor from previous response'),
360
+ search: z.string().optional().describe('Search term to filter docs by title, id, or summary (case-insensitive)'),
368
361
  }),
369
- searchCustomDocs: tool({
370
- description: toolDescriptions.searchCustomDocs,
371
- inputSchema: z.object({
372
- query: z.string().describe('Full-text search query, e.g. keywords describing the topic to find'),
373
- limit: z.number().optional().describe('Maximum number of results to return (default 10)'),
374
- }),
375
- execute: async ({ query, limit }) => {
376
- return await searchCustomDocsImpl({ query, limit });
377
- },
362
+ execute: async ({ cursor, search }) => {
363
+ return await getCustomDocsImpl({ cursor, search });
364
+ },
365
+ }),
366
+ searchCustomDocs: tool({
367
+ description: toolDescriptions.searchCustomDocs,
368
+ inputSchema: z.object({
369
+ query: z.string().describe('Full-text search query, e.g. keywords describing the topic to find'),
370
+ limit: z.number().optional().describe('Maximum number of results to return (default 10)'),
378
371
  }),
379
- getCustomDoc: tool({
380
- description: toolDescriptions.getCustomDoc,
381
- inputSchema: z.object({
382
- id: z.string().describe('The id or slug of the custom documentation page'),
383
- section: z.string().optional().describe('Optional section heading to return only that section of the page'),
384
- }),
385
- execute: async ({ id, section }) => {
386
- return await getCustomDocImpl({ id, section });
387
- },
372
+ execute: async ({ query, limit }) => {
373
+ return await searchCustomDocsImpl({ query, limit });
374
+ },
375
+ }),
376
+ getCustomDoc: tool({
377
+ description: toolDescriptions.getCustomDoc,
378
+ inputSchema: z.object({
379
+ id: z.string().describe('The id or slug of the custom documentation page'),
380
+ section: z.string().optional().describe('Optional section heading to return only that section of the page'),
388
381
  }),
389
- suggestFollowUpQuestions: tool({
390
- description:
391
- 'Use this tool after answering a question to suggest 2-3 relevant follow-up questions the user might want to ask. These will be displayed as clickable suggestions.',
392
- inputSchema: z.object({
393
- questions: z
394
- .array(z.string())
395
- .min(1)
396
- .max(3)
397
- .describe('Array of 2-3 follow-up questions relevant to the conversation'),
398
- }),
399
- execute: async ({ questions }) => {
400
- // This tool doesn't need to do anything - it just returns the questions
401
- // which will be captured by the UI
402
- return { suggestions: questions };
403
- },
382
+ execute: async ({ id, section }) => {
383
+ return await getCustomDocImpl({ id, section });
384
+ },
385
+ }),
386
+ suggestFollowUpQuestions: tool({
387
+ description:
388
+ 'Use this tool after answering a question to suggest 2-3 relevant follow-up questions the user might want to ask. These will be displayed as clickable suggestions.',
389
+ inputSchema: z.object({
390
+ questions: z.array(z.string()).min(1).max(3).describe('Array of 2-3 follow-up questions relevant to the conversation'),
404
391
  }),
405
- ...extendedTools,
392
+ execute: async ({ questions }) => {
393
+ // This tool doesn't need to do anything - it just returns the questions
394
+ // which will be captured by the UI
395
+ return { suggestions: questions };
396
+ },
397
+ }),
398
+ ...extendedTools,
399
+ };
400
+
401
+ const result = streamText({
402
+ model,
403
+ instructions: getBaseSystemPrompt(referrer ?? ''),
404
+ messages: await convertToModelMessages(messages),
405
+ temperature: modelConfiguration?.temperature ?? 0.7,
406
+ stopWhen: isStepCount(5),
407
+ onError: (error) => {
408
+ console.error('[Chat] On error', error);
406
409
  },
410
+ tools,
407
411
  });
408
- return result.toUIMessageStreamResponse({
409
- headers: {
410
- 'Content-Type': 'text/event-stream',
411
- },
412
+
413
+ return createUIMessageStreamResponse({
414
+ stream: toUIMessageStream({ stream: result.stream, tools }),
412
415
  });
413
416
  } catch (err: any) {
414
417
  console.error('[Chat] Error during streaming:', err);
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "license": "SEE LICENSE IN LICENSE",
9
9
  "type": "module",
10
- "version": "4.12.0-beta.3",
10
+ "version": "4.12.0-beta.5",
11
11
  "publishConfig": {
12
12
  "access": "public"
13
13
  },
@@ -45,7 +45,7 @@
45
45
  "dist/"
46
46
  ],
47
47
  "dependencies": {
48
- "@ai-sdk/react": "^3.0.17",
48
+ "@ai-sdk/react": "^4.0.109",
49
49
  "@astrojs/markdown-remark": "^7.3.1",
50
50
  "@astrojs/mdx": "^8.0.1",
51
51
  "@astrojs/node": "^11.1.6",
@@ -74,7 +74,7 @@
74
74
  "@tailwindcss/vite": "^4.3.1",
75
75
  "@tanstack/react-table": "^8.17.3",
76
76
  "@xyflow/react": "^12.3.6",
77
- "ai": "^6.0.17",
77
+ "ai": "^7.0.106",
78
78
  "astro": "7.3.3",
79
79
  "astro-expressive-code": "^0.44.0",
80
80
  "astro-seo": "^0.8.4",
@@ -134,8 +134,8 @@
134
134
  "uuid": "^11.1.1",
135
135
  "zod": "^4.3.6",
136
136
  "@eventcatalog/linter": "1.1.20",
137
- "@eventcatalog/visualiser": "^4.1.4",
138
- "@eventcatalog/sdk": "2.29.1"
137
+ "@eventcatalog/sdk": "2.29.1",
138
+ "@eventcatalog/visualiser": "^4.1.4"
139
139
  },
140
140
  "devDependencies": {
141
141
  "@astrojs/check": "^0.9.10",