@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,98 @@
1
+ // pages/docs/[type]/[id]/[version]/asyncapi/[filename]/index.page.ts
2
+ import { isSSR, isAuthEnabled } from '@utils/feature';
3
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
4
+ import type { CollectionEntry } from 'astro:content';
5
+ import type { CollectionTypes, PageTypes } from '@types';
6
+
7
+ export class Page extends HybridPage {
8
+ static get prerender(): boolean {
9
+ return !isSSR();
10
+ }
11
+
12
+ static async getStaticPaths(): Promise<Array<{ params: any; props: any }>> {
13
+ if (isSSR()) {
14
+ return [];
15
+ }
16
+
17
+ const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
18
+ const { getSpecificationsForService } = await import('@utils/collections/services');
19
+
20
+ const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains'];
21
+ const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
22
+
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
+ }
52
+
53
+ protected static async fetchData(params: any) {
54
+ const { type, id, version, filename } = params;
55
+
56
+ if (!type || !id || !version || !filename) {
57
+ return null;
58
+ }
59
+
60
+ const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
61
+ const { getSpecificationsForService } = await import('@utils/collections/services');
62
+
63
+ // Get all items of the specified type
64
+ const items = await pageDataLoader[type as PageTypes]();
65
+
66
+ // Find the specific item by id and version
67
+ const item = items.find((i) => i.data.id === id && i.data.version === version);
68
+
69
+ if (!item) {
70
+ return null;
71
+ }
72
+
73
+ // Check if this item has AsyncAPI specifications
74
+ const specifications = getSpecificationsForService(item);
75
+ const asyncApiSpecifications = specifications.filter((spec) => spec.type === 'asyncapi');
76
+
77
+ // Find the specific specification
78
+ const spec = asyncApiSpecifications.find((s) => (s.filenameWithoutExtension || s.type) === filename);
79
+
80
+ if (!spec) {
81
+ return null;
82
+ }
83
+
84
+ return {
85
+ type,
86
+ filenameWithoutExtension: spec.filenameWithoutExtension || spec.type,
87
+ filename: spec.filename || spec.type,
88
+ ...item,
89
+ };
90
+ }
91
+
92
+ protected static createNotFoundResponse(): Response {
93
+ return new Response(null, {
94
+ status: 404,
95
+ statusText: 'AsyncAPI specification not found',
96
+ });
97
+ }
98
+ }
@@ -0,0 +1,68 @@
1
+ import { isSSR } from '@utils/feature';
2
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
3
+ import type { PageTypes } from '@types';
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
+ if (isSSR()) {
12
+ return [];
13
+ }
14
+
15
+ const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
16
+
17
+ const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains', 'flows'];
18
+ const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
19
+
20
+ return allItems.flatMap((items, index) =>
21
+ items.map((item) => ({
22
+ params: {
23
+ type: itemTypes[index],
24
+ id: item.data.id,
25
+ version: item.data.version,
26
+ },
27
+ props: {
28
+ type: itemTypes[index],
29
+ allCollectionItems: items,
30
+ ...item,
31
+ },
32
+ }))
33
+ );
34
+ }
35
+
36
+ protected static async fetchData(params: any) {
37
+ const { type, id, version } = params;
38
+
39
+ if (!type || !id || !version) {
40
+ return null;
41
+ }
42
+
43
+ const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
44
+
45
+ // Get all items of the specified type
46
+ const items = await pageDataLoader[type as PageTypes]();
47
+
48
+ // Find the specific item by id and version
49
+ const item = items.find((i) => i.data.id === id && i.data.version === version);
50
+
51
+ if (!item) {
52
+ return null;
53
+ }
54
+
55
+ return {
56
+ type,
57
+ allCollectionItems: items,
58
+ ...item,
59
+ };
60
+ }
61
+
62
+ protected static createNotFoundResponse(): Response {
63
+ return new Response(null, {
64
+ status: 404,
65
+ statusText: 'Changelog not found',
66
+ });
67
+ }
68
+ }
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  import Footer from '@layouts/Footer.astro';
3
- import type { PageTypes } from '@types';
4
3
  import { getChangeLogs } from '@utils/collections/changelogs';
5
4
  import {
6
5
  RectangleGroupIcon,
@@ -10,7 +9,6 @@ import {
10
9
  MagnifyingGlassIcon,
11
10
  QueueListIcon,
12
11
  } from '@heroicons/react/24/outline';
13
- import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
14
12
  import { render, getEntry } from 'astro:content';
15
13
  import mdxComponents from '@components/MDX/components';
16
14
  import 'diff2html/bundles/css/diff2html.min.css';
@@ -20,38 +18,20 @@ import { getPreviousVersion } from '@utils/collections/util';
20
18
  import { getDiffsForCurrentAndPreviousVersion } from '@utils/collections/file-diffs';
21
19
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
22
20
  import { ClientRouter } from 'astro:transitions';
23
-
24
21
  import { isChangelogEnabled } from '@utils/feature';
25
22
 
26
- export async function getStaticPaths() {
27
- if (!isChangelogEnabled()) {
28
- return [];
29
- }
23
+ import { Page } from './_index.data';
30
24
 
31
- const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains', 'flows'];
32
- const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
25
+ export const prerender = Page.prerender;
26
+ export const getStaticPaths = Page.getStaticPaths;
33
27
 
34
- return allItems.flatMap((items, index) =>
35
- items.map((item) => ({
36
- params: {
37
- type: itemTypes[index],
38
- id: item.data.id,
39
- version: item.data.version,
40
- },
41
- props: {
42
- type: itemTypes[index],
43
- allCollectionItems: items,
44
- ...item,
45
- },
46
- }))
47
- );
48
- }
28
+ // Get data
29
+ const props = await Page.getData(Astro);
49
30
 
50
31
  if (!isChangelogEnabled()) {
51
32
  return Astro.redirect('/docs');
52
33
  }
53
34
 
54
- const props = Astro.props;
55
35
  let collectionItem = props;
56
36
  const logs = await getChangeLogs(props);
57
37
 
@@ -31,7 +31,6 @@ import {
31
31
  } from '@heroicons/react/24/outline';
32
32
  import { ArrowsRightLeftIcon } from '@heroicons/react/20/solid';
33
33
  import { Box, Boxes } from 'lucide-react';
34
- import type { PageTypes } from '@types';
35
34
  import type { CollectionTypes } from '@types';
36
35
 
37
36
  import { ClientRouter } from 'astro:transitions';
@@ -40,7 +39,6 @@ import type { CollectionEntry } from 'astro:content';
40
39
 
41
40
  import { getIcon } from '@utils/badges';
42
41
  import { getDeprecatedDetails } from '@utils/collections/util';
43
- import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
44
42
  import { buildUrl } from '@utils/url-builder';
45
43
  import { getSchemasFromResource } from '@utils/collections/schemas';
46
44
  import { isEventCatalogChatEnabled, isMarkdownDownloadEnabled } from '@utils/feature';
@@ -48,38 +46,21 @@ import { isEventCatalogChatEnabled, isMarkdownDownloadEnabled } from '@utils/fea
48
46
  import { getMDXComponentsByName } from '@utils/markdown';
49
47
 
50
48
  import config from '@config';
49
+ import { Page } from './_index.data';
51
50
 
52
- export async function getStaticPaths() {
53
- const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains', 'flows', 'channels', 'entities'];
54
- const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
51
+ export const prerender = Page.prerender;
52
+ export const getStaticPaths = Page.getStaticPaths;
55
53
 
56
- return allItems.flatMap((items, index) =>
57
- items.map((item) => ({
58
- params: {
59
- type: itemTypes[index],
60
- id: item.data.id,
61
- version: item.data.version,
62
- },
63
- props: {
64
- type: itemTypes[index],
65
- ...item,
66
- },
67
- }))
68
- );
69
- }
70
-
71
- const props = Astro.props;
54
+ // Get data
55
+ const props = await Page.getData(Astro);
72
56
 
73
57
  const { Content } = await render(props);
74
58
 
75
- // const { Content } = await props.render();
76
-
77
- // Capitalize the first letter of a string
78
59
  const pageTitle = `${props.collection} | ${props.data.name}`.replace(/^\w/, (c) => c.toUpperCase());
79
60
  const contentBadges = props.data.badges || [];
80
61
 
81
62
  const getContentBadges = () =>
82
- contentBadges.map((badge) => ({
63
+ contentBadges.map((badge: any) => ({
83
64
  ...badge,
84
65
  icon: badge.icon ? getIcon(badge.icon) : null,
85
66
  }));
@@ -11,45 +11,16 @@ import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
11
11
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
12
12
  import { getSpecificationsForService } from '@utils/collections/services';
13
13
  import './_styles.css';
14
+ import { Page } from './_[filename].data.ts';
14
15
 
15
- export async function getStaticPaths() {
16
- const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains'];
16
+ export const prerender = Page.prerender;
17
+ export const getStaticPaths = Page.getStaticPaths;
17
18
 
18
- const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
19
-
20
- const hasSpecifications = (item: CollectionEntry<CollectionTypes>) => {
21
- const specifications = getSpecificationsForService(item);
22
- // Ensure there is at least one 'openapi' specification
23
- return specifications && specifications.some((spec) => spec.type === 'openapi');
24
- };
25
-
26
- const filteredItems = allItems.map((items) => items.filter(hasSpecifications));
27
-
28
- return filteredItems.flatMap((items, index) =>
29
- items.flatMap((item) => {
30
- // Filter for openapi specifications only
31
- const openApiSpecifications = getSpecificationsForService(item).filter((spec) => spec.type === 'openapi');
32
-
33
- return openApiSpecifications.map((spec) => ({
34
- params: {
35
- type: itemTypes[index],
36
- id: item.data.id,
37
- version: item.data.version,
38
- filename: spec.filenameWithoutExtension || spec.type,
39
- },
40
- props: {
41
- type: itemTypes[index],
42
- filenameWithoutExtension: spec.filenameWithoutExtension || spec.type,
43
- filename: spec.filename || spec.type,
44
- ...item,
45
- },
46
- }));
47
- })
48
- );
49
- }
19
+ // Get data
20
+ const props = await Page.getData(Astro);
50
21
 
51
22
  // @ts-ignore
52
- const { collection, data, catalog, filePath, filename } = Astro.props;
23
+ const { collection, data, catalog, filePath, filename } = props;
53
24
  const fileName = filename || 'openapi.yml';
54
25
 
55
26
  const directory = path.dirname(filePath || '');
@@ -0,0 +1,99 @@
1
+ // pages/docs/[type]/[id]/[version]/spec/[filename]/index.page.ts
2
+ import { isSSR } from '@utils/feature';
3
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
4
+ import type { CollectionEntry } from 'astro:content';
5
+ import type { CollectionTypes, PageTypes } from '@types';
6
+
7
+ export class Page extends HybridPage {
8
+ static get prerender(): boolean {
9
+ return !isSSR();
10
+ }
11
+
12
+ static async getStaticPaths(): Promise<Array<{ params: any; props: any }>> {
13
+ if (isSSR()) {
14
+ return [];
15
+ }
16
+
17
+ const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
18
+ const { getSpecificationsForService } = await import('@utils/collections/services');
19
+
20
+ const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains'];
21
+ const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
22
+
23
+ const hasSpecifications = (item: CollectionEntry<CollectionTypes>) => {
24
+ const specifications = getSpecificationsForService(item);
25
+ // Ensure there is at least one 'openapi' specification
26
+ return specifications && specifications.some((spec) => spec.type === 'openapi');
27
+ };
28
+
29
+ const filteredItems = allItems.map((items) => items.filter(hasSpecifications));
30
+
31
+ return filteredItems.flatMap((items, index) =>
32
+ items.flatMap((item) => {
33
+ // Filter for openapi specifications only
34
+ const openApiSpecifications = getSpecificationsForService(item).filter((spec) => spec.type === 'openapi');
35
+
36
+ return openApiSpecifications.map((spec) => ({
37
+ params: {
38
+ type: itemTypes[index],
39
+ id: item.data.id,
40
+ version: item.data.version,
41
+ filename: spec.filenameWithoutExtension || spec.type,
42
+ },
43
+ props: {
44
+ type: itemTypes[index],
45
+ filenameWithoutExtension: spec.filenameWithoutExtension || spec.type,
46
+ filename: spec.filename || spec.type,
47
+ ...item,
48
+ },
49
+ }));
50
+ })
51
+ );
52
+ }
53
+
54
+ protected static async fetchData(params: any) {
55
+ const { type, id, version, filename } = params;
56
+
57
+ if (!type || !id || !version || !filename) {
58
+ return null;
59
+ }
60
+
61
+ const { pageDataLoader } = await import('@utils/page-loaders/page-data-loader');
62
+ const { getSpecificationsForService } = await import('@utils/collections/services');
63
+
64
+ // Get all items of the specified type
65
+ const items = await pageDataLoader[type as PageTypes]();
66
+
67
+ // Find the specific item by id and version
68
+ const item = items.find((i) => i.data.id === id && i.data.version === version);
69
+
70
+ if (!item) {
71
+ return null;
72
+ }
73
+
74
+ // Check if this item has OpenAPI specifications
75
+ const specifications = getSpecificationsForService(item);
76
+ const openApiSpecifications = specifications.filter((spec) => spec.type === 'openapi');
77
+
78
+ // Find the specific specification
79
+ const spec = openApiSpecifications.find((s) => (s.filenameWithoutExtension || s.type) === filename);
80
+
81
+ if (!spec) {
82
+ return null;
83
+ }
84
+
85
+ return {
86
+ type,
87
+ filenameWithoutExtension: spec.filenameWithoutExtension || spec.type,
88
+ filename: spec.filename || spec.type,
89
+ ...item,
90
+ };
91
+ }
92
+
93
+ protected static createNotFoundResponse(): Response {
94
+ return new Response(null, {
95
+ status: 404,
96
+ statusText: 'OpenAPI specification not found',
97
+ });
98
+ }
99
+ }
@@ -44,6 +44,7 @@ export async function getStaticPaths() {
44
44
  }
45
45
 
46
46
  const props = Astro.props;
47
+
47
48
  const pageTitle = `${props.collection} | ${props.data.name}`.replace(/^\w/, (c) => c.toUpperCase());
48
49
 
49
50
  const { pathname } = Astro.url;
@@ -0,0 +1,40 @@
1
+ import { isSSR } from '@utils/feature';
2
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
3
+
4
+ /**
5
+ * Domain page class with static methods
6
+ */
7
+ export class Page extends HybridPage {
8
+ static async getStaticPaths() {
9
+ if (isSSR()) {
10
+ return [];
11
+ }
12
+
13
+ const { getDomains } = await import('@utils/collections/domains');
14
+ const domains = await getDomains({ getAllVersions: false });
15
+
16
+ return domains.map((item) => ({
17
+ params: {
18
+ type: item.collection,
19
+ id: item.data.id,
20
+ },
21
+ props: {
22
+ type: item.collection,
23
+ ...item,
24
+ },
25
+ }));
26
+ }
27
+
28
+ protected static async fetchData(params: any) {
29
+ const { getDomains } = await import('@utils/collections/domains');
30
+ const domains = await getDomains({ getAllVersions: false });
31
+ return domains.find((d) => d.data.id === params.id && d.collection === params.type) || null;
32
+ }
33
+
34
+ protected static createNotFoundResponse(): Response {
35
+ return new Response(null, {
36
+ status: 404,
37
+ statusText: 'Domain not found',
38
+ });
39
+ }
40
+ }
@@ -1,35 +1,21 @@
1
1
  ---
2
2
  import Footer from '@layouts/Footer.astro';
3
3
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
4
- import { getDomains, type Domain, getUbiquitousLanguage } from '@utils/collections/domains';
4
+ import { getUbiquitousLanguage } from '@utils/collections/domains';
5
5
  import { buildUrl } from '@utils/url-builder';
6
- import type { CollectionEntry } from 'astro:content';
7
6
  import { ClientRouter } from 'astro:transitions';
8
7
  import * as LucideIcons from 'lucide-react';
9
8
 
10
- export async function getStaticPaths() {
11
- const domains = await getDomains({ getAllVersions: false });
9
+ import { Page } from './_index.data';
12
10
 
13
- const buildPages = (collection: CollectionEntry<'domains'>[]) => {
14
- return collection.map((item) => ({
15
- params: {
16
- type: item.collection,
17
- id: item.data.id,
18
- },
19
- props: {
20
- type: item.collection,
21
- ...item,
22
- },
23
- }));
24
- };
11
+ export const prerender = Page.prerender;
12
+ export const getStaticPaths = Page.getStaticPaths;
25
13
 
26
- return [...buildPages(domains)];
27
- }
14
+ // Get data
15
+ const props = await Page.getData(Astro);
28
16
 
29
- const props = Astro.props;
30
17
  const pageTitle = `${props.collection} | ${props.data.name}`.replace(/^\w/, (c) => c.toUpperCase());
31
18
  const ubiquitousLanguages = await getUbiquitousLanguage(props);
32
-
33
19
  const ubiquitousLanguage = ubiquitousLanguages[0];
34
20
  ---
35
21
 
@@ -0,0 +1,49 @@
1
+ // pages/docs/custom/[...path]/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
+ if (isSSR()) {
12
+ return [];
13
+ }
14
+
15
+ const { getCollection } = await import('astro:content');
16
+ const docs = await getCollection('customPages');
17
+
18
+ const paths = docs.map((doc) => ({
19
+ params: { path: doc.id.replace('docs/', '') },
20
+ props: doc,
21
+ }));
22
+
23
+ return paths;
24
+ }
25
+
26
+ protected static async fetchData(params: any) {
27
+ const { path } = params;
28
+
29
+ if (!path) {
30
+ return null;
31
+ }
32
+
33
+ const { getCollection } = await import('astro:content');
34
+ const docs = await getCollection('customPages');
35
+
36
+ // Find the specific doc by reconstructing the id
37
+ const docId = `docs/${Array.isArray(path) ? path.join('/') : path}`;
38
+ const doc = docs.find((d) => d.id === docId);
39
+
40
+ return doc || null;
41
+ }
42
+
43
+ protected static createNotFoundResponse(): Response {
44
+ return new Response(null, {
45
+ status: 404,
46
+ statusText: 'Custom documentation page not found',
47
+ });
48
+ }
49
+ }
@@ -1,20 +1,14 @@
1
1
  ---
2
2
  import CustomDocumentationPage from '@enterprise/custom-documentation/pages/docs/custom/index.astro';
3
- import { getCollection } from 'astro:content';
4
3
  import { buildUrl } from '@utils/url-builder';
5
- import type { GetStaticPaths } from 'astro';
6
4
  import { isCustomDocsEnabled } from '@utils/feature';
5
+ import { Page } from './_index.data';
7
6
 
8
- export const getStaticPaths = (async () => {
9
- const docs = await getCollection('customPages');
10
- const paths = docs.map((doc) => ({
11
- params: { path: doc.id.replace('docs/', '') },
12
- props: doc,
13
- }));
14
- return paths;
15
- }) satisfies GetStaticPaths;
7
+ export const prerender = Page.prerender;
8
+ export const getStaticPaths = Page.getStaticPaths;
16
9
 
17
- const props = Astro.props;
10
+ // Get data
11
+ const props = await Page.getData(Astro);
18
12
 
19
13
  if (!isCustomDocsEnabled()) {
20
14
  return Astro.redirect(buildUrl('/docs/custom/feature'));
@@ -0,0 +1,46 @@
1
+ // pages/teams/[id]/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
+ if (isSSR()) {
12
+ return [];
13
+ }
14
+
15
+ const { getTeams } = await import('@utils/teams');
16
+ const teams = await getTeams();
17
+
18
+ return teams.map((team) => ({
19
+ params: { id: team.data.id },
20
+ props: team,
21
+ }));
22
+ }
23
+
24
+ protected static async fetchData(params: any) {
25
+ const { id } = params;
26
+
27
+ if (!id) {
28
+ return null;
29
+ }
30
+
31
+ const { getTeams } = await import('@utils/teams');
32
+ const teams = await getTeams();
33
+
34
+ // Find the specific team by id
35
+ const team = teams.find((t) => t.data.id === id);
36
+
37
+ return team || null;
38
+ }
39
+
40
+ protected static createNotFoundResponse(): Response {
41
+ return new Response(null, {
42
+ status: 404,
43
+ statusText: 'Team not found',
44
+ });
45
+ }
46
+ }