+63
app/[locale]/next-data/api-data/route.ts
+63
app/[locale]/next-data/api-data/route.ts
···
1
+
import { deflateSync } from 'node:zlib';
2
+
3
+
import { VERCEL_REVALIDATE } from '@/next.constants.mjs';
4
+
import { defaultLocale } from '@/next.locales.mjs';
5
+
import type { GitHubApiFile } from '@/types';
6
+
import { getGitHubApiDocsUrl } from '@/util/gitHubUtils';
7
+
import { parseRichTextIntoPlainText } from '@/util/stringUtils';
8
+
9
+
const getPathnameForApiFile = (name: string) =>
10
+
`api/${name.replace('.md', '.html')}`;
11
+
12
+
// This is the Route Handler for the `GET` method which handles the request
13
+
// for a digest and metadata of all API pages from the Node.js Website
14
+
// @see https://nextjs.org/docs/app/building-your-application/routing/router-handlers
15
+
export const GET = async () => {
16
+
const gitHubApiResponse = await fetch(getGitHubApiDocsUrl('main'));
17
+
18
+
return gitHubApiResponse.json().then((apiDocsFiles: Array<GitHubApiFile>) => {
19
+
// maps over each api file and get the download_url, fetch the content and deflates it
20
+
const mappedApiFiles = apiDocsFiles.map(
21
+
async ({ name, path: filename, download_url }) => {
22
+
const apiFileResponse = await fetch(download_url);
23
+
24
+
// Retrieves the content as a raw text string
25
+
const source = await apiFileResponse.text();
26
+
27
+
// Removes empty/blank lines or lines just with spaces and trims each line
28
+
// from leading and trailing paddings/spaces
29
+
const cleanedContent = parseRichTextIntoPlainText(source);
30
+
31
+
const deflatedSource = deflateSync(cleanedContent).toString('base64');
32
+
33
+
return {
34
+
filename,
35
+
pathname: getPathnameForApiFile(name),
36
+
content: deflatedSource,
37
+
};
38
+
}
39
+
);
40
+
41
+
return Promise.all(mappedApiFiles).then(Response.json);
42
+
});
43
+
};
44
+
45
+
// This function generates the static paths that come from the dynamic segments
46
+
// `[locale]/next-data/api-data/` and returns an array of all available static paths
47
+
// This is used for ISR static validation and generation
48
+
export const generateStaticParams = async () => [
49
+
{ locale: defaultLocale.code },
50
+
];
51
+
52
+
// Enforces that only the paths from `generateStaticParams` are allowed, giving 404 on the contrary
53
+
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams
54
+
export const dynamicParams = false;
55
+
56
+
// Enforces that this route is used as static rendering
57
+
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic
58
+
export const dynamic = 'force-static';
59
+
60
+
// Ensures that this endpoint is invalidated and re-executed every X minutes
61
+
// so that when new deployments happen, the data is refreshed
62
+
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate
63
+
export const revalidate = VERCEL_REVALIDATE;
+2
-2
app/[locale]/next-data/page-data/route.ts
+2
-2
app/[locale]/next-data/page-data/route.ts
···
37
37
const deflatedSource = deflateSync(cleanedContent).toString('base64');
38
38
39
39
// Returns metadata of each page available on the Website
40
-
return { pathname, filename, title, description, content: deflatedSource };
40
+
return { filename, pathname, title, description, content: deflatedSource };
41
41
});
42
42
43
43
return Response.json(await Promise.all(availablePagesMetadata));
44
44
};
45
45
46
46
// This function generates the static paths that come from the dynamic segments
47
-
// `[locale]/next-data/release-data/` and returns an array of all available static paths
47
+
// `[locale]/next-data/page-data/` and returns an array of all available static paths
48
48
// This is used for ISR static validation and generation
49
49
export const generateStaticParams = async () => [
50
50
{ locale: defaultLocale.code },
+2
-2
components/Common/AvatarGroup/Avatar/index.stories.tsx
+2
-2
components/Common/AvatarGroup/Avatar/index.stories.tsx
···
1
1
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
2
2
3
3
import Avatar from '@/components/Common/AvatarGroup/Avatar';
4
-
import { githubProfileAvatarUrl } from '@/util/gitHubUtils';
4
+
import { getGitHubAvatarUrl } from '@/util/gitHubUtils';
5
5
6
6
type Story = StoryObj<typeof Avatar>;
7
7
type Meta = MetaObj<typeof Avatar>;
8
8
9
9
export const Default: Story = {
10
10
args: {
11
-
src: githubProfileAvatarUrl('ovflowd'),
11
+
src: getGitHubAvatarUrl('ovflowd'),
12
12
alt: 'ovflowd',
13
13
},
14
14
};
+2
-2
components/Common/AvatarGroup/index.stories.tsx
+2
-2
components/Common/AvatarGroup/index.stories.tsx
···
1
1
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
2
2
3
3
import AvatarGroup from '@/components/Common/AvatarGroup';
4
-
import { githubProfileAvatarUrl } from '@/util/gitHubUtils';
4
+
import { getGitHubAvatarUrl } from '@/util/gitHubUtils';
5
5
6
6
type Story = StoryObj<typeof AvatarGroup>;
7
7
type Meta = MetaObj<typeof AvatarGroup>;
···
31
31
const defaultProps = {
32
32
avatars: [
33
33
unknownAvatar,
34
-
...names.map(name => ({ src: githubProfileAvatarUrl(name), alt: name })),
34
+
...names.map(name => ({ src: getGitHubAvatarUrl(name), alt: name })),
35
35
],
36
36
};
37
37
+2
-2
components/Downloads/ChangelogModal/index.stories.tsx
+2
-2
components/Downloads/ChangelogModal/index.stories.tsx
···
5
5
import ChangelogModal from '@/components/Downloads/ChangelogModal';
6
6
import { MDXRenderer } from '@/components/mdxRenderer';
7
7
import { compileMDX } from '@/next.mdx.compiler.mjs';
8
-
import { githubProfileAvatarUrl } from '@/util/gitHubUtils';
8
+
import { getGitHubAvatarUrl } from '@/util/gitHubUtils';
9
9
10
10
type Story = StoryObj<typeof ChangelogModal>;
11
11
type Meta = MetaObj<typeof ChangelogModal>;
···
182
182
heading: 'Node v18.17.0',
183
183
subheading: "2023-07-18, Version 18.17.0 'Hydrogen' (LTS), @danielleadams",
184
184
avatars: names.map(name => ({
185
-
src: githubProfileAvatarUrl(name),
185
+
src: getGitHubAvatarUrl(name),
186
186
alt: name,
187
187
})),
188
188
children,
+2
-2
components/withMetaBar.tsx
+2
-2
components/withMetaBar.tsx
···
5
5
import GitHub from '@/components/Icons/Social/GitHub';
6
6
import Link from '@/components/Link';
7
7
import { useClientContext } from '@/hooks/server';
8
-
import { getGitHubEditPageUrl } from '@/util/gitHubUtils';
8
+
import { getGitHubBlobUrl } from '@/util/gitHubUtils';
9
9
10
10
const DATE_FORMAT = {
11
11
month: 'short',
···
29
29
'components.metabar.contribute': (
30
30
<>
31
31
<GitHub className="fill-neutral-700 dark:fill-neutral-100" />
32
-
<Link href={getGitHubEditPageUrl(filename)}>Edit this page</Link>
32
+
<Link href={getGitHubBlobUrl(filename)}>Edit this page</Link>
33
33
</>
34
34
),
35
35
}}
+2
-2
next.mdx.compiler.mjs
+2
-2
next.mdx.compiler.mjs
···
5
5
import { matter } from 'vfile-matter';
6
6
7
7
import { NEXT_REHYPE_PLUGINS, NEXT_REMARK_PLUGINS } from './next.mdx.mjs';
8
-
import { createGitHubSlug } from './util/gitHubUtils';
8
+
import { createGitHubSlugger } from './util/gitHubUtils';
9
9
10
10
// Defines the React Runtime Components
11
11
const reactRuntime = { Fragment, jsx, jsxs };
···
28
28
// cleaning the frontmatter to the source that is going to be parsed by the MDX Compiler
29
29
matter(source, { strip: true });
30
30
31
-
const slugger = createGitHubSlug();
31
+
const slugger = createGitHubSlugger();
32
32
33
33
// This is a minimal MDX Compiler that is lightweight and only parses the MDX
34
34
const { default: MDXContent } = await evaluate(source, {
+11
types/github.ts
+11
types/github.ts
+1
types/index.ts
+1
types/index.ts
+6
-3
util/gitHubUtils.ts
+6
-3
util/gitHubUtils.ts
···
1
1
import GitHubSlugger from 'github-slugger';
2
2
3
-
export const githubProfileAvatarUrl = (username: string): string =>
3
+
export const getGitHubAvatarUrl = (username: string): string =>
4
4
`https://avatars.githubusercontent.com/${username}`;
5
5
6
-
export const createGitHubSlug = () => {
6
+
export const createGitHubSlugger = () => {
7
7
const githubSlugger = new GitHubSlugger();
8
8
9
9
return (text: string) => githubSlugger.slug(text);
10
10
};
11
11
12
-
export const getGitHubEditPageUrl = (filename: string) =>
12
+
export const getGitHubBlobUrl = (filename: string) =>
13
13
`https://github.com/nodejs/nodejs.org/blob/main/pages/en/${filename}`;
14
+
15
+
export const getGitHubApiDocsUrl = (ref: string) =>
16
+
`https://api.github.com/repos/nodejs/node/contents/doc/api?ref=${ref}`;