@eventcatalog/core 3.44.2 → 3.46.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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-THDZCUFV.js → chunk-DOHA5HNJ.js} +1 -1
- package/dist/{chunk-BLJ5FRR3.js → chunk-FNOYJEUK.js} +1 -1
- package/dist/{chunk-LIIOK6SZ.js → chunk-JS6IYB55.js} +1 -1
- package/dist/{chunk-IU3D7JRW.js → chunk-TLLUDBO4.js} +1 -1
- package/dist/{chunk-RUACTEJR.js → chunk-X4AESI6E.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.config.d.cts +29 -0
- package/dist/eventcatalog.config.d.ts +29 -0
- package/dist/eventcatalog.js +10 -10
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +7 -10
- package/eventcatalog/ec.config.mjs +20 -0
- package/eventcatalog/src/components/MDX/SchemaViewer/SchemaViewerPortal.tsx +1 -1
- package/eventcatalog/src/components/MDX/SchemaViewer/SchemaViewerRoot.astro +19 -47
- package/eventcatalog/src/components/MDX/SchemaViewer/schema-viewer-utils.spec.ts +53 -0
- package/eventcatalog/src/components/MDX/SchemaViewer/schema-viewer-utils.ts +133 -0
- package/eventcatalog/src/content.config.ts +65 -0
- package/eventcatalog/src/enterprise/api/schemas/[collection]/[id]/[version]/index.ts +42 -50
- package/eventcatalog/src/enterprise/tools/catalog-tools.ts +23 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -1
- package/eventcatalog/src/pages/docs/llm/schemas.txt.ts +25 -17
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +33 -16
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +18 -8
- package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +45 -21
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +25 -2
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +1 -0
- package/eventcatalog/src/stores/sidebar-store/state.ts +3 -0
- package/eventcatalog/src/utils/collections/schema-loader.ts +523 -0
- package/eventcatalog/src/utils/files.ts +1 -1
- package/package.json +4 -4
|
@@ -9,6 +9,7 @@ import fs from 'fs';
|
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import { userTeamDirectoryLoader } from './enterprise/directory/user-team-directory';
|
|
11
11
|
import config from '@config';
|
|
12
|
+
import { schemaLoader } from './utils/collections/schema-loader';
|
|
12
13
|
|
|
13
14
|
// Enterprise Collections
|
|
14
15
|
import { customPagesSchema, resourceDocsSchema, resourceDocCategoriesSchema } from './enterprise/collections';
|
|
@@ -68,6 +69,17 @@ const channelPointer = z
|
|
|
68
69
|
})
|
|
69
70
|
.extend(pointer.shape);
|
|
70
71
|
|
|
72
|
+
const schemaPointer = z.object({
|
|
73
|
+
id: z.string().optional(),
|
|
74
|
+
ref: z.string().optional(),
|
|
75
|
+
file: z.string().optional(),
|
|
76
|
+
path: z.string().optional(),
|
|
77
|
+
name: z.string().optional(),
|
|
78
|
+
format: z.string().optional(),
|
|
79
|
+
environments: z.array(z.string()).optional(),
|
|
80
|
+
default: z.boolean().optional(),
|
|
81
|
+
});
|
|
82
|
+
|
|
71
83
|
const sendsPointer = z.object({
|
|
72
84
|
id: z.string(),
|
|
73
85
|
version: z.string().optional().default('latest'),
|
|
@@ -375,6 +387,7 @@ const events = defineCollection({
|
|
|
375
387
|
producers: z.array(reference('services')).optional(),
|
|
376
388
|
consumers: z.array(reference('services')).optional(),
|
|
377
389
|
channels: z.array(channelPointer).optional(),
|
|
390
|
+
schemas: z.array(schemaPointer).optional(),
|
|
378
391
|
messageChannels: z.array(reference('channels')).optional(),
|
|
379
392
|
detailsPanel: messageDetailsPanelPropertySchema.optional(),
|
|
380
393
|
})
|
|
@@ -397,6 +410,7 @@ const commands = defineCollection({
|
|
|
397
410
|
producers: z.array(reference('services')).optional(),
|
|
398
411
|
consumers: z.array(reference('services')).optional(),
|
|
399
412
|
channels: z.array(channelPointer).optional(),
|
|
413
|
+
schemas: z.array(schemaPointer).optional(),
|
|
400
414
|
detailsPanel: messageDetailsPanelPropertySchema.optional(),
|
|
401
415
|
messageChannels: z.array(reference('channels')).optional(),
|
|
402
416
|
})
|
|
@@ -419,6 +433,7 @@ const queries = defineCollection({
|
|
|
419
433
|
producers: z.array(reference('services')).optional(),
|
|
420
434
|
consumers: z.array(reference('services')).optional(),
|
|
421
435
|
channels: z.array(channelPointer).optional(),
|
|
436
|
+
schemas: z.array(schemaPointer).optional(),
|
|
422
437
|
detailsPanel: messageDetailsPanelPropertySchema.optional(),
|
|
423
438
|
messageChannels: z.array(reference('channels')).optional(),
|
|
424
439
|
})
|
|
@@ -991,6 +1006,53 @@ const diagrams = defineCollection({
|
|
|
991
1006
|
.extend(baseSchema.shape),
|
|
992
1007
|
});
|
|
993
1008
|
|
|
1009
|
+
const schemas = defineCollection({
|
|
1010
|
+
loader: schemaLoader({
|
|
1011
|
+
messages: {
|
|
1012
|
+
pattern: withIgnoredBuildArtifacts([
|
|
1013
|
+
'**/events/*/index.{md,mdx}',
|
|
1014
|
+
'**/events/*/versioned/*/index.{md,mdx}',
|
|
1015
|
+
'**/commands/*/index.{md,mdx}',
|
|
1016
|
+
'**/commands/*/versioned/*/index.{md,mdx}',
|
|
1017
|
+
'**/queries/*/index.{md,mdx}',
|
|
1018
|
+
'**/queries/*/versioned/*/index.{md,mdx}',
|
|
1019
|
+
]) as string[],
|
|
1020
|
+
base: projectDirBase,
|
|
1021
|
+
},
|
|
1022
|
+
sources: config.schemas?.sources ?? [],
|
|
1023
|
+
}),
|
|
1024
|
+
schema: z
|
|
1025
|
+
.object({
|
|
1026
|
+
format: z.string(),
|
|
1027
|
+
schemaId: z.string().optional(),
|
|
1028
|
+
ref: z.string().optional(),
|
|
1029
|
+
content: z.string().optional(),
|
|
1030
|
+
file: z.string().optional(),
|
|
1031
|
+
filePath: z.string().optional(),
|
|
1032
|
+
environments: z.array(z.string()).optional(),
|
|
1033
|
+
default: z.boolean().optional(),
|
|
1034
|
+
latest: z.boolean().optional(),
|
|
1035
|
+
message: z.object({
|
|
1036
|
+
collection: z.enum(['events', 'commands', 'queries']),
|
|
1037
|
+
id: z.string(),
|
|
1038
|
+
name: z.string().optional(),
|
|
1039
|
+
version: z.string(),
|
|
1040
|
+
summary: z.string().optional(),
|
|
1041
|
+
owners: z.array(z.string()).optional(),
|
|
1042
|
+
}),
|
|
1043
|
+
source: z.object({
|
|
1044
|
+
provider: z.string(),
|
|
1045
|
+
id: z.string().optional(),
|
|
1046
|
+
path: z.string().optional(),
|
|
1047
|
+
url: z.string().optional(),
|
|
1048
|
+
ref: z.string().optional(),
|
|
1049
|
+
branch: z.string().optional(),
|
|
1050
|
+
}),
|
|
1051
|
+
readOnly: z.boolean().optional(),
|
|
1052
|
+
})
|
|
1053
|
+
.extend(baseSchema.shape),
|
|
1054
|
+
});
|
|
1055
|
+
|
|
994
1056
|
export const collections = {
|
|
995
1057
|
events,
|
|
996
1058
|
commands,
|
|
@@ -1024,4 +1086,7 @@ export const collections = {
|
|
|
1024
1086
|
|
|
1025
1087
|
// Diagrams Collection
|
|
1026
1088
|
diagrams,
|
|
1089
|
+
|
|
1090
|
+
// Generated from message schema references
|
|
1091
|
+
schemas,
|
|
1027
1092
|
};
|
|
@@ -5,62 +5,55 @@
|
|
|
5
5
|
|
|
6
6
|
import type { APIRoute } from 'astro';
|
|
7
7
|
import { getCollection } from 'astro:content';
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
import fs from 'node:fs';
|
|
10
|
-
import utils from '@eventcatalog/sdk';
|
|
11
8
|
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
12
9
|
import { sortVersioned } from '@utils/collections/util';
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
const findSchema = async (collection: string | undefined, id: string, version: string | undefined) => {
|
|
12
|
+
const schemas = await getCollection('schemas');
|
|
13
|
+
const matchingSchemas = schemas.filter(
|
|
14
|
+
(schema) => schema.data.message.collection === collection && schema.data.message.id === id
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
if (version === 'latest') {
|
|
18
|
+
return (
|
|
19
|
+
matchingSchemas.find((schema) => schema.data.latest) ??
|
|
20
|
+
sortVersioned(matchingSchemas, (schema) => schema.data.message.version)[0]
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return matchingSchemas.find((schema) => schema.data.message.version === version);
|
|
25
|
+
};
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.filter((message) => fs.existsSync(path.join(path.dirname(message.filePath ?? ''), message.data.schemaPath ?? '')));
|
|
27
|
+
export async function getStaticPaths() {
|
|
28
|
+
const schemas = await getCollection('schemas');
|
|
23
29
|
|
|
24
30
|
// Generate paths for specific versions
|
|
25
|
-
const versionedPaths =
|
|
26
|
-
params: {
|
|
31
|
+
const versionedPaths = schemas.map((schema) => ({
|
|
32
|
+
params: {
|
|
33
|
+
collection: schema.data.message.collection,
|
|
34
|
+
id: schema.data.message.id,
|
|
35
|
+
version: schema.data.message.version,
|
|
36
|
+
},
|
|
27
37
|
props: {
|
|
28
|
-
pathToSchema:
|
|
29
|
-
schema:
|
|
30
|
-
extension: message.data.schemaPath?.split('.').pop(),
|
|
38
|
+
pathToSchema: schema.data.filePath,
|
|
39
|
+
schema: schema.data.content,
|
|
31
40
|
},
|
|
32
41
|
}));
|
|
33
42
|
|
|
34
|
-
// Group messages by collection and id to find latest versions
|
|
35
|
-
const groupedMessages = messagesWithSchemas.reduce(
|
|
36
|
-
(acc, message) => {
|
|
37
|
-
const key = `${message.collection}:${message.data.id}`;
|
|
38
|
-
if (!acc[key]) {
|
|
39
|
-
acc[key] = [];
|
|
40
|
-
}
|
|
41
|
-
acc[key].push(message);
|
|
42
|
-
return acc;
|
|
43
|
-
},
|
|
44
|
-
{} as Record<string, typeof messagesWithSchemas>
|
|
45
|
-
);
|
|
46
|
-
|
|
47
43
|
// Generate "latest" paths for each unique collection/id combination
|
|
48
|
-
const latestPaths =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
const latestPaths = schemas
|
|
45
|
+
.filter((schema) => schema.data.latest)
|
|
46
|
+
.map((latestSchema) => ({
|
|
47
|
+
params: {
|
|
48
|
+
collection: latestSchema.data.message.collection,
|
|
49
|
+
id: latestSchema.data.message.id,
|
|
50
|
+
version: 'latest',
|
|
51
|
+
},
|
|
54
52
|
props: {
|
|
55
|
-
pathToSchema:
|
|
56
|
-
schema:
|
|
57
|
-
path.join(path.dirname(latestMessage.filePath ?? ''), latestMessage.data.schemaPath ?? ''),
|
|
58
|
-
'utf8'
|
|
59
|
-
),
|
|
60
|
-
extension: latestMessage.data.schemaPath?.split('.').pop(),
|
|
53
|
+
pathToSchema: latestSchema.data.filePath,
|
|
54
|
+
schema: latestSchema.data.content,
|
|
61
55
|
},
|
|
62
|
-
};
|
|
63
|
-
});
|
|
56
|
+
}));
|
|
64
57
|
|
|
65
58
|
return [...versionedPaths, ...latestPaths];
|
|
66
59
|
}
|
|
@@ -83,14 +76,14 @@ export const GET: APIRoute = async ({ props, params }) => {
|
|
|
83
76
|
}
|
|
84
77
|
|
|
85
78
|
// In static mode, props are pre-computed by getStaticPaths
|
|
86
|
-
if (props.schema) {
|
|
79
|
+
if (props.schema !== undefined) {
|
|
87
80
|
return new Response(props.schema, {
|
|
88
81
|
headers: { 'Content-Type': 'text/plain' },
|
|
89
82
|
});
|
|
90
83
|
}
|
|
91
84
|
|
|
92
|
-
// In SSR mode, dynamically resolve the schema using the
|
|
93
|
-
const { id, version } = params;
|
|
85
|
+
// In SSR mode, dynamically resolve the schema using the generated schema collection
|
|
86
|
+
const { collection, id, version } = params;
|
|
94
87
|
|
|
95
88
|
if (!id) {
|
|
96
89
|
return new Response(JSON.stringify({ error: 'Missing id parameter' }), {
|
|
@@ -99,17 +92,16 @@ export const GET: APIRoute = async ({ props, params }) => {
|
|
|
99
92
|
});
|
|
100
93
|
}
|
|
101
94
|
|
|
102
|
-
const
|
|
103
|
-
const result = await getSchemaForMessage(id, version === 'latest' ? undefined : version);
|
|
95
|
+
const schema = await findSchema(collection, id, version);
|
|
104
96
|
|
|
105
|
-
if (
|
|
97
|
+
if (schema?.data.content === undefined) {
|
|
106
98
|
return new Response(JSON.stringify({ error: 'Schema not found' }), {
|
|
107
99
|
status: 404,
|
|
108
100
|
headers: { 'Content-Type': 'application/json' },
|
|
109
101
|
});
|
|
110
102
|
}
|
|
111
103
|
|
|
112
|
-
return new Response(
|
|
104
|
+
return new Response(schema.data.content, {
|
|
113
105
|
headers: { 'Content-Type': 'text/plain' },
|
|
114
106
|
});
|
|
115
107
|
};
|
|
@@ -28,6 +28,8 @@ import { getNodesAndEdges as getNodesAndEdgesForContainer } from '@utils/node-gr
|
|
|
28
28
|
import { convertToMermaid } from '@utils/node-graphs/export-mermaid';
|
|
29
29
|
import config from '@config';
|
|
30
30
|
|
|
31
|
+
const MESSAGE_COLLECTIONS = new Set(['events', 'commands', 'queries']);
|
|
32
|
+
|
|
31
33
|
// ============================================
|
|
32
34
|
// Pagination utilities
|
|
33
35
|
// ============================================
|
|
@@ -226,6 +228,27 @@ export async function getSchemaForResource(params: { resourceId: string; resourc
|
|
|
226
228
|
};
|
|
227
229
|
}
|
|
228
230
|
|
|
231
|
+
if (MESSAGE_COLLECTIONS.has(params.resourceCollection)) {
|
|
232
|
+
const schemaEntries = await getCollection('schemas');
|
|
233
|
+
const schemas = schemaEntries.filter(
|
|
234
|
+
(schema) =>
|
|
235
|
+
schema.data.message.collection === params.resourceCollection &&
|
|
236
|
+
schema.data.message.id === params.resourceId &&
|
|
237
|
+
schema.data.message.version === params.resourceVersion
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
if (schemas.length > 0) {
|
|
241
|
+
return schemas.map((schema) => ({
|
|
242
|
+
id: schema.id,
|
|
243
|
+
name: schema.data.name,
|
|
244
|
+
ref: schema.data.ref,
|
|
245
|
+
format: schema.data.format,
|
|
246
|
+
source: schema.data.source,
|
|
247
|
+
code: schema.data.content || '',
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
229
252
|
const schema = await getSchemasFromResource(resource);
|
|
230
253
|
|
|
231
254
|
if (schema.length > 0) {
|
|
@@ -565,7 +565,7 @@ if (!isAdrPage && !hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
|
|
|
565
565
|
<div data-pagefind-ignore>
|
|
566
566
|
<!-- @ts-ignore -->
|
|
567
567
|
<!-- <SchemaViewer id={props.data.id} catalog={props.catalog} filePath={props.filePath} /> -->
|
|
568
|
-
<SchemaViewer id={props.data.id} filePath={props.filePath} />
|
|
568
|
+
<SchemaViewer id={props.data.id} version={props.data.version} collection={props.collection} filePath={props.filePath} />
|
|
569
569
|
|
|
570
570
|
{
|
|
571
571
|
nodeGraphs.length > 0 &&
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
2
|
import config from '@config';
|
|
3
3
|
import type { APIRoute } from 'astro';
|
|
4
|
-
import type { CollectionEntry } from 'astro:content';
|
|
5
4
|
import { getSpecificationsForService } from '@utils/collections/services';
|
|
6
5
|
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const queries = await getCollection('queries');
|
|
7
|
+
type MessageCollection = 'events' | 'commands' | 'queries';
|
|
8
|
+
|
|
11
9
|
const services = await getCollection('services');
|
|
10
|
+
const schemas = await getCollection('schemas');
|
|
12
11
|
|
|
13
12
|
type ServiceWithSchema = {
|
|
14
13
|
collection: string;
|
|
@@ -33,8 +32,19 @@ const servicesWithSchemasFlat = servicesWithSchemas.reduce<ServiceWithSchema[]>(
|
|
|
33
32
|
];
|
|
34
33
|
}, []) as ServiceWithSchema[];
|
|
35
34
|
|
|
36
|
-
const
|
|
37
|
-
|
|
35
|
+
const getMessagesWithSchemas = (collection: MessageCollection) => {
|
|
36
|
+
const seenMessages = new Set<string>();
|
|
37
|
+
|
|
38
|
+
return schemas
|
|
39
|
+
.filter((schema) => schema.data.message.collection === collection)
|
|
40
|
+
.map((schema) => {
|
|
41
|
+
const key = `${schema.data.message.collection}:${schema.data.message.id}:${schema.data.message.version}`;
|
|
42
|
+
if (seenMessages.has(key)) return null;
|
|
43
|
+
seenMessages.add(key);
|
|
44
|
+
|
|
45
|
+
return schema;
|
|
46
|
+
})
|
|
47
|
+
.filter((schema): schema is NonNullable<typeof schema> => schema !== null);
|
|
38
48
|
};
|
|
39
49
|
|
|
40
50
|
export const GET: APIRoute = async ({ params, request }) => {
|
|
@@ -51,8 +61,9 @@ export const GET: APIRoute = async ({ params, request }) => {
|
|
|
51
61
|
const url = new URL(request.url);
|
|
52
62
|
const baseUrl = process.env.LLMS_TXT_BASE_URL || `${url.origin}`;
|
|
53
63
|
|
|
54
|
-
const formatVersionedItem = (item:
|
|
55
|
-
|
|
64
|
+
const formatVersionedItem = (item: (typeof schemas)[number]) => {
|
|
65
|
+
const message = item.data.message;
|
|
66
|
+
return `- [${message.name || message.id} - ${message.id} - ${message.version}](${baseUrl}/api/schemas/${message.collection}/${message.id}/${message.version})} ${message.summary ? `- ${message.summary.trim()}` : ''}`;
|
|
56
67
|
};
|
|
57
68
|
|
|
58
69
|
const formatServiceWithSchema = (item: ServiceWithSchema) => {
|
|
@@ -63,19 +74,16 @@ export const GET: APIRoute = async ({ params, request }) => {
|
|
|
63
74
|
`# ${config.organizationName} EventCatalog Schemas`,
|
|
64
75
|
`List of schemas for events, commands, queries, and services in EventCatalog.`,
|
|
65
76
|
'',
|
|
66
|
-
`## Events\n${events
|
|
67
|
-
.
|
|
68
|
-
.map((item) => formatVersionedItem(item, 'events'))
|
|
77
|
+
`## Events\n${getMessagesWithSchemas('events')
|
|
78
|
+
.map((item) => formatVersionedItem(item))
|
|
69
79
|
.join('\n')}`,
|
|
70
80
|
'',
|
|
71
|
-
`## Commands\n${commands
|
|
72
|
-
.
|
|
73
|
-
.map((item) => formatVersionedItem(item, 'commands'))
|
|
81
|
+
`## Commands\n${getMessagesWithSchemas('commands')
|
|
82
|
+
.map((item) => formatVersionedItem(item))
|
|
74
83
|
.join('\n')}`,
|
|
75
84
|
'',
|
|
76
|
-
`## Queries\n${queries
|
|
77
|
-
.
|
|
78
|
-
.map((item) => formatVersionedItem(item, 'queries'))
|
|
85
|
+
`## Queries\n${getMessagesWithSchemas('queries')
|
|
86
|
+
.map((item) => formatVersionedItem(item))
|
|
79
87
|
.join('\n')}`,
|
|
80
88
|
'',
|
|
81
89
|
`## Services\n${servicesWithSchemasFlat.map((item: any) => formatServiceWithSchema(item)).join('\n')}`,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getCollection } from 'astro:content';
|
|
1
2
|
import { isSSR } from '@utils/feature';
|
|
2
3
|
import { HybridPage } from '@utils/page-loaders/hybrid-page';
|
|
3
4
|
import type { PageTypes } from '@types';
|
|
@@ -23,25 +24,41 @@ export class Page extends HybridPage {
|
|
|
23
24
|
// 'entities',
|
|
24
25
|
// 'containers',
|
|
25
26
|
];
|
|
26
|
-
const allItems = await Promise.all(
|
|
27
|
+
const [schemas, ...allItems] = await Promise.all([
|
|
28
|
+
getCollection('schemas'),
|
|
29
|
+
...itemTypes.map((type) => pageDataLoader[type]()),
|
|
30
|
+
]);
|
|
31
|
+
const itemsByKey = new Map(allItems.flat().map((item) => [`${item.collection}:${item.data.id}:${item.data.version}`, item]));
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
const
|
|
33
|
+
const seenMessageSchemas = new Set<string>();
|
|
34
|
+
const messageSchemas = schemas.filter((schema) => {
|
|
35
|
+
const key = `${schema.data.message.collection}:${schema.data.message.id}:${schema.data.message.version}`;
|
|
36
|
+
if (seenMessageSchemas.has(key)) return false;
|
|
37
|
+
seenMessageSchemas.add(key);
|
|
38
|
+
return true;
|
|
39
|
+
});
|
|
30
40
|
|
|
31
41
|
// Generate paths for messages with schemas
|
|
32
|
-
const messagePaths =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const messagePaths = messageSchemas
|
|
43
|
+
.map((schema) => {
|
|
44
|
+
const item = itemsByKey.get(`${schema.data.message.collection}:${schema.data.message.id}:${schema.data.message.version}`);
|
|
45
|
+
if (!item) return null;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
params: {
|
|
49
|
+
type: schema.data.message.collection,
|
|
50
|
+
id: schema.data.message.id,
|
|
51
|
+
version: schema.data.message.version,
|
|
52
|
+
},
|
|
53
|
+
props: {
|
|
54
|
+
type: schema.data.message.collection,
|
|
55
|
+
...item,
|
|
56
|
+
// Not everything needs the body of the page itself.
|
|
57
|
+
body: undefined,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
})
|
|
61
|
+
.filter((path): path is NonNullable<typeof path> => path !== null);
|
|
45
62
|
|
|
46
63
|
// Generate paths for data products with contracts
|
|
47
64
|
const dataProducts = await pageDataLoader['data-products']();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { PageTypes } from '@types';
|
|
3
|
+
import { getCollection } from 'astro:content';
|
|
3
4
|
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
4
5
|
import { Page } from './_index.data';
|
|
5
6
|
import SchemaPageViewer from '@components/SchemaExplorer/SchemaPageViewer';
|
|
@@ -76,32 +77,41 @@ if (isDataProduct && contractPath) {
|
|
|
76
77
|
}
|
|
77
78
|
} else {
|
|
78
79
|
// Handle regular messages (events, commands, queries)
|
|
79
|
-
const allItems = await pageDataLoader[type]();
|
|
80
|
+
const [allItems, schemaEntries] = await Promise.all([pageDataLoader[type](), getCollection('schemas')]);
|
|
80
81
|
const versions = allItems.filter((item) => item.data.id === data.id);
|
|
82
|
+
const schemasForMessage = schemaEntries.filter(
|
|
83
|
+
(schema) => schema.data.message.collection === type && schema.data.message.id === data.id
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const getSchemaForVersion = (version: string) => {
|
|
87
|
+
const schemasForVersion = schemasForMessage.filter((schema) => schema.data.message.version === version);
|
|
88
|
+
return schemasForVersion.find((schema) => schema.data.default) ?? schemasForVersion[0];
|
|
89
|
+
};
|
|
81
90
|
|
|
82
91
|
// Transform to SchemaItems
|
|
83
92
|
const availableVersions = versions
|
|
84
|
-
.filter((message) => message.data.schemaPath && resourceFileExists(message, message.data.schemaPath))
|
|
85
93
|
.map((message) => {
|
|
86
94
|
try {
|
|
87
|
-
const
|
|
88
|
-
|
|
95
|
+
const schema = getSchemaForVersion(message.data.version);
|
|
96
|
+
if (!schema) return null;
|
|
97
|
+
|
|
98
|
+
const schemaPath = schema.data.file || schema.data.source.path || '';
|
|
89
99
|
const schemaExtension = path.extname(schemaPath).slice(1);
|
|
90
100
|
|
|
91
101
|
return {
|
|
92
102
|
collection: message.collection,
|
|
93
103
|
data: {
|
|
94
104
|
id: message.data.id,
|
|
95
|
-
name: message.data.name,
|
|
105
|
+
name: schema.data.message.name || message.data.name,
|
|
96
106
|
version: message.data.version,
|
|
97
|
-
summary: message.data.summary,
|
|
98
|
-
schemaPath
|
|
107
|
+
summary: schema.data.message.summary || message.data.summary,
|
|
108
|
+
schemaPath,
|
|
99
109
|
// @ts-ignore
|
|
100
110
|
producers: message.data.producers || [],
|
|
101
111
|
// @ts-ignore
|
|
102
112
|
consumers: message.data.consumers || [],
|
|
103
113
|
},
|
|
104
|
-
schemaContent,
|
|
114
|
+
schemaContent: schema.data.content || '',
|
|
105
115
|
schemaExtension,
|
|
106
116
|
examples: getExamplesForResource(message),
|
|
107
117
|
} as SchemaItem;
|
|
@@ -10,6 +10,7 @@ import { getOwner } from '@utils/collections/owners';
|
|
|
10
10
|
import { buildUrl } from '@utils/url-builder';
|
|
11
11
|
import { resourceFileExists, readResourceFile } from '@utils/resource-files';
|
|
12
12
|
import { getExamplesForResource } from '@utils/collections/examples';
|
|
13
|
+
import { getCollection } from 'astro:content';
|
|
13
14
|
import path from 'path';
|
|
14
15
|
|
|
15
16
|
// Helper function to enrich owners with full details
|
|
@@ -32,61 +33,84 @@ async function fetchAllSchemas() {
|
|
|
32
33
|
const events = await getEvents({ getAllVersions: true });
|
|
33
34
|
const commands = await getCommands({ getAllVersions: true });
|
|
34
35
|
const queries = await getQueries({ getAllVersions: true });
|
|
36
|
+
const schemaEntries = await getCollection('schemas');
|
|
35
37
|
|
|
36
38
|
// Fetch all services
|
|
37
39
|
const services = await getServices({ getAllVersions: true });
|
|
38
40
|
|
|
39
41
|
// Combine all messages
|
|
40
42
|
const allMessages = [...events, ...commands, ...queries];
|
|
43
|
+
const messagesBySchemaReference = new Map(
|
|
44
|
+
allMessages.map((message) => [`${message.collection}:${message.data.id}:${message.data.version}`, message])
|
|
45
|
+
);
|
|
41
46
|
|
|
42
|
-
//
|
|
47
|
+
// Read message schemas from the generated schemas collection.
|
|
43
48
|
const messagesWithSchemas = await Promise.all(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
schemaEntries.map(async (schema) => {
|
|
50
|
+
const message = messagesBySchemaReference.get(
|
|
51
|
+
`${schema.data.message.collection}:${schema.data.message.id}:${schema.data.message.version}`
|
|
52
|
+
);
|
|
53
|
+
const schemaPath = schema.data.file || schema.data.source.path || '';
|
|
54
|
+
const schemaExtension = path.extname(schemaPath).slice(1) || schema.data.format;
|
|
55
|
+
|
|
56
|
+
if (message) {
|
|
48
57
|
try {
|
|
49
|
-
const
|
|
50
|
-
const schemaContent = readResourceFile(message, schemaPath) ?? '';
|
|
51
|
-
const schemaExtension = path.extname(schemaPath).slice(1);
|
|
52
|
-
const enrichedOwners = await enrichOwners(message.data.owners || []);
|
|
58
|
+
const enrichedOwners = await enrichOwners(schema.data.message.owners || []);
|
|
53
59
|
|
|
54
60
|
return {
|
|
55
61
|
collection: message.collection,
|
|
56
62
|
data: {
|
|
57
63
|
id: message.data.id,
|
|
58
|
-
name: message.data.name,
|
|
64
|
+
name: schema.data.message.name || message.data.name,
|
|
59
65
|
version: message.data.version,
|
|
60
|
-
summary: message.data.summary,
|
|
61
|
-
schemaPath
|
|
66
|
+
summary: schema.data.message.summary || message.data.summary,
|
|
67
|
+
schemaPath,
|
|
62
68
|
producers: message.data.producers || [],
|
|
63
69
|
consumers: message.data.consumers || [],
|
|
64
70
|
owners: enrichedOwners,
|
|
65
71
|
},
|
|
66
|
-
schemaContent,
|
|
72
|
+
schemaContent: schema.data.content || '',
|
|
67
73
|
schemaExtension,
|
|
68
74
|
examples: getExamplesForResource(message),
|
|
69
75
|
};
|
|
70
76
|
} catch (error) {
|
|
71
|
-
console.error(`Error reading schema for ${message.data.id}:`, error);
|
|
72
|
-
const enrichedOwners = await enrichOwners(
|
|
77
|
+
console.error(`Error reading schema metadata for ${message.data.id}:`, error);
|
|
78
|
+
const enrichedOwners = await enrichOwners(schema.data.message.owners || []);
|
|
73
79
|
return {
|
|
74
80
|
collection: message.collection,
|
|
75
81
|
data: {
|
|
76
82
|
id: message.data.id,
|
|
77
|
-
name: message.data.name,
|
|
83
|
+
name: schema.data.message.name || schema.data.name || message.data.name,
|
|
78
84
|
version: message.data.version,
|
|
79
|
-
summary: message.data.summary,
|
|
80
|
-
schemaPath
|
|
85
|
+
summary: schema.data.message.summary || message.data.summary,
|
|
86
|
+
schemaPath,
|
|
81
87
|
producers: message.data.producers || [],
|
|
82
88
|
consumers: message.data.consumers || [],
|
|
83
89
|
owners: enrichedOwners,
|
|
84
90
|
},
|
|
85
|
-
schemaContent: '',
|
|
86
|
-
schemaExtension
|
|
91
|
+
schemaContent: schema.data.content || '',
|
|
92
|
+
schemaExtension,
|
|
87
93
|
};
|
|
88
94
|
}
|
|
89
|
-
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
collection: schema.data.message.collection,
|
|
99
|
+
data: {
|
|
100
|
+
id: schema.data.message.id,
|
|
101
|
+
name: schema.data.message.name || schema.data.name || schema.data.message.id,
|
|
102
|
+
version: schema.data.message.version,
|
|
103
|
+
summary: schema.data.message.summary,
|
|
104
|
+
schemaPath,
|
|
105
|
+
owners: await enrichOwners(schema.data.message.owners || []),
|
|
106
|
+
producers: [],
|
|
107
|
+
consumers: [],
|
|
108
|
+
},
|
|
109
|
+
schemaContent: schema.data.content || '',
|
|
110
|
+
schemaExtension,
|
|
111
|
+
examples: [],
|
|
112
|
+
};
|
|
113
|
+
})
|
|
90
114
|
);
|
|
91
115
|
|
|
92
116
|
// Filter services with specifications and read spec content - only keep essential data
|
|
@@ -15,11 +15,33 @@ import { isVisualiserEnabled, isChangelogEnabled } from '@utils/feature';
|
|
|
15
15
|
import { iconFieldsForResource } from '@utils/icon';
|
|
16
16
|
import { collectionToResourceMap } from '@utils/collections/util';
|
|
17
17
|
|
|
18
|
+
type MessageSchemaEntry = CollectionEntry<'schemas'>;
|
|
19
|
+
|
|
18
20
|
const getProducerConsumerPageRef = (resource: any) => {
|
|
19
21
|
const resourceType = collectionToResourceMap[resource.collection as keyof typeof collectionToResourceMap];
|
|
20
22
|
return `${resourceType}:${resource.data.id}:${resource.data.version}`;
|
|
21
23
|
};
|
|
22
24
|
|
|
25
|
+
const getSchemasForMessage = (
|
|
26
|
+
message: CollectionEntry<'events' | 'commands' | 'queries'>,
|
|
27
|
+
schemas: MessageSchemaEntry[] = []
|
|
28
|
+
) => {
|
|
29
|
+
return schemas.filter(
|
|
30
|
+
(schema) =>
|
|
31
|
+
schema.data.message.collection === message.collection &&
|
|
32
|
+
schema.data.message.id === message.data.id &&
|
|
33
|
+
schema.data.message.version === message.data.version
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getSchemaNavTitle = (schemas: MessageSchemaEntry[]) => {
|
|
38
|
+
if (schemas.length > 1) return 'Schemas';
|
|
39
|
+
|
|
40
|
+
const schemaPath = schemas[0]?.data.file || schemas[0]?.data.source.path || schemas[0]?.data.ref || schemas[0]?.id;
|
|
41
|
+
const format = schemaPath ? getSchemaFormatFromURL(schemaPath) : schemas[0]?.data.format;
|
|
42
|
+
return format ? `Schema (${format.toUpperCase()})` : 'Schema';
|
|
43
|
+
};
|
|
44
|
+
|
|
23
45
|
export const buildMessageNode = (
|
|
24
46
|
message: CollectionEntry<'events' | 'commands' | 'queries'>,
|
|
25
47
|
owners: any[],
|
|
@@ -51,7 +73,8 @@ export const buildMessageNode = (
|
|
|
51
73
|
};
|
|
52
74
|
const defaultIcon = iconMap[collection] || 'Mail';
|
|
53
75
|
|
|
54
|
-
const
|
|
76
|
+
const resolvedSchemas = getSchemasForMessage(message, context.schemas);
|
|
77
|
+
const hasSchema = resolvedSchemas.length > 0;
|
|
55
78
|
const renderVisualiser = isVisualiserEnabled();
|
|
56
79
|
const docsSection = buildResourceDocsSection(
|
|
57
80
|
collection as 'events' | 'commands' | 'queries',
|
|
@@ -116,7 +139,7 @@ export const buildMessageNode = (
|
|
|
116
139
|
pages: [
|
|
117
140
|
{
|
|
118
141
|
type: 'item',
|
|
119
|
-
title:
|
|
142
|
+
title: getSchemaNavTitle(resolvedSchemas),
|
|
120
143
|
href: buildUrl(`/schemas/${collection}/${message.data.id}/${message.data.version}`),
|
|
121
144
|
},
|
|
122
145
|
hasFieldUsage && {
|