@eventcatalog/core 2.42.10 → 2.43.1

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 (56) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/catalog-to-astro-content-directory.js +2 -2
  6. package/dist/{chunk-QVBE3VN4.js → chunk-A6LT34RD.js} +1 -1
  7. package/dist/{chunk-HDG7YSFG.js → chunk-LUUBKWYP.js} +8 -0
  8. package/dist/{chunk-ZG2E6QCK.js → chunk-QYZZIYJW.js} +1 -1
  9. package/dist/{chunk-K7RD2O76.js → chunk-ZV5T7TKQ.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.auth.cjs +18 -0
  13. package/dist/eventcatalog.auth.d.cts +20 -0
  14. package/dist/eventcatalog.auth.d.ts +20 -0
  15. package/dist/eventcatalog.auth.js +0 -0
  16. package/dist/eventcatalog.cjs +50 -23
  17. package/dist/eventcatalog.js +29 -8
  18. package/dist/features.cjs +9 -0
  19. package/dist/features.d.cts +2 -1
  20. package/dist/features.d.ts +2 -1
  21. package/dist/features.js +3 -1
  22. package/dist/watcher.js +1 -1
  23. package/eventcatalog/astro.config.mjs +7 -3
  24. package/eventcatalog/auth.config.ts +156 -0
  25. package/eventcatalog/src/components/Header.astro +125 -25
  26. package/eventcatalog/src/middleware.ts +62 -0
  27. package/eventcatalog/src/pages/auth/error.astro +55 -0
  28. package/eventcatalog/src/pages/auth/login.astro +267 -0
  29. package/eventcatalog/src/pages/directory/[type]/_index.data.ts +63 -0
  30. package/eventcatalog/src/pages/directory/[type]/index.astro +6 -23
  31. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +62 -0
  32. package/eventcatalog/src/pages/discover/[type]/index.astro +7 -24
  33. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +62 -0
  34. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +5 -37
  35. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/_[filename].data.ts +98 -0
  36. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +68 -0
  37. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +5 -25
  38. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +6 -25
  39. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +6 -35
  40. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/_[filename].data.ts +99 -0
  41. package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +1 -0
  42. package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +40 -0
  43. package/eventcatalog/src/pages/docs/[type]/[id]/{language.astro → language/index.astro} +6 -20
  44. package/eventcatalog/src/pages/docs/custom/[...path]/_index.data.ts +49 -0
  45. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +5 -11
  46. package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +46 -0
  47. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +6 -10
  48. package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +46 -0
  49. package/eventcatalog/src/pages/docs/users/[id]/index.astro +5 -9
  50. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +99 -0
  51. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +5 -29
  52. package/eventcatalog/src/utils/feature.ts +10 -0
  53. package/eventcatalog/src/utils/page-loaders/hybrid-page.ts +68 -0
  54. package/eventcatalog/tsconfig.json +2 -1
  55. package/package.json +3 -1
  56. package/dist/{chunk-SLEMYHTU.js → chunk-SFA7F3CQ.js} +3 -3
@@ -0,0 +1,267 @@
1
+ ---
2
+ import config from '@config';
3
+ const { title, logo } = config;
4
+ import { getSession } from 'auth-astro/server';
5
+ import { join } from 'node:path';
6
+ import { isAuthEnabled, isSSR } from '@utils/feature';
7
+
8
+ const session = await getSession(Astro.request);
9
+ const catalogDirectory = process.env.PROJECT_DIR || process.cwd();
10
+
11
+ let hasAuthConfigurationFile = false;
12
+ let providers: string[] = [];
13
+
14
+ try {
15
+ const authConfig = await import(/* @vite-ignore */ join(catalogDirectory, 'eventcatalog.auth.js'));
16
+ providers = Object.keys(authConfig.default.providers);
17
+ hasAuthConfigurationFile = true;
18
+ } catch (error) {
19
+ hasAuthConfigurationFile = false;
20
+ }
21
+
22
+ // Check if we should show login (auth file exists, SSR enabled, auth enabled, and has providers)
23
+ const shouldShowLogin = hasAuthConfigurationFile && isSSR() && isAuthEnabled() && providers.length > 0;
24
+
25
+ // Check if configuration exists but no providers are set up
26
+ const hasConfigButNoProviders = hasAuthConfigurationFile && isSSR() && isAuthEnabled() && providers.length === 0;
27
+
28
+ if (session) {
29
+ return Astro.redirect('/');
30
+ }
31
+
32
+ // Provider configurations
33
+ const providerConfig = {
34
+ github: {
35
+ name: 'GitHub',
36
+ icon: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
37
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"></path>
38
+ </svg>`,
39
+ },
40
+ google: {
41
+ name: 'Google',
42
+ icon: `<svg class="w-5 h-5" viewBox="0 0 24 24">
43
+ <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
44
+ <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
45
+ <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
46
+ <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
47
+ </svg>`,
48
+ },
49
+ okta: {
50
+ name: 'Okta',
51
+ icon: `<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
52
+ <path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm0 18c-4.418 0-8-3.582-8-8s3.582-8 8-8 8 3.582 8 8-3.582 8-8 8zm-1-13h2v6h-2V7zm0 8h2v2h-2v-2z"></path>
53
+ </svg>`,
54
+ },
55
+ auth0: {
56
+ name: 'Auth0',
57
+ icon: `<svg class="w-5 h-5" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path fill="#000000" d="M12.549 1h-4.55l1.407 4.38h4.548l-3.68 2.61 1.406 4.405c2.37-1.725 3.143-4.336 2.274-7.016L12.55 1zM2.045 5.38h4.55L8 1H3.45L2.045 5.38c-.868 2.68-.094 5.29 2.275 7.015L5.725 7.99l-3.68-2.612zm2.275 7.015L8 15l3.68-2.605L8 9.745l-3.68 2.65z"></path></g></svg>`,
58
+ },
59
+ };
60
+ ---
61
+
62
+ <!doctype html>
63
+ <html lang="en">
64
+ <head>
65
+ <meta charset="UTF-8" />
66
+ <meta name="viewport" content="width=device-width" />
67
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
68
+ <meta name="generator" content={Astro.generator} />
69
+ <title>Sign In | {title}</title>
70
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
71
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
72
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
73
+ <style>
74
+ body {
75
+ font-family: 'Inter', sans-serif;
76
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
77
+ }
78
+ </style>
79
+ </head>
80
+ <body class="min-h-screen">
81
+ <div class="flex min-h-screen flex-col items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
82
+ <!-- Logo at the top -->
83
+ <div class="mb-8">
84
+ {
85
+ logo && (
86
+ <div class="flex flex-col items-center space-y-4">
87
+ <img alt={logo.alt} src={logo.src} class="w-12 h-12" />
88
+ <h1 class="text-2xl font-bold text-gray-900">{title}</h1>
89
+ </div>
90
+ )
91
+ }
92
+ </div>
93
+
94
+ {
95
+ shouldShowLogin ? (
96
+ <div class="w-full max-w-md">
97
+ <div class="bg-white rounded-xl shadow-lg border border-gray-100 p-8 space-y-6">
98
+ <div class="text-center">
99
+ <h2 class="text-2xl font-bold text-gray-900">Sign in to your account</h2>
100
+ </div>
101
+
102
+ <div class="space-y-4">
103
+ {providers.map((provider) => {
104
+ const config = providerConfig[provider as keyof typeof providerConfig];
105
+ if (!config) return null;
106
+
107
+ return (
108
+ <button
109
+ data-provider={provider}
110
+ class="provider-login-btn flex w-full items-center justify-center rounded-lg border border-gray-200 bg-white px-4 py-3 text-sm font-medium text-gray-700 shadow-sm hover:bg-purple-50 hover:border-purple-200 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 transition-all duration-200"
111
+ >
112
+ <span class="mr-3" set:html={config.icon} />
113
+ Sign in with {config.name}
114
+ </button>
115
+ );
116
+ })}
117
+ </div>
118
+ </div>
119
+
120
+ <div class="mt-6 text-center">
121
+ <p class="text-gray-600 text-sm">
122
+ Missing integration?
123
+ <a
124
+ href="https://github.com/event-catalog/eventcatalog/issues"
125
+ target="_blank"
126
+ class="text-purple-600 hover:text-purple-700 underline font-medium"
127
+ >
128
+ Let us know
129
+ </a>
130
+ </p>
131
+ </div>
132
+ </div>
133
+ ) : hasConfigButNoProviders ? (
134
+ <div class="w-full max-w-2xl">
135
+ <div class="bg-white rounded-xl shadow-lg border border-gray-100 p-8 space-y-6">
136
+ <div class="text-center">
137
+ <h2 class="text-2xl font-bold text-gray-900">No Authentication Providers Configured</h2>
138
+ <p class="mt-4 text-gray-600">
139
+ Authentication is enabled but no providers are configured in your auth configuration file.
140
+ </p>
141
+ </div>
142
+
143
+ <div class="bg-purple-50 border border-purple-100 rounded-lg p-6 space-y-4">
144
+ <h3 class="text-lg font-semibold text-gray-900">To add authentication providers:</h3>
145
+ <ol class="list-decimal list-inside space-y-2 text-gray-700">
146
+ <li>
147
+ Update your{' '}
148
+ <code class="bg-purple-100 text-purple-800 px-2 py-1 rounded text-sm font-mono">eventcatalog.auth.js</code>{' '}
149
+ file to include at least one provider (GitHub, Google, Okta, etc.)
150
+ </li>
151
+ <li>Configure the provider with the necessary credentials and settings</li>
152
+ <li>Restart your EventCatalog server to apply the changes</li>
153
+ </ol>
154
+ </div>
155
+
156
+ <div class="text-center">
157
+ <a
158
+ href="#"
159
+ class="inline-flex items-center px-6 py-3 border border-transparent text-sm font-medium rounded-lg text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 transition-colors duration-200"
160
+ >
161
+ Read Authentication Documentation
162
+ </a>
163
+ </div>
164
+ </div>
165
+
166
+ <div class="mt-6 text-center">
167
+ <p class="text-gray-600 text-sm">
168
+ Missing integration?
169
+ <a
170
+ href="https://github.com/event-catalog/eventcatalog/issues"
171
+ target="_blank"
172
+ class="text-purple-600 hover:text-purple-700 underline font-medium"
173
+ >
174
+ Let us know
175
+ </a>
176
+ </p>
177
+ </div>
178
+ </div>
179
+ ) : (
180
+ <div class="w-full max-w-2xl">
181
+ <div class="bg-white rounded-xl shadow-lg border border-gray-100 p-8 space-y-6">
182
+ <div class="text-center">
183
+ <h2 class="text-2xl font-bold text-gray-900">Authentication Not Configured</h2>
184
+ <p class="mt-4 text-gray-600">
185
+ {!hasAuthConfigurationFile
186
+ ? 'No authentication configuration file found.'
187
+ : 'Authentication is not properly enabled.'}
188
+ </p>
189
+ </div>
190
+
191
+ <div class="bg-purple-50 border border-purple-100 rounded-lg p-6 space-y-4">
192
+ <h3 class="text-lg font-semibold text-gray-900">To enable authentication:</h3>
193
+ <ol class="list-decimal list-inside space-y-2 text-gray-700">
194
+ {!hasAuthConfigurationFile && (
195
+ <li>
196
+ Create an{' '}
197
+ <code class="bg-purple-100 text-purple-800 px-2 py-1 rounded text-sm font-mono">eventcatalog.auth.js</code>{' '}
198
+ configuration file in your project root
199
+ </li>
200
+ )}
201
+ {!isSSR() && (
202
+ <li>
203
+ Enable SSR (Server-Side Rendering) in your{' '}
204
+ <code class="bg-purple-100 text-purple-800 px-2 py-1 rounded text-sm font-mono">
205
+ eventcatalog.config.js
206
+ </code>{' '}
207
+ file by setting{' '}
208
+ <code class="bg-purple-100 text-purple-800 px-2 py-1 rounded text-sm font-mono">output: 'server'</code>
209
+ </li>
210
+ )}
211
+ {!isAuthEnabled() && (
212
+ <li>
213
+ Enable authentication in your{' '}
214
+ <code class="bg-purple-100 text-purple-800 px-2 py-1 rounded text-sm font-mono">
215
+ eventcatalog.config.js
216
+ </code>{' '}
217
+ file by setting{' '}
218
+ <code class="bg-purple-100 text-purple-800 px-2 py-1 rounded text-sm font-mono">
219
+ auth: {`{ enabled: true }`}
220
+ </code>
221
+ </li>
222
+ )}
223
+ </ol>
224
+ </div>
225
+
226
+ <div class="text-center">
227
+ <a
228
+ href="#"
229
+ class="inline-flex items-center px-6 py-3 border border-transparent text-sm font-medium rounded-lg text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 transition-colors duration-200"
230
+ >
231
+ Read Authentication Documentation
232
+ </a>
233
+ </div>
234
+ </div>
235
+
236
+ <div class="mt-6 text-center">
237
+ <p class="text-gray-600 text-sm">
238
+ Missing integration?
239
+ <a
240
+ href="https://github.com/event-catalog/eventcatalog/issues"
241
+ target="_blank"
242
+ class="text-purple-600 hover:text-purple-700 underline font-medium"
243
+ >
244
+ Let us know
245
+ </a>
246
+ </p>
247
+ </div>
248
+ </div>
249
+ )
250
+ }
251
+ </div>
252
+ </body>
253
+ </html>
254
+
255
+ <script>
256
+ import { signIn } from 'auth-astro/client';
257
+
258
+ // Add event listeners to all provider login buttons
259
+ const providerButtons = document.querySelectorAll('.provider-login-btn');
260
+
261
+ providerButtons.forEach((button) => {
262
+ const provider = button.getAttribute('data-provider');
263
+ if (provider) {
264
+ button.addEventListener('click', () => signIn(provider));
265
+ }
266
+ });
267
+ </script>
@@ -0,0 +1,63 @@
1
+ // pages/directory/[type]/index.page.ts
2
+ import { isSSR } from '@utils/feature';
3
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
4
+
5
+ export class Page extends HybridPage {
6
+ static get prerender(): boolean {
7
+ return !isSSR();
8
+ }
9
+
10
+ static async getStaticPaths(): Promise<Array<{ params: any; props: any }>> {
11
+ const { getUsers } = await import('@utils/users');
12
+ const { getTeams } = await import('@utils/teams');
13
+
14
+ const loaders = {
15
+ users: getUsers,
16
+ teams: getTeams,
17
+ };
18
+
19
+ const itemTypes = ['users', 'teams'] as const;
20
+ const allItems = await Promise.all(itemTypes.map((type) => loaders[type]()));
21
+
22
+ return allItems.flatMap((items, index) => ({
23
+ params: {
24
+ type: itemTypes[index],
25
+ },
26
+ props: {
27
+ data: items,
28
+ type: itemTypes[index],
29
+ },
30
+ }));
31
+ }
32
+
33
+ protected static async fetchData(params: any) {
34
+ const { type } = params;
35
+
36
+ if (!type) {
37
+ return null;
38
+ }
39
+
40
+ const { getUsers } = await import('@utils/users');
41
+ const { getTeams } = await import('@utils/teams');
42
+
43
+ const loaders = {
44
+ users: getUsers,
45
+ teams: getTeams,
46
+ };
47
+
48
+ // Get all items of the specified type
49
+ const items = await loaders[type as keyof typeof loaders]();
50
+
51
+ return {
52
+ type,
53
+ data: items,
54
+ };
55
+ }
56
+
57
+ protected static createNotFoundResponse(): Response {
58
+ return new Response(null, {
59
+ status: 404,
60
+ statusText: 'Directory type not found',
61
+ });
62
+ }
63
+ }
@@ -1,30 +1,13 @@
1
1
  ---
2
- import { getUsers } from '@utils/users';
3
- import { getTeams } from '@utils/teams';
2
+ import type { CollectionEntry } from 'astro:content';
4
3
 
5
4
  import DirectoryLayout, { type Props as DirectoryLayoutProps } from '@layouts/DirectoryLayout.astro';
5
+ import { Page } from './_index.data';
6
6
 
7
- export async function getStaticPaths() {
8
- const loaders = {
9
- users: getUsers,
10
- teams: getTeams,
11
- };
12
-
13
- const itemTypes = ['users', 'teams'] as const;
14
- const allItems = await Promise.all(itemTypes.map((type) => loaders[type]()));
15
-
16
- return allItems.flatMap((items, index) => ({
17
- params: {
18
- type: itemTypes[index],
19
- },
20
- props: {
21
- data: items,
22
- type: itemTypes[index],
23
- },
24
- }));
25
- }
7
+ export const prerender = Page.prerender;
8
+ export const getStaticPaths = Page.getStaticPaths;
26
9
 
27
- const { type, data } = Astro.props;
10
+ const { type, data } = await Page.getData(Astro);
28
11
 
29
12
  function mapToItem(i: any) {
30
13
  return {
@@ -42,7 +25,7 @@ function mapToItem(i: any) {
42
25
  title={`${type} (${data.length})`}
43
26
  subtitle={`Find, filter and search for any ${type} in your system.`}
44
27
  data={data.map(
45
- (d) =>
28
+ (d: CollectionEntry<'users' | 'teams'>) =>
46
29
  ({
47
30
  collection: d.collection,
48
31
  data: {
@@ -0,0 +1,62 @@
1
+ // pages/discover/[type]/index.page.ts
2
+ import { isSSR } from '@utils/feature';
3
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
4
+ import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
5
+
6
+ export class Page extends HybridPage {
7
+ static get prerender(): boolean {
8
+ return !isSSR();
9
+ }
10
+
11
+ static async getStaticPaths(): Promise<Array<{ params: any; props: any }>> {
12
+ const { getFlows } = await import('@utils/collections/flows');
13
+
14
+ const loaders = {
15
+ ...pageDataLoader,
16
+ flows: getFlows,
17
+ };
18
+
19
+ const itemTypes = ['events', 'commands', 'queries', 'services', 'domains', 'flows'] as const;
20
+ const allItems = await Promise.all(itemTypes.map((type) => loaders[type]()));
21
+
22
+ return allItems.flatMap((items, index) => ({
23
+ params: {
24
+ type: itemTypes[index],
25
+ },
26
+ props: {
27
+ data: items,
28
+ type: itemTypes[index],
29
+ },
30
+ }));
31
+ }
32
+
33
+ protected static async fetchData(params: any) {
34
+ const { type } = params;
35
+
36
+ if (!type) {
37
+ return null;
38
+ }
39
+
40
+ const { getFlows } = await import('@utils/collections/flows');
41
+
42
+ const loaders = {
43
+ ...pageDataLoader,
44
+ flows: getFlows,
45
+ };
46
+
47
+ // @ts-ignore
48
+ const items = await loaders[type]();
49
+
50
+ return {
51
+ type,
52
+ data: items,
53
+ };
54
+ }
55
+
56
+ protected static createNotFoundResponse(): Response {
57
+ return new Response(null, {
58
+ status: 404,
59
+ statusText: 'Collection type not found',
60
+ });
61
+ }
62
+ }
@@ -1,30 +1,13 @@
1
1
  ---
2
+ import type { CollectionEntry } from 'astro:content';
3
+ import type { CollectionTypes } from '@types';
2
4
  import DiscoverLayout, { type Props as DiscoverLayoutProps } from '@layouts/DiscoverLayout.astro';
3
- import { getFlows } from '@utils/collections/flows';
5
+ import { Page } from './_index.data';
4
6
 
5
- import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
7
+ export const prerender = Page.prerender;
8
+ export const getStaticPaths = Page.getStaticPaths;
6
9
 
7
- export async function getStaticPaths() {
8
- const loaders = {
9
- ...pageDataLoader,
10
- flows: getFlows,
11
- };
12
-
13
- const itemTypes = ['events', 'commands', 'queries', 'services', 'domains', 'flows'] as const;
14
- const allItems = await Promise.all(itemTypes.map((type) => loaders[type]()));
15
-
16
- return allItems.flatMap((items, index) => ({
17
- params: {
18
- type: itemTypes[index],
19
- },
20
- props: {
21
- data: items,
22
- type: itemTypes[index],
23
- },
24
- }));
25
- }
26
-
27
- const { type, data } = Astro.props;
10
+ const { type, data } = await Page.getData(Astro);
28
11
 
29
12
  function mapToItem(i: any) {
30
13
  return {
@@ -42,7 +25,7 @@ function mapToItem(i: any) {
42
25
  title={`${type} (${data.length})`}
43
26
  subtitle={`Find, filter and search for any ${type} in your system.`}
44
27
  data={data.map(
45
- (d) =>
28
+ (d: CollectionEntry<CollectionTypes>) =>
46
29
  ({
47
30
  collection: d.collection,
48
31
  data: {
@@ -0,0 +1,62 @@
1
+ import { isSSR } from '@utils/feature';
2
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
3
+ import type { PageTypes } from '@types';
4
+ import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
5
+
6
+ /**
7
+ * Documentation page class for all collection types with versioning
8
+ */
9
+ export class Page extends HybridPage {
10
+ static async getStaticPaths() {
11
+ if (isSSR()) {
12
+ return [];
13
+ }
14
+
15
+ const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains', 'flows', 'channels', 'entities'];
16
+ const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
17
+
18
+ return allItems.flatMap((items, index) =>
19
+ items.map((item) => ({
20
+ params: {
21
+ type: itemTypes[index],
22
+ id: item.data.id,
23
+ version: item.data.version,
24
+ },
25
+ props: {
26
+ type: itemTypes[index],
27
+ ...item,
28
+ },
29
+ }))
30
+ );
31
+ }
32
+
33
+ protected static async fetchData(params: any) {
34
+ const { type, id, version } = params;
35
+
36
+ if (!type || !id || !version) {
37
+ return null;
38
+ }
39
+
40
+ // Get all items of the specified type
41
+ const items = await pageDataLoader[type as PageTypes]();
42
+
43
+ // Find the specific item by id and version
44
+ const item = items.find((i) => i.data.id === id && i.data.version === version);
45
+
46
+ if (!item) {
47
+ return null;
48
+ }
49
+
50
+ return {
51
+ type,
52
+ ...item,
53
+ };
54
+ }
55
+
56
+ protected static createNotFoundResponse(): Response {
57
+ return new Response(null, {
58
+ status: 404,
59
+ statusText: 'Documentation not found',
60
+ });
61
+ }
62
+ }
@@ -5,53 +5,21 @@ import { renderToString } from 'react-dom/server';
5
5
  import { Parser } from '@asyncapi/parser';
6
6
  import { AvroSchemaParser } from '@asyncapi/avro-schema-parser';
7
7
  import fs from 'fs';
8
- import { getSpecificationsForService } from '@utils/collections/services';
9
- import type { CollectionTypes, PageTypes } from '@types';
10
8
 
11
9
  import '@asyncapi/react-component/styles/default.min.css';
12
10
  import js from '@asyncapi/react-component/browser/standalone/without-parser.js?url';
13
11
  import { AsyncApiComponentWP, type ConfigInterface } from '@asyncapi/react-component';
14
- import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
15
- import type { CollectionEntry } from 'astro:content';
16
12
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
17
13
  import Config from '@utils/eventcatalog-config/catalog';
14
+ import { Page } from './_[filename].data';
18
15
 
19
- export async function getStaticPaths() {
20
- const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains'];
21
- const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
16
+ export const prerender = Page.prerender;
17
+ export const getStaticPaths = Page.getStaticPaths;
22
18
 
23
- const hasSpecifications = (item: CollectionEntry<CollectionTypes>) => {
24
- const specifications = getSpecificationsForService(item);
25
- // Ensure there is at least one 'asyncapi' specification
26
- return specifications && specifications.some((spec) => spec.type === 'asyncapi');
27
- };
28
-
29
- const filteredItems = allItems.map((items) => items.filter(hasSpecifications));
30
-
31
- return filteredItems.flatMap((items, index) =>
32
- items.flatMap((item) => {
33
- const asyncApiSpecifications = getSpecificationsForService(item).filter((spec) => spec.type === 'asyncapi');
34
-
35
- return asyncApiSpecifications.map((spec) => ({
36
- params: {
37
- type: itemTypes[index],
38
- id: item.data.id,
39
- version: item.data.version,
40
- filename: spec.filenameWithoutExtension || spec.type,
41
- },
42
- props: {
43
- type: itemTypes[index],
44
- filenameWithoutExtension: spec.filenameWithoutExtension || spec.type,
45
- filename: spec.filename || spec.type,
46
- ...item,
47
- },
48
- }));
49
- })
50
- );
51
- }
19
+ // Get data
20
+ const { collection, data, filePath, filename } = await Page.getData(Astro);
52
21
 
53
22
  // @ts-ignore
54
- const { collection, catalog, data, filePath, filename } = Astro.props;
55
23
  const fileName = filename || 'asyncapi.yaml';
56
24
  const directory = path.dirname(filePath || '');
57
25
  const pathToSpec = path.join(directory, fileName);