@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,156 @@
1
+ import { defineConfig } from 'auth-astro';
2
+ import { join } from 'node:path';
3
+ import GitHub from '@auth/core/providers/github';
4
+ import Okta from '@auth/core/providers/okta';
5
+ import type { Account, Profile, User, Session } from '@auth/core/types';
6
+ import { isAuthEnabled, isSSR } from '@utils/feature';
7
+ import Google from '@auth/core/providers/google';
8
+ import Auth0 from '@auth/core/providers/auth0';
9
+
10
+ // Need to try and read the eventcatalog.auth.js file and get the auth providers from there
11
+ const catalogDirectory = process.env.PROJECT_DIR || process.cwd();
12
+
13
+ const getAuthProviders = async () => {
14
+ try {
15
+ const config = await import(/* @vite-ignore */ join(catalogDirectory, 'eventcatalog.auth.js'));
16
+ const authConfig = config.default;
17
+
18
+ const providers = [];
19
+
20
+ // GitHub provider
21
+ if (authConfig.providers?.github) {
22
+ const githubConfig = authConfig.providers.github;
23
+ providers.push(
24
+ GitHub({
25
+ clientId: githubConfig.clientId,
26
+ clientSecret: githubConfig.clientSecret,
27
+ })
28
+ );
29
+ console.log('✅ GitHub provider configured');
30
+ }
31
+
32
+ // Google provider
33
+ if (authConfig.providers?.google) {
34
+ const googleConfig = authConfig.providers.google;
35
+ providers.push(
36
+ Google({
37
+ clientId: googleConfig.clientId,
38
+ clientSecret: googleConfig.clientSecret,
39
+ })
40
+ );
41
+ console.log('✅ Google provider configured');
42
+ }
43
+
44
+ // Okta provider
45
+ if (authConfig.providers?.okta) {
46
+ const oktaConfig = authConfig.providers.okta;
47
+ providers.push(
48
+ Okta({
49
+ clientId: oktaConfig.clientId,
50
+ clientSecret: oktaConfig.clientSecret,
51
+ issuer: oktaConfig.issuer,
52
+ })
53
+ );
54
+ console.log('✅ Okta provider configured');
55
+ }
56
+
57
+ // Auth0 provider
58
+ if (authConfig.providers?.auth0) {
59
+ const auth0Config = authConfig.providers.auth0;
60
+ providers.push(
61
+ Auth0({
62
+ clientId: auth0Config.clientId,
63
+ clientSecret: auth0Config.clientSecret,
64
+ issuer: auth0Config.issuer,
65
+ })
66
+ );
67
+ console.log('✅ Auth0 provider configured');
68
+ }
69
+
70
+ if (providers.length === 0) {
71
+ console.warn('⚠️ No auth providers configured');
72
+ }
73
+
74
+ return providers;
75
+ } catch (error) {
76
+ console.log('No eventcatalog.auth.js found or error loading config:', (error as Error).message);
77
+ return [];
78
+ }
79
+ };
80
+
81
+ const getAuthConfig = async () => {
82
+ // If auth is disabled or we are not in SSR, return an empty config
83
+ if (!isAuthEnabled() || !isSSR()) {
84
+ return {
85
+ providers: [],
86
+ };
87
+ }
88
+ try {
89
+ const config = await import(/* @vite-ignore */ join(catalogDirectory, 'eventcatalog.auth.js'));
90
+ const authConfig = config.default;
91
+
92
+ // If custom auth config is specified (Enterprise feature)
93
+ if (authConfig?.customAuthConfig) {
94
+ console.log('🚀 Loading custom auth configuration:', authConfig.customAuthConfig);
95
+ try {
96
+ const customConfig = await import(/* @vite-ignore */ join(catalogDirectory, authConfig.customAuthConfig));
97
+ return customConfig.default;
98
+ } catch (error) {
99
+ console.error('❌ Failed to load custom auth config:', error);
100
+ // Fall back to managed config
101
+ }
102
+ }
103
+
104
+ // Return managed auth config
105
+ const providers = await getAuthProviders();
106
+
107
+ return {
108
+ providers,
109
+ callbacks: {
110
+ async signIn({ user, account, profile }: { user: User; account: Account | null; profile?: Profile }) {
111
+ // Just allow everyone who can authenticate with the provider
112
+ return true;
113
+ },
114
+ async session({ session, token }: { session: Session; token: any }) {
115
+ // Add provider info to session
116
+ if (token?.provider) {
117
+ (session.user as any).provider = token.provider;
118
+ }
119
+ if (token?.login) {
120
+ (session.user as any).username = token.login;
121
+ }
122
+ return session;
123
+ },
124
+ async jwt({ token, account, profile }: { token: any; account: Account | null; profile?: Profile }) {
125
+ // Persist provider info in JWT
126
+ if (account && profile) {
127
+ token.provider = account.provider;
128
+ token.login = (profile as any).login || (profile as any).preferred_username;
129
+ }
130
+ return token;
131
+ },
132
+ },
133
+ pages: {
134
+ signIn: '/auth/login',
135
+ error: '/auth/error',
136
+ },
137
+ session: {
138
+ strategy: 'jwt' as const,
139
+ maxAge: authConfig?.session?.maxAge || 30 * 24 * 60 * 60, // 30 days default
140
+ },
141
+ debug: authConfig?.debug || false,
142
+ };
143
+ } catch (error) {
144
+ console.log(
145
+ 'No auth config found, auth disabled. If you want to use auth, create a eventcatalog.auth.js file in your project directory.'
146
+ );
147
+ return {
148
+ providers: [],
149
+ pages: {
150
+ signIn: '/auth/disabled',
151
+ },
152
+ };
153
+ }
154
+ };
155
+
156
+ export default defineConfig(await getAuthConfig());
@@ -3,6 +3,13 @@ import catalog from '@utils/eventcatalog-config/catalog';
3
3
  import Search from '@components/Search.astro';
4
4
  import { buildUrl } from '@utils/url-builder';
5
5
  import { showEventCatalogBranding, showCustomBranding } from '@utils/feature';
6
+ import { getSession } from 'auth-astro/server';
7
+ import { isAuthEnabled, isSSR } from '@utils/feature';
8
+
9
+ let session = null;
10
+ if (isAuthEnabled()) {
11
+ session = await getSession(Astro.request);
12
+ }
6
13
 
7
14
  const logo = {
8
15
  src: ('/' + (catalog?.logo?.src || 'logo.png')).replace(/^\/+/, '/'),
@@ -27,35 +34,94 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
27
34
  </div>
28
35
 
29
36
  <div class="hidden lg:block flex-grow w-6/12 px-10">
30
- <Search />
37
+ <!-- Page find only works on static builds, disable for SSR builds for now -->
38
+ {!isSSR() && <Search />}
31
39
  </div>
32
40
 
33
41
  <div class="hidden md:block w-3/12">
34
42
  {
35
- showEventCatalogBranding() && (
36
- <ul class="flex space-x-8 justify-end pr-2">
37
- <li>
38
- <a href="https://discord.com/invite/3rjaZMmrAm">
39
- <img src={buildUrl('/icons/discord.svg', true)} class="h-7 w-7" />
40
- </a>
41
- </li>
42
- <li>
43
- <a href="https://github.com/event-catalog/eventcatalog">
44
- <img src={buildUrl('/icons/github.svg', true)} class="h-7 w-7" />
45
- </a>
46
- </li>
47
- </ul>
48
- )
49
- }
50
- {
51
- showCustomBranding() && !showEventCatalogBranding() && (
52
- <ul class="flex space-x-8 justify-end pr-2">
53
- <li>
54
- <a href={repositoryUrl} class="text-gray-500 hover:text-gray-600 focus:outline-none focus:text-gray-600">
55
- <img src={buildUrl('/icons/github.svg', true)} class="h-7 w-7" />
56
- </a>
57
- </li>
58
- </ul>
43
+ session ? (
44
+ <div class="flex justify-end pr-2">
45
+ <div class="relative">
46
+ <button
47
+ id="profile-menu-button"
48
+ type="button"
49
+ class="flex items-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 rounded-full"
50
+ aria-expanded="false"
51
+ aria-haspopup="true"
52
+ >
53
+ {session.user?.image && !session.user?.image?.includes('googleusercontent.com') ? (
54
+ <img
55
+ src={session.user.image}
56
+ alt={session.user?.name || 'User'}
57
+ class="h-8 w-8 rounded-full border-2 border-gray-200 hover:border-gray-300 transition-colors"
58
+ />
59
+ ) : (
60
+ <div class="h-8 w-8 rounded-full border-2 border-gray-200 hover:border-gray-300 transition-colors bg-gray-100 flex items-center justify-center text-sm font-medium text-gray-600">
61
+ {session.user?.name
62
+ ? session.user.name
63
+ .split(' ')
64
+ .map((n) => n[0])
65
+ .join('')
66
+ .substring(0, 2)
67
+ .toUpperCase()
68
+ : 'U'}
69
+ </div>
70
+ )}
71
+ </button>
72
+ <div
73
+ id="profile-dropdown"
74
+ class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50 border border-gray-100"
75
+ >
76
+ <div class="px-4 py-2 text-sm text-gray-700 border-b border-gray-100">
77
+ <div class="font-medium">{session.user?.name || 'User'}</div>
78
+ {session.user?.email && <div class="text-gray-500">{session.user.email}</div>}
79
+ </div>
80
+ <button
81
+ id="signout-btn"
82
+ class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors"
83
+ >
84
+ Sign out
85
+ </button>
86
+ </div>
87
+ </div>
88
+ </div>
89
+ ) : (
90
+ <>
91
+ <div class="flex items-center space-x-4 justify-end pr-2">
92
+ {isAuthEnabled() && (
93
+ <button
94
+ id="okta-signin-btn"
95
+ class="bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium px-4 py-2 rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
96
+ >
97
+ Sign In
98
+ </button>
99
+ )}
100
+ {showEventCatalogBranding() && (
101
+ <ul class="flex space-x-8">
102
+ <li>
103
+ <a href="https://discord.com/invite/3rjaZMmrAm">
104
+ <img src={buildUrl('/icons/discord.svg', true)} class="h-7 w-7" />
105
+ </a>
106
+ </li>
107
+ <li>
108
+ <a href="https://github.com/event-catalog/eventcatalog">
109
+ <img src={buildUrl('/icons/github.svg', true)} class="h-7 w-7" />
110
+ </a>
111
+ </li>
112
+ </ul>
113
+ )}
114
+ {showCustomBranding() && !showEventCatalogBranding() && (
115
+ <ul class="flex space-x-8">
116
+ <li>
117
+ <a href={repositoryUrl} class="text-gray-500 hover:text-gray-600 focus:outline-none focus:text-gray-600">
118
+ <img src={buildUrl('/icons/github.svg', true)} class="h-7 w-7" />
119
+ </a>
120
+ </li>
121
+ </ul>
122
+ )}
123
+ </div>
124
+ </>
59
125
  )
60
126
  }
61
127
  </div>
@@ -100,12 +166,46 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
100
166
  <script>
101
167
  const menuToggle = document.getElementById('menu-toggle');
102
168
  const mobileMenu = document.getElementById('mobile-menu');
169
+ import { signOut } from 'auth-astro/client';
103
170
 
104
171
  if (menuToggle && mobileMenu) {
105
172
  menuToggle.addEventListener('click', () => {
106
173
  mobileMenu.classList.toggle('hidden');
107
174
  });
108
175
  }
176
+
177
+ // Profile dropdown functionality
178
+ const profileButton = document.getElementById('profile-menu-button');
179
+ const profileDropdown = document.getElementById('profile-dropdown');
180
+
181
+ if (profileButton && profileDropdown) {
182
+ profileButton.addEventListener('click', (e) => {
183
+ e.stopPropagation();
184
+ profileDropdown.classList.toggle('hidden');
185
+ profileButton.setAttribute('aria-expanded', !profileDropdown.classList.contains('hidden') ? 'true' : 'false');
186
+ });
187
+
188
+ // Close dropdown when clicking outside
189
+ document.addEventListener('click', (e) => {
190
+ if (!profileButton.contains(e.target as Node) && !profileDropdown.contains(e.target as Node)) {
191
+ profileDropdown.classList.add('hidden');
192
+ profileButton.setAttribute('aria-expanded', 'false');
193
+ }
194
+ });
195
+
196
+ // Close dropdown on escape key
197
+ document.addEventListener('keydown', (e) => {
198
+ if (e.key === 'Escape' && !profileDropdown.classList.contains('hidden')) {
199
+ profileDropdown.classList.add('hidden');
200
+ profileButton.setAttribute('aria-expanded', 'false');
201
+ profileButton.focus();
202
+ }
203
+ });
204
+
205
+ document.getElementById('signout-btn')?.addEventListener('click', async () => {
206
+ await signOut();
207
+ });
208
+ }
109
209
  </script>
110
210
 
111
211
  <style>
@@ -0,0 +1,62 @@
1
+ // src/middleware.ts
2
+ import type { MiddlewareHandler } from 'astro';
3
+ import { getSession } from 'auth-astro/server';
4
+ import { isAuthEnabled } from '@utils/feature';
5
+
6
+ export const onRequest: MiddlewareHandler = async (context, next) => {
7
+ const { request, redirect, locals } = context;
8
+ const url = new URL(request.url);
9
+ const pathname = url.pathname;
10
+
11
+ // If auth is disabled and we are on an auth route, redirect to home
12
+ if (!isAuthEnabled() && pathname.includes('/auth')) {
13
+ return redirect('/');
14
+ }
15
+
16
+ // Auth is disabled, skip auth check
17
+ if (!isAuthEnabled()) {
18
+ return next();
19
+ }
20
+
21
+ // Skip system/browser requests
22
+ const systemRoutes = ['/.well-known/', '/favicon.ico', '/robots.txt', '/sitemap.xml', '/_astro/', '/__astro'];
23
+
24
+ // Skip auth check for these routes
25
+ const publicRoutes = ['/auth/login', '/auth/signout', '/auth/error', '/api/auth'];
26
+
27
+ // Skip static files, system routes, and browser requests
28
+ if (
29
+ pathname.startsWith('/_') ||
30
+ systemRoutes.some((route) => pathname.startsWith(route)) ||
31
+ pathname.startsWith('/.well-known/')
32
+ ) {
33
+ return next();
34
+ }
35
+
36
+ // Skip public routes
37
+ if (publicRoutes.some((route) => pathname.startsWith(route))) {
38
+ return next();
39
+ }
40
+
41
+ try {
42
+ // Check if user is logged in
43
+ const session = await getSession(request);
44
+
45
+ if (!session) {
46
+ const callbackUrl = encodeURIComponent(pathname + url.search);
47
+ return redirect(`/auth/login?callbackUrl=${callbackUrl}`);
48
+ }
49
+
50
+ // Add session to locals for pages to use
51
+ // @ts-ignore
52
+ locals.session = session;
53
+ // @ts-ignore
54
+ locals.user = session.user;
55
+ } catch (error) {
56
+ console.error('Session error:', error);
57
+ const callbackUrl = encodeURIComponent(pathname + url.search);
58
+ return redirect(`/auth/login?callbackUrl=${callbackUrl}`);
59
+ }
60
+
61
+ return next();
62
+ };
@@ -0,0 +1,55 @@
1
+ ---
2
+ // src/pages/auth/error.astro
3
+
4
+ const { searchParams } = new URL(Astro.request.url);
5
+ const error = searchParams.get('error');
6
+
7
+ const errorMessages = {
8
+ Configuration: 'There is a problem with the server configuration.',
9
+ AccessDenied: 'You do not have permission to access this resource.',
10
+ Verification: 'The verification token has expired or has already been used.',
11
+ Default: 'An error occurred during authentication.',
12
+ };
13
+
14
+ // @ts-ignore
15
+ const errorMessage = errorMessages[error] || errorMessages.Default;
16
+ ---
17
+
18
+ <main title="Authentication Error - EventCatalog">
19
+ <div class="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
20
+ <div class="max-w-md w-full space-y-8 text-center">
21
+ <div>
22
+ <svg class="mx-auto h-12 w-12 text-red-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
23
+ <path
24
+ stroke-linecap="round"
25
+ stroke-linejoin="round"
26
+ stroke-width="2"
27
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
28
+ ></path>
29
+ </svg>
30
+ <h2 class="mt-6 text-3xl font-bold text-gray-900">Authentication Error</h2>
31
+ <p class="mt-2 text-sm text-gray-600">
32
+ {errorMessage}
33
+ </p>
34
+ </div>
35
+
36
+ <div class="space-y-4">
37
+ <a
38
+ href="/auth/login"
39
+ class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
40
+ >
41
+ Try Again
42
+ </a>
43
+
44
+ <a
45
+ href="/"
46
+ class="w-full flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
47
+ >
48
+ Back to Home
49
+ </a>
50
+ </div>
51
+
52
+ {error && <div class="mt-8 text-xs text-gray-400">Error code: {error}</div>}
53
+ </div>
54
+ </div>
55
+ </main>