@eventcatalog/core 2.62.1 → 2.64.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-4BYDUGYI.js → chunk-6AMZOBWI.js} +1 -1
- package/dist/{chunk-GZ2SVHEA.js → chunk-CWGFHLMX.js} +1 -1
- package/dist/{chunk-IWFL6VRS.js → chunk-PLMTJHGH.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 +34 -0
- package/dist/eventcatalog.config.d.ts +34 -0
- package/dist/eventcatalog.js +3 -3
- package/eventcatalog/astro.config.mjs +2 -1
- package/eventcatalog/public/icons/avro.svg +21 -0
- package/eventcatalog/public/icons/json-schema.svg +6 -0
- package/eventcatalog/public/icons/proto.svg +10 -0
- package/eventcatalog/src/components/Grids/utils.tsx +5 -3
- package/eventcatalog/src/components/MDX/RemoteFile.astro +5 -11
- package/eventcatalog/src/components/MDX/SchemaViewer/SchemaViewerRoot.astro +41 -6
- package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +139 -0
- package/eventcatalog/src/components/SchemaExplorer/AvroSchemaViewer.tsx +423 -0
- package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +102 -0
- package/eventcatalog/src/components/SchemaExplorer/JSONSchemaViewer.tsx +740 -0
- package/eventcatalog/src/components/SchemaExplorer/OwnersSection.tsx +56 -0
- package/eventcatalog/src/components/SchemaExplorer/Pagination.tsx +33 -0
- package/eventcatalog/src/components/SchemaExplorer/ProducersConsumersSection.tsx +91 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +93 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +130 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsHeader.tsx +181 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +232 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +415 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaFilters.tsx +174 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaListItem.tsx +73 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaViewerModal.tsx +77 -0
- package/eventcatalog/src/components/SchemaExplorer/VersionHistoryModal.tsx +72 -0
- package/eventcatalog/src/components/SchemaExplorer/types.ts +45 -0
- package/eventcatalog/src/components/SchemaExplorer/utils.ts +81 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +33 -2
- package/eventcatalog/src/components/Tables/Table.tsx +10 -2
- package/eventcatalog/src/components/Tables/columns/ContainersTableColumns.tsx +10 -8
- package/eventcatalog/src/components/Tables/columns/DomainTableColumns.tsx +8 -6
- package/eventcatalog/src/components/Tables/columns/FlowTableColumns.tsx +9 -7
- package/eventcatalog/src/components/Tables/columns/MessageTableColumns.tsx +11 -9
- package/eventcatalog/src/components/Tables/columns/ServiceTableColumns.tsx +9 -7
- package/eventcatalog/src/components/Tables/columns/SharedColumns.tsx +4 -2
- package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +12 -8
- package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +14 -9
- package/eventcatalog/src/components/Tables/columns/index.tsx +9 -8
- package/eventcatalog/src/content.config.ts +3 -2
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +1 -0
- package/eventcatalog/src/layouts/DirectoryLayout.astro +21 -22
- package/eventcatalog/src/layouts/DiscoverLayout.astro +26 -12
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +10 -0
- package/eventcatalog/src/pages/api/schemas/[collection]/[id]/[version]/index.ts +45 -0
- package/eventcatalog/src/pages/api/schemas/services/[id]/[version]/[specification]/index.ts +51 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/llm/schemas.txt.ts +86 -0
- package/eventcatalog/src/pages/schemas/index.astro +175 -0
- package/eventcatalog/src/types/index.ts +9 -0
- package/eventcatalog/src/utils/files.ts +9 -0
- package/package.json +1 -1
- package/eventcatalog/src/components/MDX/SchemaViewer/SchemaProperty.astro +0 -204
- package/eventcatalog/src/components/MDX/SchemaViewer/SchemaViewer.astro +0 -705
|
@@ -14,6 +14,7 @@ import { DatabaseIcon } from 'lucide-react';
|
|
|
14
14
|
import { MagnifyingGlassIcon } from '@heroicons/react/20/solid';
|
|
15
15
|
import VerticalSideBarLayout from './VerticalSideBarLayout.astro';
|
|
16
16
|
import Checkbox from '@components/Checkbox.astro';
|
|
17
|
+
import config from '@config';
|
|
17
18
|
|
|
18
19
|
const events = await getEvents();
|
|
19
20
|
const queries = await getQueries();
|
|
@@ -35,6 +36,9 @@ const currentPath = Astro.url.pathname;
|
|
|
35
36
|
const checkboxLatestId = 'latest-only';
|
|
36
37
|
const checkboxDraftsId = 'show-drafts';
|
|
37
38
|
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
const tableConfiguration = config[type as keyof typeof config]?.tableConfiguration ?? { columns: {} };
|
|
41
|
+
|
|
38
42
|
const tabs = [
|
|
39
43
|
{
|
|
40
44
|
label: `Events (${events.length})`,
|
|
@@ -43,6 +47,7 @@ const tabs = [
|
|
|
43
47
|
icon: BoltIcon,
|
|
44
48
|
activeColor: 'orange',
|
|
45
49
|
enabled: events.length > 0,
|
|
50
|
+
visible: events.length > 0,
|
|
46
51
|
},
|
|
47
52
|
{
|
|
48
53
|
label: `Commands (${commands.length})`,
|
|
@@ -51,6 +56,7 @@ const tabs = [
|
|
|
51
56
|
icon: ChatBubbleLeftIcon,
|
|
52
57
|
activeColor: 'blue',
|
|
53
58
|
enabled: commands.length > 0,
|
|
59
|
+
visible: commands.length > 0,
|
|
54
60
|
},
|
|
55
61
|
{
|
|
56
62
|
label: `Queries (${queries.length})`,
|
|
@@ -59,6 +65,7 @@ const tabs = [
|
|
|
59
65
|
icon: MagnifyingGlassIcon,
|
|
60
66
|
activeColor: 'green',
|
|
61
67
|
enabled: queries.length > 0,
|
|
68
|
+
visible: queries.length > 0,
|
|
62
69
|
},
|
|
63
70
|
{
|
|
64
71
|
label: `Services (${services.length})`,
|
|
@@ -67,6 +74,7 @@ const tabs = [
|
|
|
67
74
|
icon: ServerIcon,
|
|
68
75
|
activeColor: 'pink',
|
|
69
76
|
enabled: services.length > 0,
|
|
77
|
+
visible: services.length > 0,
|
|
70
78
|
},
|
|
71
79
|
{
|
|
72
80
|
label: `Domains (${domains.length})`,
|
|
@@ -75,6 +83,7 @@ const tabs = [
|
|
|
75
83
|
icon: RectangleGroupIcon,
|
|
76
84
|
activeColor: 'yellow',
|
|
77
85
|
enabled: domains.length > 0,
|
|
86
|
+
visible: domains.length > 0,
|
|
78
87
|
},
|
|
79
88
|
{
|
|
80
89
|
label: `Data (${containers.length})`,
|
|
@@ -83,6 +92,7 @@ const tabs = [
|
|
|
83
92
|
icon: DatabaseIcon,
|
|
84
93
|
activeColor: 'blue',
|
|
85
94
|
enabled: containers.length > 0,
|
|
95
|
+
visible: containers.length > 0,
|
|
86
96
|
},
|
|
87
97
|
{
|
|
88
98
|
label: `Flows (${flows.length})`,
|
|
@@ -91,6 +101,7 @@ const tabs = [
|
|
|
91
101
|
icon: QueueListIcon,
|
|
92
102
|
activeColor: 'teal',
|
|
93
103
|
enabled: flows.length > 0,
|
|
104
|
+
visible: flows.length > 0,
|
|
94
105
|
},
|
|
95
106
|
];
|
|
96
107
|
---
|
|
@@ -102,18 +113,20 @@ const tabs = [
|
|
|
102
113
|
<div class="border-b border-gray-200">
|
|
103
114
|
<nav class="flex space-x-8 -mb-0.5 pl-6" aria-label="Tabs">
|
|
104
115
|
{
|
|
105
|
-
tabs
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
tabs
|
|
117
|
+
.filter((tab) => tab.visible)
|
|
118
|
+
.map((tab) => (
|
|
119
|
+
<a
|
|
120
|
+
href={tab.href}
|
|
121
|
+
class={` text-black group inline-flex items-center py-4 px-1 text-sm font-light ${tab.isActive ? `border-${tab.activeColor}-500 border-b-[2px] text-${tab.activeColor}-500` : 'opacity-80'} ${!tab.enabled ? 'disabled' : ''}`}
|
|
122
|
+
aria-current="page"
|
|
123
|
+
>
|
|
124
|
+
<tab.icon
|
|
125
|
+
className={`w-6 h-6 -ml-0.5 mr-2 ${tab.isActive ? `text-${tab.activeColor}-500` : 'text-gray-500'}`}
|
|
126
|
+
/>
|
|
127
|
+
<span>{tab.label}</span>
|
|
128
|
+
</a>
|
|
129
|
+
))
|
|
117
130
|
}
|
|
118
131
|
</nav>
|
|
119
132
|
</div>
|
|
@@ -145,6 +158,7 @@ const tabs = [
|
|
|
145
158
|
checkboxDraftsId={checkboxDraftsId}
|
|
146
159
|
data={data}
|
|
147
160
|
collection={type}
|
|
161
|
+
tableConfiguration={tableConfiguration}
|
|
148
162
|
client:load
|
|
149
163
|
/>
|
|
150
164
|
</div>
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
Rocket,
|
|
18
18
|
FileText,
|
|
19
19
|
SquareDashedMousePointerIcon,
|
|
20
|
+
PackageSearch,
|
|
21
|
+
FileJson,
|
|
20
22
|
} from 'lucide-react';
|
|
21
23
|
import Header from '../components/Header.astro';
|
|
22
24
|
import SEO from '../components/Seo.astro';
|
|
@@ -121,6 +123,14 @@ const navigationItems = [
|
|
|
121
123
|
current: currentPath.includes('/discover/'),
|
|
122
124
|
sidebar: false,
|
|
123
125
|
},
|
|
126
|
+
{
|
|
127
|
+
id: '/schemas',
|
|
128
|
+
label: 'Schema Explorer',
|
|
129
|
+
icon: FileJson,
|
|
130
|
+
href: buildUrl('/schemas'),
|
|
131
|
+
current: currentPath.includes('/schemas'),
|
|
132
|
+
sidebar: false,
|
|
133
|
+
},
|
|
124
134
|
{
|
|
125
135
|
id: '/directory',
|
|
126
136
|
label: 'Users & Teams',
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro';
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
6
|
+
|
|
7
|
+
export async function getStaticPaths() {
|
|
8
|
+
const events = await getCollection('events');
|
|
9
|
+
const commands = await getCollection('commands');
|
|
10
|
+
const queries = await getCollection('queries');
|
|
11
|
+
const messages = [...events, ...commands, ...queries];
|
|
12
|
+
return messages
|
|
13
|
+
.filter((message) => message.data.schemaPath)
|
|
14
|
+
.filter((message) => fs.existsSync(path.join(path.dirname(message.filePath ?? ''), message.data.schemaPath ?? '')))
|
|
15
|
+
.map((message) => ({
|
|
16
|
+
params: { collection: message.collection, id: message.data.id, version: message.data.version },
|
|
17
|
+
props: {
|
|
18
|
+
pathToSchema: path.join(path.dirname(message.filePath ?? ''), message.data.schemaPath ?? ''),
|
|
19
|
+
schema: fs.readFileSync(path.join(path.dirname(message.filePath ?? ''), message.data.schemaPath ?? ''), 'utf8'),
|
|
20
|
+
extension: message.data.schemaPath?.split('.').pop(),
|
|
21
|
+
},
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const GET: APIRoute = async ({ props }) => {
|
|
26
|
+
if (!isEventCatalogScaleEnabled()) {
|
|
27
|
+
return new Response(
|
|
28
|
+
JSON.stringify({
|
|
29
|
+
error: 'feature_not_available_on_server',
|
|
30
|
+
message: 'Schema API is not enabled for this deployment and supported in EventCatalog Scale.',
|
|
31
|
+
}),
|
|
32
|
+
{
|
|
33
|
+
status: 501,
|
|
34
|
+
headers: {
|
|
35
|
+
'Content-Type': 'application/json',
|
|
36
|
+
'Cache-Control': 'no-store',
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return new Response(props.schema, {
|
|
43
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
44
|
+
});
|
|
45
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro';
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { getSpecificationsForService } from '@utils/collections/services';
|
|
6
|
+
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
7
|
+
|
|
8
|
+
export async function getStaticPaths() {
|
|
9
|
+
const services = await getCollection('services');
|
|
10
|
+
const servicesWithSpecifications = services.filter((service) => getSpecificationsForService(service).length > 0);
|
|
11
|
+
return servicesWithSpecifications.reduce<
|
|
12
|
+
{ params: { collection: string; id: string; version: string; specification: string }; props: { schema: string } }[]
|
|
13
|
+
>(
|
|
14
|
+
(acc, service) => {
|
|
15
|
+
const specifications = getSpecificationsForService(service);
|
|
16
|
+
return [
|
|
17
|
+
...acc,
|
|
18
|
+
...specifications.map((specification) => ({
|
|
19
|
+
params: {
|
|
20
|
+
collection: service.collection,
|
|
21
|
+
id: service.data.id,
|
|
22
|
+
version: service.data.version,
|
|
23
|
+
specification: specification.type,
|
|
24
|
+
},
|
|
25
|
+
props: {
|
|
26
|
+
schema: fs.readFileSync(path.join(path.dirname(service.filePath ?? ''), specification.path ?? ''), 'utf8'),
|
|
27
|
+
},
|
|
28
|
+
})),
|
|
29
|
+
];
|
|
30
|
+
},
|
|
31
|
+
[] as { params: { collection: string; id: string; version: string; specification: string }; props: { schema: string } }[]
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const GET: APIRoute = async ({ props }) => {
|
|
36
|
+
if (!isEventCatalogScaleEnabled()) {
|
|
37
|
+
return new Response(
|
|
38
|
+
JSON.stringify({
|
|
39
|
+
error: 'feature_not_available_on_server',
|
|
40
|
+
message: 'Schema API is not enabled for this deployment and supported in EventCatalog Scale.',
|
|
41
|
+
}),
|
|
42
|
+
{
|
|
43
|
+
status: 501,
|
|
44
|
+
headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' },
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return new Response(props.schema, {
|
|
49
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
50
|
+
});
|
|
51
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { getCollection } from 'astro:content';
|
|
2
|
+
import config from '@config';
|
|
3
|
+
import type { APIRoute } from 'astro';
|
|
4
|
+
import type { CollectionEntry } from 'astro:content';
|
|
5
|
+
import { getSpecificationsForService } from '@utils/collections/services';
|
|
6
|
+
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
7
|
+
|
|
8
|
+
const events = await getCollection('events');
|
|
9
|
+
const commands = await getCollection('commands');
|
|
10
|
+
const queries = await getCollection('queries');
|
|
11
|
+
const services = await getCollection('services');
|
|
12
|
+
|
|
13
|
+
type ServiceWithSchema = {
|
|
14
|
+
collection: string;
|
|
15
|
+
id: string;
|
|
16
|
+
version: string;
|
|
17
|
+
specification: string;
|
|
18
|
+
summary: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const servicesWithSchemas = services.filter((service) => getSpecificationsForService(service).length > 0);
|
|
22
|
+
|
|
23
|
+
const servicesWithSchemasFlat = servicesWithSchemas.reduce<ServiceWithSchema[]>((acc, service) => {
|
|
24
|
+
return [
|
|
25
|
+
...acc,
|
|
26
|
+
...getSpecificationsForService(service).map((specification) => ({
|
|
27
|
+
collection: 'services',
|
|
28
|
+
id: service.data.id,
|
|
29
|
+
version: service.data.version,
|
|
30
|
+
specification: specification.type,
|
|
31
|
+
summary: service.data.summary?.trim() || '',
|
|
32
|
+
})),
|
|
33
|
+
];
|
|
34
|
+
}, []) as ServiceWithSchema[];
|
|
35
|
+
|
|
36
|
+
const messageHasSchema = (message: CollectionEntry<'events' | 'commands' | 'queries'>) => {
|
|
37
|
+
return message.data.schemaPath;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
41
|
+
if (!isEventCatalogScaleEnabled()) {
|
|
42
|
+
return new Response(
|
|
43
|
+
JSON.stringify({
|
|
44
|
+
error: 'feature_not_available_on_server',
|
|
45
|
+
message: 'Schema API is not enabled for this deployment and supported in EventCatalog Scale.',
|
|
46
|
+
}),
|
|
47
|
+
{ status: 501, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' } }
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const url = new URL(request.url);
|
|
52
|
+
const baseUrl = process.env.LLMS_TXT_BASE_URL || `${url.origin}`;
|
|
53
|
+
|
|
54
|
+
const formatVersionedItem = (item: any, type: string, extraParams?: string | string[]) => {
|
|
55
|
+
return `- [${item.data.name} - ${item.data.id} - ${item.data.version}](${baseUrl}/api/schemas/${type}/${item.data.id}/${item.data.version})} ${item.data.summary ? `- ${item.data.summary.trim()}` : ''}`;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const formatServiceWithSchema = (item: ServiceWithSchema) => {
|
|
59
|
+
return `- [${item.id} - ${item.version} - ${item.specification} specification](${baseUrl}/api/schemas/${item.collection}/${item.id}/${item.version}/${item.specification}) ${item.summary ? `- Specification for ${item.summary}` : ''}`;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const content = [
|
|
63
|
+
`# ${config.organizationName} EventCatalog Schemas`,
|
|
64
|
+
`List of schemas for events, commands, queries, and services in EventCatalog.`,
|
|
65
|
+
'',
|
|
66
|
+
`## Events\n${events
|
|
67
|
+
.filter(messageHasSchema)
|
|
68
|
+
.map((item) => formatVersionedItem(item, 'events'))
|
|
69
|
+
.join('\n')}`,
|
|
70
|
+
'',
|
|
71
|
+
`## Commands\n${commands
|
|
72
|
+
.filter(messageHasSchema)
|
|
73
|
+
.map((item) => formatVersionedItem(item, 'commands'))
|
|
74
|
+
.join('\n')}`,
|
|
75
|
+
'',
|
|
76
|
+
`## Queries\n${queries
|
|
77
|
+
.filter(messageHasSchema)
|
|
78
|
+
.map((item) => formatVersionedItem(item, 'queries'))
|
|
79
|
+
.join('\n')}`,
|
|
80
|
+
'',
|
|
81
|
+
`## Services\n${servicesWithSchemasFlat.map((item: any) => formatServiceWithSchema(item)).join('\n')}`,
|
|
82
|
+
].join('\n');
|
|
83
|
+
return new Response(content, {
|
|
84
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
85
|
+
});
|
|
86
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
3
|
+
import { getEvents } from '@utils/events';
|
|
4
|
+
import { getCommands } from '@utils/commands';
|
|
5
|
+
import { getQueries } from '@utils/queries';
|
|
6
|
+
import { getServices, getSpecificationsForService } from '@utils/collections/services';
|
|
7
|
+
import SchemaExplorer from '@components/SchemaExplorer/SchemaExplorer';
|
|
8
|
+
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
9
|
+
import { getOwner } from '@utils/collections/owners';
|
|
10
|
+
import { buildUrl } from '@utils/url-builder';
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
|
|
14
|
+
// Fetch all messages
|
|
15
|
+
const events = await getEvents({ getAllVersions: true });
|
|
16
|
+
const commands = await getCommands({ getAllVersions: true });
|
|
17
|
+
const queries = await getQueries({ getAllVersions: true });
|
|
18
|
+
|
|
19
|
+
// Fetch all services
|
|
20
|
+
const services = await getServices({ getAllVersions: true });
|
|
21
|
+
|
|
22
|
+
// Combine all messages
|
|
23
|
+
const allMessages = [...events, ...commands, ...queries];
|
|
24
|
+
|
|
25
|
+
// Helper function to enrich owners with full details
|
|
26
|
+
async function enrichOwners(ownersRaw: any[]) {
|
|
27
|
+
if (!ownersRaw || ownersRaw.length === 0) return [];
|
|
28
|
+
|
|
29
|
+
const owners = await Promise.all(ownersRaw.map(getOwner));
|
|
30
|
+
const filteredOwners = owners.filter((o) => o !== undefined);
|
|
31
|
+
|
|
32
|
+
return filteredOwners.map((o) => ({
|
|
33
|
+
id: o.data.id,
|
|
34
|
+
name: o.data.name,
|
|
35
|
+
type: o.collection,
|
|
36
|
+
href: buildUrl(`/docs/${o.collection}/${o.data.id}`),
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Filter messages with schemas and read schema content - only keep essential data
|
|
41
|
+
const messagesWithSchemas = await Promise.all(
|
|
42
|
+
allMessages
|
|
43
|
+
.filter((message) => message.data.schemaPath)
|
|
44
|
+
// Make sure the file exists
|
|
45
|
+
.filter((message) => fs.existsSync(path.join(path.dirname(message.filePath ?? ''), message.data.schemaPath ?? '')))
|
|
46
|
+
.map(async (message) => {
|
|
47
|
+
try {
|
|
48
|
+
// Get the schema file path
|
|
49
|
+
const schemaPath = message.data.schemaPath;
|
|
50
|
+
const fullSchemaPath = path.join(path.dirname(message.filePath ?? ''), schemaPath ?? '');
|
|
51
|
+
|
|
52
|
+
// Read the schema content
|
|
53
|
+
let schemaContent = '';
|
|
54
|
+
if (fs.existsSync(fullSchemaPath)) {
|
|
55
|
+
schemaContent = fs.readFileSync(fullSchemaPath, 'utf-8');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Get schema file extension
|
|
59
|
+
const schemaExtension = path.extname(schemaPath ?? '').slice(1);
|
|
60
|
+
|
|
61
|
+
// Enrich owners with full details
|
|
62
|
+
const enrichedOwners = await enrichOwners(message.data.owners || []);
|
|
63
|
+
|
|
64
|
+
// Only return essential data - strip out markdown, full data objects, etc.
|
|
65
|
+
return {
|
|
66
|
+
collection: message.collection,
|
|
67
|
+
data: {
|
|
68
|
+
id: message.data.id,
|
|
69
|
+
name: message.data.name,
|
|
70
|
+
version: message.data.version,
|
|
71
|
+
summary: message.data.summary,
|
|
72
|
+
schemaPath: message.data.schemaPath,
|
|
73
|
+
producers: message.data.producers || [],
|
|
74
|
+
consumers: message.data.consumers || [],
|
|
75
|
+
owners: enrichedOwners,
|
|
76
|
+
},
|
|
77
|
+
schemaContent,
|
|
78
|
+
schemaExtension,
|
|
79
|
+
};
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(`Error reading schema for ${message.data.id}:`, error);
|
|
82
|
+
const enrichedOwners = await enrichOwners(message.data.owners || []);
|
|
83
|
+
return {
|
|
84
|
+
collection: message.collection,
|
|
85
|
+
data: {
|
|
86
|
+
id: message.data.id,
|
|
87
|
+
name: message.data.name,
|
|
88
|
+
version: message.data.version,
|
|
89
|
+
summary: message.data.summary,
|
|
90
|
+
schemaPath: message.data.schemaPath,
|
|
91
|
+
producers: message.data.producers || [],
|
|
92
|
+
consumers: message.data.consumers || [],
|
|
93
|
+
owners: enrichedOwners,
|
|
94
|
+
},
|
|
95
|
+
schemaContent: '',
|
|
96
|
+
schemaExtension: 'json',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Filter services with specifications and read spec content - only keep essential data
|
|
103
|
+
const servicesWithSpecs = await Promise.all(
|
|
104
|
+
services.map(async (service) => {
|
|
105
|
+
try {
|
|
106
|
+
const specifications = getSpecificationsForService(service);
|
|
107
|
+
|
|
108
|
+
// Only include services that have specifications
|
|
109
|
+
if (specifications.length === 0) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Process each specification file for this service
|
|
114
|
+
return await Promise.all(
|
|
115
|
+
specifications.map(async (spec) => {
|
|
116
|
+
const specPath = path.join(path.dirname(service.filePath ?? ''), spec.path);
|
|
117
|
+
|
|
118
|
+
// Only include if the spec file exists
|
|
119
|
+
if (!fs.existsSync(specPath)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const schemaContent = fs.readFileSync(specPath, 'utf-8');
|
|
124
|
+
// Use spec type (openapi, asyncapi) as the extension for proper labeling
|
|
125
|
+
const schemaExtension = spec.type;
|
|
126
|
+
|
|
127
|
+
// Enrich owners with full details
|
|
128
|
+
const enrichedOwners = await enrichOwners(service.data.owners || []);
|
|
129
|
+
|
|
130
|
+
// Only return essential data - strip out markdown, sends/receives, entities, etc.
|
|
131
|
+
return {
|
|
132
|
+
collection: 'services',
|
|
133
|
+
data: {
|
|
134
|
+
id: `${service.data.id}`,
|
|
135
|
+
name: `${service.data.name} - ${spec.name}`,
|
|
136
|
+
version: service.data.version,
|
|
137
|
+
summary: service.data.summary,
|
|
138
|
+
schemaPath: spec.path,
|
|
139
|
+
owners: enrichedOwners,
|
|
140
|
+
},
|
|
141
|
+
schemaContent,
|
|
142
|
+
schemaExtension,
|
|
143
|
+
specType: spec.type,
|
|
144
|
+
specName: spec.name,
|
|
145
|
+
specFilenameWithoutExtension: spec.filenameWithoutExtension,
|
|
146
|
+
};
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error(`Error reading specifications for service ${service.data.id}:`, error);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Flatten and filter out null values
|
|
157
|
+
const flatServicesWithSpecs = servicesWithSpecs.flat().filter((service) => service !== null);
|
|
158
|
+
|
|
159
|
+
// Combine messages and services
|
|
160
|
+
const allSchemas = [...messagesWithSchemas, ...flatServicesWithSpecs];
|
|
161
|
+
|
|
162
|
+
const apiAccessEnabled = isEventCatalogScaleEnabled();
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
<VerticalSideBarLayout title="Schema Explorer - EventCatalog">
|
|
166
|
+
<main class="flex sm:px-8 docs-layout h-[calc(100vh-var(--header-height,0px)-64px)]">
|
|
167
|
+
<div class="flex docs-layout w-full h-full">
|
|
168
|
+
<div class="w-full lg:mr-2 pr-8 py-6 flex flex-col h-full">
|
|
169
|
+
<div class="w-full !max-w-none h-full flex flex-col overflow-hidden">
|
|
170
|
+
<SchemaExplorer client:load schemas={allSchemas as any} apiAccessEnabled={apiAccessEnabled} />
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
</main>
|
|
175
|
+
</VerticalSideBarLayout>
|
|
@@ -50,3 +50,12 @@ export const getAbsoluteFilePathForAstroFile = (filePath: string, fileName?: str
|
|
|
50
50
|
|
|
51
51
|
return resolveProjectPath(filePath, PROJECT_DIR);
|
|
52
52
|
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Checks if a file path is an Avro schema based on its extension
|
|
56
|
+
* @param filePath - The file path to check
|
|
57
|
+
* @returns True if the file is an Avro schema (.avro or .avsc)
|
|
58
|
+
*/
|
|
59
|
+
export const isAvroSchema = (filePath: string): boolean => {
|
|
60
|
+
return filePath.endsWith('.avro') || filePath.endsWith('.avsc');
|
|
61
|
+
};
|