@eventcatalog/core 4.0.0-beta.1 → 4.0.0-beta.2

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 (43) hide show
  1. package/bin/eventcatalog.config.d.ts +1 -1
  2. package/dist/analytics/analytics.cjs +1 -1
  3. package/dist/analytics/analytics.js +2 -2
  4. package/dist/analytics/log-build.cjs +1 -1
  5. package/dist/analytics/log-build.js +3 -3
  6. package/dist/{chunk-U5OTNDVQ.js → chunk-24K6JJV5.js} +1 -1
  7. package/dist/{chunk-MBVTS76Q.js → chunk-7NOXTLJP.js} +1 -1
  8. package/dist/{chunk-M2ZRT7KQ.js → chunk-FLLYUYF2.js} +1 -1
  9. package/dist/{chunk-JTZT2SDF.js → chunk-IK6AW6IC.js} +1 -1
  10. package/dist/{chunk-TZTPGQGL.js → chunk-JRCXVY3E.js} +1 -1
  11. package/dist/constants.cjs +1 -1
  12. package/dist/constants.js +1 -1
  13. package/dist/eventcatalog.cjs +1 -1
  14. package/dist/eventcatalog.config.d.cts +40 -7
  15. package/dist/eventcatalog.config.d.ts +40 -7
  16. package/dist/eventcatalog.js +5 -5
  17. package/dist/generate.cjs +1 -1
  18. package/dist/generate.js +3 -3
  19. package/dist/utils/cli-logger.cjs +1 -1
  20. package/dist/utils/cli-logger.js +2 -2
  21. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +16 -2
  22. package/eventcatalog/src/components/CopyAsMarkdown.tsx +6 -57
  23. package/eventcatalog/src/enterprise/ai/chat-api.ts +4 -2
  24. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +26 -7
  25. package/eventcatalog/src/enterprise/feature.ts +0 -4
  26. package/eventcatalog/src/enterprise/integrations/eventcatalog-features.ts +0 -9
  27. package/eventcatalog/src/enterprise/tools/catalog-tools.ts +6 -1
  28. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +343 -282
  29. package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +6 -81
  30. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +0 -8
  31. package/eventcatalog/src/stores/sidebar-store/state.ts +4 -4
  32. package/eventcatalog/src/utils/feature.ts +0 -2
  33. package/package.json +3 -3
  34. package/eventcatalog/src/enterprise/print/_message.data.ts +0 -63
  35. package/eventcatalog/src/enterprise/print/components/PrintHeader.astro +0 -183
  36. package/eventcatalog/src/enterprise/print/components/PrintLayout.astro +0 -271
  37. package/eventcatalog/src/enterprise/print/components/PrintParticipantsTable.astro +0 -64
  38. package/eventcatalog/src/enterprise/print/components/PrintSchemaPropertiesTable.astro +0 -65
  39. package/eventcatalog/src/enterprise/print/components/PrintSchemaViewer.tsx +0 -55
  40. package/eventcatalog/src/enterprise/print/components/PrintSection.astro +0 -17
  41. package/eventcatalog/src/enterprise/print/message.astro +0 -353
  42. package/eventcatalog/src/enterprise/print/utils.ts +0 -58
  43. package/eventcatalog/src/utils/sidebar-visibility.ts +0 -41
@@ -1,353 +0,0 @@
1
- ---
2
- import { render } from 'astro:content';
3
- import PrintLayout from './components/PrintLayout.astro';
4
- import PrintHeader from './components/PrintHeader.astro';
5
- import PrintSection from './components/PrintSection.astro';
6
- import PrintSchemaViewer from './components/PrintSchemaViewer';
7
- import config from '@config';
8
- import { PrintPage } from './_message.data';
9
- import fs from 'node:fs/promises';
10
- import { getAbsoluteFilePathForAstroFile, isAvroSchema } from '@utils/files';
11
- import components from '@components/MDX/components';
12
- import { getOwnerDetails } from '@utils/collections/owners';
13
- import { satisfies, collectionToResourceMap, getPointerField } from '@utils/collections/util';
14
- import { getDomains } from '@utils/collections/domains';
15
- import { getExamplesForResource } from '@utils/collections/examples';
16
- import { hydrateParticipants } from './utils';
17
- import PrintSchemaPropertiesTable from './components/PrintSchemaPropertiesTable.astro';
18
- import PrintParticipantsTable from './components/PrintParticipantsTable.astro';
19
- import yaml from 'js-yaml';
20
-
21
- export const prerender = PrintPage.prerender;
22
- export const getStaticPaths = PrintPage.getStaticPaths;
23
-
24
- const props = await PrintPage.getData(Astro);
25
- const { Content } = await render(props);
26
-
27
- const messageType = (collectionToResourceMap as Record<string, string>)[props.collection] as 'event' | 'command' | 'query';
28
- const catalogName = config?.title || 'EventCatalog';
29
-
30
- // Get producers and consumers
31
- const producers = props.data.producers || [];
32
- const consumers = props.data.consumers || [];
33
-
34
- // Hydrate message owners
35
- const hydratedOwners = await getOwnerDetails(props.data.owners || []);
36
-
37
- const messageId = props.data.id;
38
- const latestVersion = props.data.latestVersion || props.data.version;
39
-
40
- const [producersWithOwners, consumersWithOwners] = await Promise.all([
41
- hydrateParticipants(producers, 'sends', messageId, latestVersion),
42
- hydrateParticipants(consumers, 'receives', messageId, latestVersion),
43
- ]);
44
-
45
- // Get schema content from schemaPath frontmatter property
46
- let schemaContent: string | null = null;
47
- let schemaFormat: string | null = null;
48
- let schemaExtension: string = 'json';
49
- let schemaParsed: any = null;
50
- let schemaIsAvro: boolean = false;
51
-
52
- try {
53
- if (props.data.schemaPath) {
54
- const schemaPath = getAbsoluteFilePathForAstroFile(props.filePath, props.data.schemaPath);
55
- schemaContent = await fs.readFile(schemaPath, 'utf-8');
56
- const ext = schemaPath.split('.').pop() || '';
57
- schemaExtension = ext;
58
- schemaIsAvro = isAvroSchema(schemaPath);
59
- schemaFormat =
60
- ext === 'json' ? 'JSON' : ext === 'avsc' ? 'Avro' : ext === 'yaml' || ext === 'yml' ? 'YAML' : ext.toUpperCase();
61
-
62
- // Parse schema for the property viewer
63
- try {
64
- if (ext === 'yaml' || ext === 'yml') {
65
- schemaParsed = yaml.load(schemaContent);
66
- } else {
67
- schemaParsed = JSON.parse(schemaContent);
68
- }
69
- } catch {}
70
-
71
- // Pretty-print JSON using the already-parsed object
72
- if (schemaParsed && (ext === 'json' || ext === 'avsc')) {
73
- schemaContent = JSON.stringify(schemaParsed, null, 2);
74
- }
75
- }
76
- } catch {
77
- // Schema loading is best-effort
78
- }
79
-
80
- // Get examples
81
- const messageExamples = getExamplesForResource(props);
82
-
83
- const dotColor = messageType === 'event' ? '#ea580c' : messageType === 'command' ? '#2563eb' : '#16a34a';
84
- const stamp = props.data.draft ? 'draft' : props.data.deprecated ? 'deprecated' : undefined;
85
-
86
- // Compute consumer counts per version using already-loaded consumers
87
- const allVersions = [...new Set([props.data.version, ...(props.data.versions || [])])];
88
- const sortedVersions = [...allVersions].sort((a, b) => b.localeCompare(a, undefined, { numeric: true }));
89
-
90
- const versionConsumerCounts = new Map<string, number>();
91
- for (const v of allVersions) versionConsumerCounts.set(v, 0);
92
-
93
- // Extract consumer pointers from the already-hydrated consumers (services + data-products)
94
- const consumerPointers: { id: string; version?: string }[] = [];
95
- for (const c of consumers) {
96
- const field = getPointerField(c.collection, 'receives');
97
- for (const pointer of c.data?.[field] || []) {
98
- if (pointer.id === messageId) consumerPointers.push(pointer);
99
- }
100
- }
101
- // Also check domain-level receives (getDomains is cached internally)
102
- const allDomains = await getDomains({ getAllVersions: false });
103
- for (const domain of allDomains) {
104
- for (const pointer of (domain.data as any).receives || []) {
105
- if (pointer.id === messageId) consumerPointers.push(pointer);
106
- }
107
- }
108
-
109
- for (const pointer of consumerPointers) {
110
- let matched: string | undefined;
111
- if (!pointer.version || pointer.version === 'latest') {
112
- matched = latestVersion;
113
- } else {
114
- matched = sortedVersions.find((v) => satisfies(v, pointer.version as string));
115
- }
116
- if (matched && versionConsumerCounts.has(matched)) {
117
- versionConsumerCounts.set(matched, (versionConsumerCounts.get(matched) || 0) + 1);
118
- }
119
- }
120
- ---
121
-
122
- <PrintLayout title={`${props.data.name} — ${catalogName}`} stamp={stamp}>
123
- <PrintHeader
124
- name={props.data.name}
125
- version={props.data.version}
126
- type={messageType}
127
- summary={props.data.summary}
128
- catalogName={catalogName}
129
- draft={props.data.draft}
130
- deprecated={props.data.deprecated}
131
- />
132
-
133
- <!-- Overview cards -->
134
- <div class="grid grid-cols-5 gap-3 mb-9">
135
- <div class="bg-slate-50 border border-slate-200 rounded-lg px-4 py-3">
136
- <div class="text-[0.6875rem] font-semibold uppercase tracking-wider text-slate-400 mb-1">Type</div>
137
- <div class="text-sm font-medium text-slate-700 capitalize">{messageType}</div>
138
- </div>
139
- <div class="bg-slate-50 border border-slate-200 rounded-lg px-4 py-3">
140
- <div class="text-[0.6875rem] font-semibold uppercase tracking-wider text-slate-400 mb-1">Latest Version</div>
141
- <div class="text-sm font-medium text-slate-700">{latestVersion}</div>
142
- </div>
143
- <div class="bg-slate-50 border border-slate-200 rounded-lg px-4 py-3">
144
- <div class="text-[0.6875rem] font-semibold uppercase tracking-wider text-slate-400 mb-1">Producers</div>
145
- <div class="text-sm font-medium text-slate-700">{producers.length}</div>
146
- </div>
147
- <div class="bg-slate-50 border border-slate-200 rounded-lg px-4 py-3">
148
- <div class="text-[0.6875rem] font-semibold uppercase tracking-wider text-slate-400 mb-1">Consumers</div>
149
- <div class="text-sm font-medium text-slate-700">{consumers.length}</div>
150
- </div>
151
- <div class="bg-slate-50 border border-slate-200 rounded-lg px-4 py-3">
152
- <div class="text-[0.6875rem] font-semibold uppercase tracking-wider text-slate-400 mb-1">Versions</div>
153
- <div class="text-sm font-medium text-slate-700">{props.data.versions?.length || 1}</div>
154
- </div>
155
- </div>
156
-
157
- {
158
- hydratedOwners.length > 0 && (
159
- <PrintSection title="Owners">
160
- <table class="w-full text-sm border-separate border-spacing-0 border border-slate-200 rounded-lg overflow-hidden table-fixed">
161
- <thead>
162
- <tr>
163
- <th class="w-[50%] text-left font-semibold text-slate-500 px-4 py-2.5 bg-slate-100 border-b border-slate-200 text-[0.6875rem] uppercase tracking-wider">
164
- Name
165
- </th>
166
- <th class="w-[20%] text-left font-semibold text-slate-500 px-4 py-2.5 bg-slate-100 border-b border-slate-200 text-[0.6875rem] uppercase tracking-wider">
167
- Type
168
- </th>
169
- <th class="w-[30%] text-left font-semibold text-slate-500 px-4 py-2.5 bg-slate-100 border-b border-slate-200 text-[0.6875rem] uppercase tracking-wider">
170
- Role
171
- </th>
172
- </tr>
173
- </thead>
174
- <tbody>
175
- {hydratedOwners.map((owner, i) => (
176
- <tr>
177
- <td
178
- class={`px-4 py-2.5 font-medium text-slate-700 ${i < hydratedOwners.length - 1 ? 'border-b border-slate-100' : ''}`}
179
- >
180
- {owner.name}
181
- </td>
182
- <td class={`px-4 py-2.5 text-slate-500 ${i < hydratedOwners.length - 1 ? 'border-b border-slate-100' : ''}`}>
183
- <span class="inline-flex items-center gap-1.5 text-sm">
184
- {owner.type === 'teams' ? (
185
- <svg
186
- xmlns="http://www.w3.org/2000/svg"
187
- width="13"
188
- height="13"
189
- viewBox="0 0 24 24"
190
- fill="none"
191
- stroke="currentColor"
192
- stroke-width="2"
193
- stroke-linecap="round"
194
- stroke-linejoin="round"
195
- class="text-slate-400"
196
- >
197
- <path d="M18 21a8 8 0 0 0-16 0" />
198
- <circle cx="10" cy="8" r="5" />
199
- <path d="M22 20c0-3.37-2-6.5-4-8a5 5 0 0 0-.45-8.3" />
200
- </svg>
201
- ) : (
202
- <svg
203
- xmlns="http://www.w3.org/2000/svg"
204
- width="13"
205
- height="13"
206
- viewBox="0 0 24 24"
207
- fill="none"
208
- stroke="currentColor"
209
- stroke-width="2"
210
- stroke-linecap="round"
211
- stroke-linejoin="round"
212
- class="text-slate-400"
213
- >
214
- <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
215
- <circle cx="12" cy="7" r="4" />
216
- </svg>
217
- )}
218
- {owner.type === 'teams' ? 'Team' : owner.type === 'users' ? 'User' : '—'}
219
- </span>
220
- </td>
221
- <td class={`px-4 py-2.5 text-slate-500 ${i < hydratedOwners.length - 1 ? 'border-b border-slate-100' : ''}`}>
222
- {owner.role || '—'}
223
- </td>
224
- </tr>
225
- ))}
226
- </tbody>
227
- </table>
228
- </PrintSection>
229
- )
230
- }
231
-
232
- <PrintSection title="Producers" sectionId="producers">
233
- <PrintParticipantsTable
234
- participants={producersWithOwners}
235
- dotColor={dotColor}
236
- emptyMessage="No producers found for this message."
237
- />
238
- </PrintSection>
239
-
240
- <PrintSection title="Consumers" sectionId="consumers">
241
- <PrintParticipantsTable
242
- participants={consumersWithOwners}
243
- dotColor={dotColor}
244
- emptyMessage="No consumers found for this message."
245
- />
246
- </PrintSection>
247
-
248
- {
249
- (props.data.versions?.length || 0) > 0 && (
250
- <PrintSection title="Version History" sectionId="versions">
251
- <table class="w-full text-sm border-separate border-spacing-0 border border-slate-200 rounded-lg overflow-hidden table-fixed">
252
- <thead>
253
- <tr>
254
- <th class="w-[50%] text-left font-semibold text-slate-500 px-4 py-2.5 bg-slate-100 border-b border-slate-200 text-[0.6875rem] uppercase tracking-wider">
255
- Version
256
- </th>
257
- <th class="w-[20%] text-left font-semibold text-slate-500 px-4 py-2.5 bg-slate-100 border-b border-slate-200 text-[0.6875rem] uppercase tracking-wider">
258
- Status
259
- </th>
260
- <th class="w-[30%] text-left font-semibold text-slate-500 px-4 py-2.5 bg-slate-100 border-b border-slate-200 text-[0.6875rem] uppercase tracking-wider">
261
- Consumers
262
- </th>
263
- </tr>
264
- </thead>
265
- <tbody>
266
- {allVersions.map((v, i) => (
267
- <tr>
268
- <td
269
- class={`px-4 py-2.5 font-medium text-slate-700 ${i < allVersions.length - 1 ? 'border-b border-slate-100' : ''}`}
270
- >
271
- <span class="flex items-center gap-2">
272
- <span class="w-1.5 h-1.5 rounded-full shrink-0" style={`background: ${i === 0 ? dotColor : '#94a3b8'};`} />v
273
- {v}
274
- </span>
275
- </td>
276
- <td class={`px-4 py-2.5 text-slate-500 ${i < allVersions.length - 1 ? 'border-b border-slate-100' : ''}`}>
277
- {i === 0 ? (
278
- <span class="inline-flex items-center gap-1 text-xs font-semibold text-green-700 bg-green-50 border border-green-200 px-2 py-0.5 rounded-full">
279
- Current
280
- </span>
281
- ) : (
282
- <span class="inline-flex items-center gap-1 text-xs font-semibold text-slate-500 bg-slate-50 border border-slate-200 px-2 py-0.5 rounded-full">
283
- Previous
284
- </span>
285
- )}
286
- </td>
287
- <td class={`px-4 py-2.5 text-slate-700 ${i < allVersions.length - 1 ? 'border-b border-slate-100' : ''}`}>
288
- {versionConsumerCounts.get(v) || 0}
289
- </td>
290
- </tr>
291
- ))}
292
- </tbody>
293
- </table>
294
- </PrintSection>
295
- )
296
- }
297
-
298
- <PrintSection title="Documentation" sectionId="documentation">
299
- <div class="prose prose-slate prose-sm max-w-none">
300
- <Content
301
- components={{
302
- ...components(props),
303
- NodeGraph: () => null,
304
- Flow: () => null,
305
- EntityMap: () => null,
306
- Tiles: () => null,
307
- Tile: () => null,
308
- }}
309
- />
310
- </div>
311
- </PrintSection>
312
-
313
- {
314
- schemaContent && (
315
- <PrintSection title="Schema" sectionId="schema">
316
- <PrintSchemaViewer client:load content={schemaContent} format={schemaFormat || 'Schema'} extension={schemaExtension} />
317
- </PrintSection>
318
- )
319
- }
320
-
321
- {
322
- schemaParsed && (
323
- <PrintSection title="Schema Properties" sectionId="schema">
324
- <PrintSchemaPropertiesTable schema={schemaParsed} isAvro={schemaIsAvro} />
325
- </PrintSection>
326
- )
327
- }
328
-
329
- {
330
- messageExamples.length > 0 && (
331
- <PrintSection title="Examples" sectionId="examples">
332
- <div class="space-y-5">
333
- {messageExamples.map((example) => (
334
- <div>
335
- {example.summary && <p class="text-sm text-slate-500 mb-2">{example.summary}</p>}
336
- <PrintSchemaViewer
337
- client:load
338
- content={example.content}
339
- format={`${example.title} (.${example.extension})`}
340
- extension={example.extension}
341
- />
342
- </div>
343
- ))}
344
- </div>
345
- </PrintSection>
346
- )
347
- }
348
-
349
- <div class="mt-12 pt-6 border-t border-slate-200 flex justify-between items-center text-xs text-slate-400">
350
- <span>Generated from {catalogName}</span>
351
- <span>EventCatalog</span>
352
- </div>
353
- </PrintLayout>
@@ -1,58 +0,0 @@
1
- /**
2
- * Licensed under the EventCatalog Commercial License.
3
- * See /packages/core/eventcatalog/src/enterprise/LICENSE
4
- */
5
-
6
- import { getOwnerNames } from '@utils/collections/owners';
7
- import { satisfies, getResourceTypeLabel, getPointerField } from '@utils/collections/util';
8
- import { getDomainsForService } from '@utils/collections/domains';
9
-
10
- export interface HydratedParticipant {
11
- name: string;
12
- resourceType: string;
13
- resourceVersion: string;
14
- messageVersion: string;
15
- isLatest: boolean;
16
- owners: string[];
17
- domain: string | undefined;
18
- }
19
-
20
- /**
21
- * Hydrates a list of producer/consumer collection entries with owner names,
22
- * domain info, message version, and isLatest badge.
23
- */
24
- export async function hydrateParticipants(
25
- list: any[],
26
- direction: 'sends' | 'receives',
27
- messageId: string,
28
- latestVersion: string
29
- ): Promise<HydratedParticipant[]> {
30
- return Promise.all(
31
- list.map(async (s: any) => {
32
- const field = getPointerField(s.collection, direction);
33
- const pointers = s.data?.[field] || [];
34
- const pointer = pointers.find((p: any) => p.id === messageId);
35
- const messageVersion = pointer?.version || 'latest';
36
- const isLatest = !pointer?.version || pointer.version === 'latest' || satisfies(latestVersion, pointer.version);
37
-
38
- // Use getDomainsForService for service participants (getDomains is cached internally)
39
- let domain: string | undefined;
40
- if (s.collection === 'services') {
41
- const domains = await getDomainsForService(s);
42
- if (domains.length > 0) {
43
- domain = domains.map((d) => d.data.name || d.data.id).join(', ');
44
- }
45
- }
46
-
47
- return {
48
- name: s.data?.name || s.id,
49
- resourceType: getResourceTypeLabel(s.collection),
50
- resourceVersion: s.data?.version || s.version,
51
- messageVersion,
52
- isLatest,
53
- owners: await getOwnerNames(s.data?.owners || []),
54
- domain,
55
- };
56
- })
57
- );
58
- }
@@ -1,41 +0,0 @@
1
- export type SidebarVisibilityConfig = {
2
- id: string;
3
- visible: boolean;
4
- };
5
-
6
- export type SidebarConfigurableItem = {
7
- id: string;
8
- aliases?: string[];
9
- visible?: boolean;
10
- };
11
-
12
- const getVisibilityOption = <T extends SidebarConfigurableItem>(
13
- item: T,
14
- configuration: SidebarVisibilityConfig[]
15
- ): SidebarVisibilityConfig | undefined => {
16
- const exactMatch = configuration.find((option) => option.id === item.id);
17
-
18
- if (exactMatch) {
19
- return exactMatch;
20
- }
21
-
22
- return configuration.find((option) => item.aliases?.includes(option.id));
23
- };
24
-
25
- export const isSidebarItemVisible = <T extends SidebarConfigurableItem>(
26
- item: T,
27
- configuration: SidebarVisibilityConfig[] = []
28
- ): boolean => {
29
- const visibilityOption = getVisibilityOption(item, configuration);
30
-
31
- if (visibilityOption) {
32
- return visibilityOption.visible;
33
- }
34
-
35
- return item.visible ?? true;
36
- };
37
-
38
- export const filterSidebarItems = <T extends SidebarConfigurableItem>(
39
- items: T[],
40
- configuration: SidebarVisibilityConfig[] = []
41
- ): T[] => items.filter((item) => isSidebarItemVisible(item, configuration));