diff --git a/apps/site/components/Common/Button.tsx b/apps/site/components/Common/Button.tsx index 206570b3a9bcb..11768132a2d07 100644 --- a/apps/site/components/Common/Button.tsx +++ b/apps/site/components/Common/Button.tsx @@ -1,6 +1,5 @@ -import BaseButton, { - type ButtonProps, -} from '@node-core/ui-components/Common/BaseButton'; +import BaseButton from '@node-core/ui-components/Common/BaseButton'; +import type { ButtonProps } from '@node-core/ui-components/Common/BaseButton'; import type { FC, ComponentProps } from 'react'; import Link from '#site/components/Link'; diff --git a/apps/site/components/Downloads/DownloadReleasesTable/DetailsButton.tsx b/apps/site/components/Downloads/DownloadReleasesTable/DetailsButton.tsx deleted file mode 100644 index b8fbeb6f160b9..0000000000000 --- a/apps/site/components/Downloads/DownloadReleasesTable/DetailsButton.tsx +++ /dev/null @@ -1,30 +0,0 @@ -'use client'; - -import { useTranslations } from 'next-intl'; -import type { FC } from 'react'; -import { use } from 'react'; - -import LinkWithArrow from '#site/components/LinkWithArrow'; -import { ReleaseModalContext } from '#site/providers/releaseModalProvider'; -import type { NodeRelease } from '#site/types'; - -type DetailsButtonProps = { - versionData: NodeRelease; -}; - -const DetailsButton: FC = ({ versionData }) => { - const t = useTranslations('components.downloadReleasesTable'); - - const { openModal } = use(ReleaseModalContext); - - return ( - openModal(versionData)} - > - {t('details')} - - ); -}; - -export default DetailsButton; diff --git a/apps/site/components/Downloads/DownloadReleasesTable/index.tsx b/apps/site/components/Downloads/DownloadReleasesTable/index.tsx index 557d6bd86e039..de74b92da2570 100644 --- a/apps/site/components/Downloads/DownloadReleasesTable/index.tsx +++ b/apps/site/components/Downloads/DownloadReleasesTable/index.tsx @@ -1,11 +1,16 @@ +'use client'; + import Badge from '@node-core/ui-components/Common/Badge'; import { useTranslations } from 'next-intl'; +import { useState } from 'react'; import type { FC } from 'react'; import FormattedTime from '#site/components/Common/FormattedTime'; -import DetailsButton from '#site/components/Downloads/DownloadReleasesTable/DetailsButton'; +import LinkWithArrow from '#site/components/LinkWithArrow'; import provideReleaseData from '#site/next-data/providers/releaseData'; +import ReleaseModal from '../ReleaseModal'; + const BADGE_KIND_MAP = { 'End-of-life': 'warning', 'Maintenance LTS': 'neutral', @@ -18,8 +23,10 @@ const DownloadReleasesTable: FC = () => { const releaseData = provideReleaseData(); const t = useTranslations(); + const [currentModal, setCurrentModal] = useState(); + return ( - +
@@ -32,25 +39,37 @@ const DownloadReleasesTable: FC = () => { {releaseData.map(release => ( - - - - - - - - + <> + + + + + + + + + open || setCurrentModal(undefined)} + /> + ))}
{t('components.downloadReleasesTable.version')}
v{release.major}{release.codename || '-'} - - - - - - {release.status} - {release.status === 'End-of-life' ? ' (EoL)' : ''} - - - -
v{release.major}{release.codename || '-'} + + + + + + {release.status} + {release.status === 'End-of-life' ? ' (EoL)' : ''} + + + setCurrentModal(release.version)} + > + {t('components.downloadReleasesTable.details')} + +
diff --git a/apps/site/components/Downloads/MinorReleasesTable/index.tsx b/apps/site/components/Downloads/MinorReleasesTable/index.tsx index 641af7fec0cb8..f712e9e71f83a 100644 --- a/apps/site/components/Downloads/MinorReleasesTable/index.tsx +++ b/apps/site/components/Downloads/MinorReleasesTable/index.tsx @@ -18,14 +18,14 @@ type MinorReleasesTableProps = { export const MinorReleasesTable: FC = ({ releases, }) => { - const t = useTranslations('components.minorReleasesTable'); + const t = useTranslations(); return ( - - + + @@ -38,21 +38,21 @@ export const MinorReleasesTable: FC = ({ kind="neutral" href={`https://nodejs.org/download/release/v${release.version}/`} > - {t('actions.release')} + {t('components.minorReleasesTable.actions.release')} - {t('actions.changelog')} + {t('components.minorReleasesTable.actions.changelog')} - {t('actions.docs')} + {t('components.minorReleasesTable.actions.docs')} diff --git a/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx b/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx index ccd9073412f41..1258763784fba 100644 --- a/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx +++ b/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx @@ -122,7 +122,7 @@ const ReleaseCodeBox: FC = () => { size="small" > {t.rich('layouts.download.codeBox.unsupportedVersionWarning', { - link: text => {text}, + link: text => {text}, })} )} diff --git a/apps/site/components/Downloads/ReleaseModal/index.tsx b/apps/site/components/Downloads/ReleaseModal/index.tsx index f5a89e8a8a776..bfc6888a1bfe4 100644 --- a/apps/site/components/Downloads/ReleaseModal/index.tsx +++ b/apps/site/components/Downloads/ReleaseModal/index.tsx @@ -1,23 +1,21 @@ import AlertBox from '@node-core/ui-components/Common/AlertBox'; import { Modal, Title, Content } from '@node-core/ui-components/Common/Modal'; import { useTranslations } from 'next-intl'; -import type { FC } from 'react'; +import type { ComponentProps, FC } from 'react'; import { MinorReleasesTable } from '#site/components/Downloads/MinorReleasesTable'; import { ReleaseOverview } from '#site/components/Downloads/ReleaseOverview'; import Link from '#site/components/Link'; import type { NodeRelease } from '#site/types'; -type ReleaseModalProps = { - isOpen: boolean; - closeModal: () => void; +type ReleaseModalProps = ComponentProps & { release: NodeRelease; }; const ReleaseModal: FC = ({ - isOpen, - closeModal, release, + onOpenChange, + ...props }) => { const t = useTranslations(); @@ -31,7 +29,7 @@ const ReleaseModal: FC = ({ }); return ( - + {release.status === 'End-of-life' && (
= ({ size="small" > {t.rich('components.releaseModal.unsupportedVersionWarning', { - link: text => ( - - {text} - - ), + link: text => {text}, })}
diff --git a/apps/site/components/EOL/EOLAlert/index.tsx b/apps/site/components/EOL/EOLAlert/index.tsx new file mode 100644 index 0000000000000..1b517f84f5b00 --- /dev/null +++ b/apps/site/components/EOL/EOLAlert/index.tsx @@ -0,0 +1,19 @@ +import AlertBox from '@node-core/ui-components/Common/AlertBox'; +import { useTranslations } from 'next-intl'; + +import Link from '#site/components/Link'; + +const EOLAlert = () => { + const t = useTranslations(); + return ( + + {t('components.eolAlert.intro')}{' '} + + OpenJS Ecosystem Sustainability Program{' '} + {t('components.eolAlert.partner')} HeroDevs + + + ); +}; + +export default EOLAlert; diff --git a/apps/site/components/EOL/EOLModal/index.tsx b/apps/site/components/EOL/EOLModal/index.tsx new file mode 100644 index 0000000000000..bbd4eb502b9ca --- /dev/null +++ b/apps/site/components/EOL/EOLModal/index.tsx @@ -0,0 +1,66 @@ +import { Modal, Title, Content } from '@node-core/ui-components/Common/Modal'; +import { useTranslations } from 'next-intl'; +import { useMemo } from 'react'; +import type { FC, ComponentProps } from 'react'; + +import KnownSeveritySection from '#site/components/EOL/KnownSeveritySection'; +import UnknownSeveritySection from '#site/components/EOL/UnknownSeveritySection'; +import { SEVERITY_ORDER } from '#site/next.constants.mjs'; +import type { NodeRelease } from '#site/types/releases'; +import type { Vulnerability } from '#site/types/vulnerabilities'; + +type EOLModalProps = ComponentProps & { + release: NodeRelease; + vulnerabilities: Array; +}; + +const EOLModal: FC = ({ + release, + vulnerabilities, + ...props +}) => { + const t = useTranslations(); + + const modalHeading = release.codename + ? t('components.eolModal.title', { + version: release.major, + codename: release.codename, + }) + : t('components.eolModal.titleWithoutCodename', { version: release.major }); + + useMemo( + () => + vulnerabilities.sort( + (a, b) => + SEVERITY_ORDER.indexOf(a.severity) - + SEVERITY_ORDER.indexOf(b.severity) + ), + [vulnerabilities] + ); + + return ( + + {modalHeading} + + {vulnerabilities.length > 0 && ( +

+ {t('components.eolModal.vulnerabilitiesMessage', { + count: vulnerabilities.length, + })} +

+ )} + + + + + {!vulnerabilities.length && ( +

+ {t('components.eolModal.noVulnerabilitiesMessage')} +

+ )} +
+
+ ); +}; + +export default EOLModal; diff --git a/apps/site/components/EOL/EOLReleaseTable/index.tsx b/apps/site/components/EOL/EOLReleaseTable/index.tsx new file mode 100644 index 0000000000000..48ad61a0021b2 --- /dev/null +++ b/apps/site/components/EOL/EOLReleaseTable/index.tsx @@ -0,0 +1,78 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import { useState } from 'react'; +import type { FC } from 'react'; + +import FormattedTime from '#site/components/Common/FormattedTime'; +import VulnerabilityChips from '#site/components/EOL/VulnerabilityChips'; +import LinkWithArrow from '#site/components/LinkWithArrow'; +import provideReleaseData from '#site/next-data/providers/releaseData'; +import provideVulnerabilities from '#site/next-data/providers/vulnerabilities'; +import { EOL_VERSION_IDENTIFIER } from '#site/next.constants.mjs'; + +import EOLModal from '../EOLModal'; + +const EOLReleaseTable: FC = () => { + const releaseData = provideReleaseData(); + const vulnerabilities = provideVulnerabilities(); + const eolReleases = releaseData.filter( + release => release.status === EOL_VERSION_IDENTIFIER + ); + + const t = useTranslations(); + + const [currentModal, setCurrentModal] = useState(); + + return ( +
{t('version')}{t('links')}{t('components.minorReleasesTable.version')}{t('components.minorReleasesTable.links')}
+ + + + + + + + + + {eolReleases.map(release => ( + <> + + + + + + + open || setCurrentModal(undefined)} + /> + + ))} + +
+ {t('components.eolTable.version')} ( + {t('components.eolTable.codename')}) + {t('components.eolTable.lastUpdated')}{t('components.eolTable.vulnerabilities')}{t('components.eolTable.details')}
+ v{release.major}{' '} + {release.codename ? `(${release.codename})` : ''} + + + + + + setCurrentModal(release.version)} + > + {t('components.downloadReleasesTable.details')} + +
+ ); +}; + +export default EOLReleaseTable; diff --git a/apps/site/components/EOL/KnownSeveritySection/index.tsx b/apps/site/components/EOL/KnownSeveritySection/index.tsx new file mode 100644 index 0000000000000..0f79e8a64fad6 --- /dev/null +++ b/apps/site/components/EOL/KnownSeveritySection/index.tsx @@ -0,0 +1,30 @@ +import type { FC } from 'react'; + +import VulnerabilitiesTable from '#site/components/EOL/VulnerabilitiesTable'; +import type { Vulnerability } from '#site/types/vulnerabilities'; + +type KnownSeveritySectionProps = { + vulnerabilities: Array; +}; + +const KnownSeveritySection: FC = ({ + vulnerabilities, +}) => { + const knownVulnerabilities = vulnerabilities.filter( + v => v.severity !== 'unknown' + ); + + if (!knownVulnerabilities.length) { + return null; + } + + return ( + vuln.severity !== 'unknown' + )} + /> + ); +}; + +export default KnownSeveritySection; diff --git a/apps/site/components/EOL/UnknownSeveritySection/index.tsx b/apps/site/components/EOL/UnknownSeveritySection/index.tsx new file mode 100644 index 0000000000000..6162e6418a3ce --- /dev/null +++ b/apps/site/components/EOL/UnknownSeveritySection/index.tsx @@ -0,0 +1,40 @@ +import { useTranslations } from 'next-intl'; +import type { FC } from 'react'; + +import VulnerabilitiesTable from '#site/components/EOL/VulnerabilitiesTable'; +import type { Vulnerability } from '#site/types/vulnerabilities'; + +type UnknownSeveritySectionProps = { + vulnerabilities: Array; +}; + +const UnknownSeveritySection: FC = ({ + vulnerabilities, +}) => { + const t = useTranslations(); + + const unknownVulnerabilities = vulnerabilities.filter( + v => v.severity === 'unknown' + ); + + if (!unknownVulnerabilities.length) { + return null; + } + + return ( +
+ + {t('components.eolModal.showUnknownSeverities')} ( + {unknownVulnerabilities.length}) + +
+ +
+
+ ); +}; + +export default UnknownSeveritySection; diff --git a/apps/site/components/EOL/VulnerabilitiesTable/index.tsx b/apps/site/components/EOL/VulnerabilitiesTable/index.tsx new file mode 100644 index 0000000000000..a12803eb4586e --- /dev/null +++ b/apps/site/components/EOL/VulnerabilitiesTable/index.tsx @@ -0,0 +1,73 @@ +import classNames from 'classnames'; +import { useTranslations } from 'next-intl'; +import type { FC } from 'react'; + +import VulnerabilityChip from '#site/components/EOL/VulnerabilityChips/Chip'; +import LinkWithArrow from '#site/components/LinkWithArrow'; +import type { Vulnerability } from '#site/types/vulnerabilities'; + +const VulnerabilitiesTable: FC<{ + vulnerabilities: Array; + maxWidth?: string; +}> = ({ vulnerabilities, maxWidth = 'max-w-2xs' }) => { + const t = useTranslations(); + + if (!vulnerabilities.length) { + return null; + } + + return ( + + + + + + + + + + + {vulnerabilities.map((vulnerability, i) => ( + + + + + + + ))} + +
{t('components.eolModal.table.cves')}{t('components.eolModal.table.severity')}{t('components.eolModal.table.overview')}{t('components.eolModal.table.details')}
+ {vulnerability.cve.map(cveId => ( +
+ + {cveId} + +
+ ))} + + {vulnerability.cve.length > 0 || '-'} +
+ + + {vulnerability.description || vulnerability.overview || '-'} + + {vulnerability.url ? ( + + {t('components.eolModal.blogLinkText')} + + ) : ( + '—' + )} +
+ ); +}; + +export default VulnerabilitiesTable; diff --git a/apps/site/components/EOL/VulnerabilityChips/Chip/index.module.css b/apps/site/components/EOL/VulnerabilityChips/Chip/index.module.css new file mode 100644 index 0000000000000..0dc0a5ebc7337 --- /dev/null +++ b/apps/site/components/EOL/VulnerabilityChips/Chip/index.module.css @@ -0,0 +1,8 @@ +@reference "../../../../styles/index.css"; + +.chipCount { + @apply mr-1 + rounded-sm + bg-gray-800/20 + px-1.5; +} diff --git a/apps/site/components/EOL/VulnerabilityChips/Chip/index.tsx b/apps/site/components/EOL/VulnerabilityChips/Chip/index.tsx new file mode 100644 index 0000000000000..6c2d7232ce07d --- /dev/null +++ b/apps/site/components/EOL/VulnerabilityChips/Chip/index.tsx @@ -0,0 +1,33 @@ +import Badge, { type BadgeKind } from '@node-core/ui-components/Common/Badge'; +import { useTranslations } from 'next-intl'; +import type { FC } from 'react'; + +import { SEVERITY_KIND_MAP } from '#site/next.constants.mjs'; +import type { Severity } from '#site/types'; + +import styles from './index.module.css'; + +type VulnerabilityChipProps = { + severity: Severity; + count?: number; +}; + +const VulnerabilityChip: FC = ({ + severity, + count = 0, +}) => { + const t = useTranslations(); + + return ( + + {count > 0 ? {count} : null} + {t(`components.eolChip.severity.${severity}`)} + + ); +}; + +export default VulnerabilityChip; diff --git a/apps/site/components/EOL/VulnerabilityChips/index.tsx b/apps/site/components/EOL/VulnerabilityChips/index.tsx new file mode 100644 index 0000000000000..cec0b7a86e2da --- /dev/null +++ b/apps/site/components/EOL/VulnerabilityChips/index.tsx @@ -0,0 +1,39 @@ +import type { FC } from 'react'; + +import VulnerabilityChip from '#site/components/EOL/VulnerabilityChips/Chip'; +import { SEVERITY_ORDER } from '#site/next.constants.mjs'; +import type { Severity, Vulnerability } from '#site/types'; + +type VulnerabilityChipsProps = { + vulnerabilities: Array; +}; + +const VulnerabilityChips: FC = ({ + vulnerabilities, +}) => { + // Group vulnerabilities by severity + const groupedBySeverity = vulnerabilities.reduce>( + (acc, vuln) => { + const severity = vuln.severity.toLowerCase(); + acc[severity] = (acc[severity] || 0) + 1; + return acc; + }, + {} + ); + + return ( +
+ {SEVERITY_ORDER.filter(severity => groupedBySeverity[severity] > 0).map( + severity => ( + + ) + )} +
+ ); +}; + +export default VulnerabilityChips; diff --git a/apps/site/layouts/About.tsx b/apps/site/layouts/About.tsx index b6f2fecae5419..cf616baf892aa 100644 --- a/apps/site/layouts/About.tsx +++ b/apps/site/layouts/About.tsx @@ -6,10 +6,9 @@ import WithFooter from '#site/components/withFooter'; import WithMetaBar from '#site/components/withMetaBar'; import WithNavBar from '#site/components/withNavBar'; import WithSidebar from '#site/components/withSidebar'; -import { ReleaseModalProvider } from '#site/providers/releaseModalProvider'; const AboutLayout: FC = ({ children }) => ( - + <>
@@ -25,7 +24,7 @@ const AboutLayout: FC = ({ children }) => (
-
+ ); export default AboutLayout; diff --git a/apps/site/layouts/ArticlePage.tsx b/apps/site/layouts/ArticlePage.tsx index c33c3f4fe3998..f4936da8a2487 100644 --- a/apps/site/layouts/ArticlePage.tsx +++ b/apps/site/layouts/ArticlePage.tsx @@ -1,6 +1,7 @@ import Article from '@node-core/ui-components/Containers/Article'; import type { FC, PropsWithChildren } from 'react'; +import WithFooter from '#site/components/withFooter'; import WithMetaBar from '#site/components/withMetaBar'; import WithNavBar from '#site/components/withNavBar'; import WithSidebar from '#site/components/withSidebar'; @@ -18,6 +19,8 @@ const ArticlePageLayout: FC = ({ children }) => ( + + ); diff --git a/apps/site/layouts/Post.tsx b/apps/site/layouts/Post.tsx index 9b5234b727757..3d7a5188b67c8 100644 --- a/apps/site/layouts/Post.tsx +++ b/apps/site/layouts/Post.tsx @@ -1,6 +1,7 @@ import Preview from '@node-core/ui-components/Common/Preview'; import type { FC, PropsWithChildren } from 'react'; +import EOLAlert from '#site/components/EOL/EOLAlert'; import WithAvatarGroup from '#site/components/withAvatarGroup'; import WithBlogCrossLinks from '#site/components/withBlogCrossLinks'; import WithFooter from '#site/components/withFooter'; @@ -26,6 +27,8 @@ const PostLayout: FC = ({ children }) => {
+ {type === 'vulnerability' && } +

{frontmatter.title}

diff --git a/apps/site/next-data/generators/__tests__/vulnerabilities.test.mjs b/apps/site/next-data/generators/__tests__/vulnerabilities.test.mjs new file mode 100644 index 0000000000000..b645bfdb84a55 --- /dev/null +++ b/apps/site/next-data/generators/__tests__/vulnerabilities.test.mjs @@ -0,0 +1,145 @@ +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; + +import { groupVulnerabilitiesByMajor } from '#site/next-data/generators/vulnerabilities.mjs'; + +const MOCK_VULNERABILITIES = { + 1: { + cve: ['CVE-2017-1000381'], + vulnerable: '8.x || 7.x || 4.x || 6.x || 5.x', + }, + 8: { + cve: ['CVE-2016-5180'], + vulnerable: '0.10.x || 0.12.x || 4.x', + }, + 11: { + cve: [], + vulnerable: '6.x', + }, + 24: { + cve: ['CVE-2016-1669'], + vulnerable: '>=6.0.0 <6.2.0 || 5.x || 4.x', + }, + 54: { + cve: ['CVE-2018-12115'], + vulnerable: '<= 10', + }, +}; + +const VULNERABILITIES_VALUES = Object.values(MOCK_VULNERABILITIES); + +describe('groupVulnerabilitiesByMajor', () => { + it('returns an empty object when given an empty array', () => { + const grouped = groupVulnerabilitiesByMajor([]); + assert.deepEqual(grouped, {}); + }); + + it('ignores non-numeric values in the "vulnerable" string', () => { + const vulnerabilities = [ + { cve: ['CVE-2021-1234'], vulnerable: 'foo || bar || 12.x' }, + { cve: ['CVE-2021-5678'], vulnerable: 'baz || 13.x' }, + ]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), ['12', '13']); + }); + + it('handles vulnerabilities with no "vulnerable" field gracefully', () => { + const vulnerabilities = [ + { cve: ['CVE-2021-1234'], vulnerable: '12.x' }, + { cve: ['CVE-2021-5678'] }, // no vulnerable field + ]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), ['12']); + }); + + it('can group a single version', () => { + const vulnerabilities = [{ cve: ['CVE-2021-1234'], vulnerable: '12.x' }]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), ['12']); + }); + + it('can group a 0.x version', () => { + const vulnerabilities = [{ cve: ['CVE-2021-1234'], vulnerable: '0.10.x' }]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), ['0']); + }); + + it('can group two versions', () => { + const vulnerabilities = [ + { cve: ['CVE-2021-1234'], vulnerable: '12.x || 13.x' }, + ]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), ['12', '13']); + }); + + it('can group an integer version and a 0.X version', () => { + const vulnerabilities = [ + { cve: ['CVE-2021-1234'], vulnerable: '0.10.x || 12.x' }, + ]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), ['0', '12']); + }); + + it('returns a the major when given a greater-than range', () => { + const vulnerabilities = [ + { cve: ['CVE-2021-5678'], vulnerable: '>=6.0.0 <6.2.0' }, + ]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), ['6']); + }); + + it('returns a descending list of major versions when given a less-than range', () => { + const vulnerabilities = [{ cve: ['CVE-2021-5678'], vulnerable: '< 5' }]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), [ + '0', + '1', + '2', + '3', + '4', + ]); + }); + + it('returns a descending list of major versions when given a less-than or equal range, inclusive', () => { + const vulnerabilities = [{ cve: ['CVE-2021-5678'], vulnerable: '<= 5' }]; + const grouped = groupVulnerabilitiesByMajor(vulnerabilities); + assert.deepEqual(Object.keys(grouped).sort(Number), [ + '0', + '1', + '2', + '3', + '4', + '5', + ]); + }); + + it('groups vulnerabilities by major version extracted from "vulnerable" string', () => { + const grouped = groupVulnerabilitiesByMajor(VULNERABILITIES_VALUES); + + assert.deepEqual(Object.keys(grouped).sort(Number), [ + '0', + '1', // note, comes from the <= 10 + '2', // note, comes from the <= 10 + '3', // note, comes from the <= 10 + '4', + '5', + '6', + '7', + '8', + '9', // note, comes from the <= 10 + '10', // note, comes from the <= 10 + ]); + + assert.strictEqual(grouped['0'].length, 3); + assert.strictEqual(grouped['1'].length, 1); + assert.strictEqual(grouped['2'].length, 1); + assert.strictEqual(grouped['3'].length, 1); + assert.strictEqual(grouped['4'].length, 4); + assert.strictEqual(grouped['5'].length, 3); + assert.strictEqual(grouped['6'].length, 4); + assert.strictEqual(grouped['7'].length, 2); + assert.strictEqual(grouped['8'].length, 2); + assert.strictEqual(grouped['9'].length, 1); + assert.strictEqual(grouped['10'].length, 1); + }); +}); diff --git a/apps/site/next-data/generators/vulnerabilities.mjs b/apps/site/next-data/generators/vulnerabilities.mjs new file mode 100644 index 0000000000000..b59b89cc126b5 --- /dev/null +++ b/apps/site/next-data/generators/vulnerabilities.mjs @@ -0,0 +1,82 @@ +import { VULNERABILITIES_URL } from '#site/next.constants.mjs'; + +/** + * Groups vulnerabilities by major version number extracted from the `vulnerable` string. + * + * @param {Array} vulnerabilities Array of Vulnerability objects + */ +export function groupVulnerabilitiesByMajor(vulnerabilities) { + const grouped = {}; + + for (const vulnerability of vulnerabilities) { + // To avoid future confusion, rename 'ref' to 'url' + vulnerability.url = vulnerability.ref; + delete vulnerability.ref; + + // split on '||' to handle multiple versions and trim whitespace + const potentialVersions = + vulnerability.vulnerable?.split('||').map(v => v.trim()) || []; + + potentialVersions.forEach(version => { + // handle 0.X versions, which did not follow semver + // we don't even capture the minor here. + if (/^0\.\d+(\.x)?$/.test(version)) { + const majorVersion = '0'; + if (!grouped[majorVersion]) grouped[majorVersion] = []; + grouped[majorVersion].push(vulnerability); + return; + } + + // handle simple cases, where there is no range + // this is something like 12.x + if (/^\d+.x/.test(version)) { + const majorVersion = version.split('.')[0]; + if (!grouped[majorVersion]) grouped[majorVersion] = []; + grouped[majorVersion].push(vulnerability); + return; + } + + // detect if there is a range in the values, + // which would include a > or < or <= or >=, with spaces + const rangeMatch = version.match(/([<>]=?)\s*(\d+)?\.?(\d+)?/); + if (rangeMatch) { + const operator = rangeMatch[1]; + + // if we have equality or greater than, we simply add the current + // and assume that other piped sections handle any higher bounds + if (operator === '>=' || operator === '>' || operator === '<=') { + const majorVersion = rangeMatch[2]; + if (!grouped[majorVersion]) grouped[majorVersion] = []; + grouped[majorVersion].push(vulnerability); + } + + // if we only specify (< pr <=) vulnerability, + // we need to count down from this to all majors! + if (operator === '<' || operator === '<=') { + const majorVersion = rangeMatch[2]; + for (let i = majorVersion - 1; i >= 0; i--) { + if (!grouped[i]) grouped[i] = []; + grouped[i].push(vulnerability); + } + return; + } + } + }); + } + + return grouped; +} + +/** + * Fetches vulnerability data from the Node.js Security Working Group repository, + * and returns it grouped by major version. + * + * @returns {Promise} Grouped vulnerabilities + */ +export default async function generateVulnerabilityData() { + const response = await fetch(VULNERABILITIES_URL); + + const data = await response.json(); + + return groupVulnerabilitiesByMajor(Object.values(data)); +} diff --git a/apps/site/next-data/providers/vulnerabilities.ts b/apps/site/next-data/providers/vulnerabilities.ts new file mode 100644 index 0000000000000..cfc3cce008ba0 --- /dev/null +++ b/apps/site/next-data/providers/vulnerabilities.ts @@ -0,0 +1,9 @@ +import { cache } from 'react'; + +import generateVulnerabilities from '#site/next-data/generators/vulnerabilities.mjs'; + +const vulnerabilities = await generateVulnerabilities(); + +const provideVulnerabilities = cache(() => vulnerabilities); + +export default provideVulnerabilities; diff --git a/apps/site/next.constants.mjs b/apps/site/next.constants.mjs index 313b682d54aa9..0ff5b27102530 100644 --- a/apps/site/next.constants.mjs +++ b/apps/site/next.constants.mjs @@ -174,3 +174,30 @@ export const GITHUB_API_KEY = process.env.NEXT_GITHUB_API_KEY || ''; */ export const TRANSLATION_URL = 'https://github.com/nodejs/nodejs.org/blob/main/TRANSLATION.md#how-to-translate'; + +/** + * Define the order in which vulnerabilities should be sorted + */ +export const SEVERITY_ORDER = ['critical', 'high', 'medium', 'low']; + +/** + * Maps vulnerability severity levels to UI Badge kinds + */ +export const SEVERITY_KIND_MAP = { + unknown: 'neutral', + low: 'default', + medium: 'info', + high: 'warning', + critical: 'error', +}; + +/** + * Which Node.js versions do we want to display vulnerabilities for? + */ +export const EOL_VERSION_IDENTIFIER = 'End-of-life'; + +/** + * The location of the Node.js Security Working Group Vulnerabilities data. + */ +export const VULNERABILITIES_URL = + 'https://raw.githubusercontent.com/nodejs/security-wg/main/vuln/core/index.json'; diff --git a/apps/site/next.mdx.use.mjs b/apps/site/next.mdx.use.mjs index b67817de4e9ff..e2b5af114b23f 100644 --- a/apps/site/next.mdx.use.mjs +++ b/apps/site/next.mdx.use.mjs @@ -4,6 +4,8 @@ import BadgeGroup from '@node-core/ui-components/Common/BadgeGroup'; import Button from './components/Common/Button'; import DownloadReleasesTable from './components/Downloads/DownloadReleasesTable'; +import EOLAlertBox from './components/EOL/EOLAlert'; +import EOLReleaseTable from './components/EOL/EOLReleaseTable'; import Link from './components/Link'; import LinkWithArrow from './components/LinkWithArrow'; import UpcomingMeetings from './components/MDX/Calendar/UpcomingMeetings'; @@ -28,6 +30,10 @@ export const mdxComponents = { BadgeGroup, // Renders an container for Upcoming Node.js Meetings UpcomingMeetings, + // Renders an EOL alert + EOLAlertBox, + // Renders the EOL Table + EOLReleaseTable, // Renders a Button Component for `button` tags Button, // Regular links (without arrow) diff --git a/apps/site/pages/en/about/previous-releases.mdx b/apps/site/pages/en/about/previous-releases.mdx index 8ef856f11261a..dc0b0c65a8200 100644 --- a/apps/site/pages/en/about/previous-releases.mdx +++ b/apps/site/pages/en/about/previous-releases.mdx @@ -5,6 +5,8 @@ layout: about # Node.js Releases + + Major Node.js versions enter _Current_ release status for six months, which gives library authors time to add support for them. After six months, odd-numbered releases (9, 11, etc.) become unsupported, and even-numbered releases (10, 12, etc.) move to _Active LTS_ status and are ready for general use. _LTS_ release status is "long-term support", which typically guarantees that critical bugs will be fixed for a total of 30 months. @@ -16,10 +18,6 @@ Production applications should only use _Active LTS_ or _Maintenance LTS_ releas Full details regarding the Node.js release schedule are available [on GitHub](https://github.com/nodejs/release#release-schedule). -### Commercial Support - -Commercial support for versions past the Maintenance phase is available through our OpenJS Ecosystem Sustainability Program partner [HeroDevs](https://www.herodevs.com/support/node-nes?utm_source=NodeJS+&utm_medium=Link&utm_campaign=Version_support_page). - ## Looking for the latest release of a version branch? diff --git a/apps/site/pages/en/eol.mdx b/apps/site/pages/en/eol.mdx new file mode 100644 index 0000000000000..9229e6e354c73 --- /dev/null +++ b/apps/site/pages/en/eol.mdx @@ -0,0 +1,43 @@ +--- +title: End-Of-Life +layout: article +--- + +# End-Of-Life (EOL) + +## Why and how Node.js releases reach End-Of-Life + +Major versions of Node.js are released, patched, and designated End-Of-Life on a predictable schedule. As it's not feasible to maintain all release lines in perpetuity, after a planned maintenance period, a Node.js major release line will stop being maintained by the project. + +
+ + or + +
+ +[View the Node.js release schedule](/about/releases/). + +## What Happens When a Release Line Reaches EOL + +When a version reaches End-Of-Life, it means that it will no longer receive updates, including security patches. This can leave applications running on these versions vulnerable to security issues and bugs that will never be fixed. + +- **No more vulnerability fixes**: When new security releases reveal issues and patches in newer major lines, even if the same vulnerability affects EOL release lines, there will not be any new releases for them. Users still clinging on to EOL release lines and using affected code paths will be immediately vulnerable to attacks exploiting these disclosed vulnerabilities. +- **Tool-chain breakage**: EOL releases may no longer dynamically link to newer versions of the shared libraries they depend on, blocking or breaking system updates. +- **Ecosystem drift**: Many popular user-land packages drop support for EOL Node.js releases over time. When an application clings onto outdated packages, it may suffer from even more unfixed vulnerabilities and bugs, further drifting away from ecosystem norm. +- **Compliance red flags**: Many industry audits forbid unmaintained runtimes. + +## EOL Versions + + + +## Commercial Support + +Despite the obvious downsides of using EOL releases, in practice, organizations face constraints that prevent immediate upgrades, such as legacy codebases, compliance requirements, or complex dependency chains. For users who cannot upgrade immediately but needs continued security support for End-Of-Life versions of Node.js, commercial support is available through the [OpenJS Ecosystem Sustainability Program](https://openjsf.org/blog/ecosystem-sustainability-program) partnership. + +Node.js currently partners with HeroDevs to provide Never-Ending Support (NES) for Node.js versions past their official maintenance phase. This includes security patches, compliance assistance, and technical support to help bridge the gap while you plan your upgrade strategy. For more detailed information, visit the [**HeroDevs Node.js NES page**](https://nodejs.org/esp/herodevs). + +Using EOL releases through NES should be viewed as a temporary solution—the goal should always be to upgrade to actively supported versions. diff --git a/apps/site/pages/en/index.mdx b/apps/site/pages/en/index.mdx index 02f5c43bd78a2..0721fafa8b692 100644 --- a/apps/site/pages/en/index.mdx +++ b/apps/site/pages/en/index.mdx @@ -21,10 +21,10 @@ layout: home -
diff --git a/apps/site/pages/es/about/previous-releases.mdx b/apps/site/pages/es/about/previous-releases.mdx deleted file mode 100644 index b86e253475021..0000000000000 --- a/apps/site/pages/es/about/previous-releases.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Versiones de Node.js -layout: about ---- - -# Versiones de Node.js - -Las versiones principales de Node.js entran en estado de lanzamiento _Actual_ durante seis meses, lo que les da a los autores de bibliotecas tiempo para agregarles manutención. -Después de seis meses, las versiones impares (9, 11, etc.) dejan de ser compatibles y las versiones pares (10, 12, etc.) pasan al estado _LTS Activo_ y están listas para uso general. -El estado de la versión _LTS_ es "soporte a largo plazo", que normalmente garantiza que los errores críticos se corregirán durante un total de 30 meses. -Las aplicaciones de producción solo deben usar versiones _LTS Activo_ o _LTS en Mantenimiento_. - -## Calendario de Lanzamiento - -![Lanzamientos](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Los detalles del calendario de lanzamiento de Node.js están disponibles [en GitHub](https://github.com/nodejs/release#release-schedule). - -### Soporte Comercial - -El soporte comercial para las versiones que han superado la fase de Mantenimiento está disponible a través de nuestro socio del programa OpenJS Ecosystem Sustainability, [HeroDevs](https://www.herodevs.com/support/node-nes?utm_source=NodeJS+&utm_medium=Link&utm_campaign=Version_support_page). - -## ¿Buscando las últimas versiones de una rama específica? - - - -## Métodos de Instalación Oficial vs. Comunidad - -El sito web de Node.js ofrece varios métodos de instalación que facilitan una instalación de Node.js sin interacción, como por una interfaz de línea de comandos (CLI), gestores de paquetes del sistema operativo (OS) (e.g. `brew`), o gestores de versiones de Node.js (e.g. `nvm`). - -En un intento de anunciar y popularizar esfuerzos comunitarios, el proyecto Node.js ha introducido una página de Descargas actualizada que distingue entre métodos de instalación Oficial y de la Comunidad. Esta presentación provee más flexibilidad y opciones para usuarios. Para evitar confusión, hemos definido requisitos para cada designación. - -### Métodos de Instalación Oficiales - -Para considerarse "Oficial", métodos de instalación deben cumplir con los siguientes requisitos: - -| Requisitos (Métodos de Instalación Oficiales) | -| :------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Lanzamientos nuevos de Node.js deben estar disponible al mismo tiempo que el lanzamiento oficial. | -| Los mantenedores del proyecto tienen una estrecha relación con Node.js, la cual incluye comunicación directa. | -| El método de instalación debe descargar los binarios oficiales empaquetados por el proyecto Node.js. | -| El método de instalación no compila desde el código fuente cuando binarios están disponibles, ni modifica los binarios oficiales proveídos por Node.js. | - -### Métodos de Instalación de Comunidad - -Para ser incluida en la página de descargas (/download), los métodos de instalación de comunidad deben cumplir con unos requisitos mínimos: - -- **Apoyo de versiones:** Debe proveer instalaciones de cada versión de Node.js apoyado oficialmente que no ha pasado el fin de su vida útil (EOL). -- **Compatibilidad con Sistemas Operativos**: Debe operar en uno o más sistemas operativos oficialmente compatible. -- **Apoyo amplio de Sistemas Operativos:** No se puede limitar a una fracción de distribuciones o versiones del sistema operativo. - - Por ejemplo, si un método de instalación declara compatibilidad con "Windows", debe funcionar en cada edición de "Windows 10" y "Windows 11" (incluso versiones para servidores). - - De igual manera, un método de instalación que declara compatibilidad con "Linux" debe poder instalarse en cada una de las distribuciones principales de Linux, y no solo una selección reducida. No puede depender de un gestor de paquetes específico a una distribución en particular como `apt` o `dnf`. -- **Gratis y de Código Abierto:** Debe ser de código abierto que puede usarse gratuitamente y no como producto comercial vendido ni un servicio pagado. diff --git a/apps/site/pages/fa/about/previous-releases.mdx b/apps/site/pages/fa/about/previous-releases.mdx deleted file mode 100644 index 90e1f48e38c8a..0000000000000 --- a/apps/site/pages/fa/about/previous-releases.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: انتشارهای Node.js -layout: about ---- - -انتشارهای Node.js - -نسخه‌های اصلی Node.js برای شش ماه وضعیت انتشار _Current_ را پیدا می‌کنند که به نویسندگان کتابخانه ها زمان می‌دهد تا پشتیبانی از آنها را اضافه کنند. -پس از شش ماه، انتشارهای با شماره فرد (11، 9 و غیره) پشتیبانی نمی‌شوند و انتشارهای با شماره زوج (12، 10 و غیره) به وضعیت _Active LTS_ منتقل می‌شوند و برای استفاده عمومی آماده هستند. -وضعیت انتشار LTS به معنای "پشتیبانی طولانی مدت" است که معمولاً تضمین می‌کند باگ‌های بحرانی در مجموع برای 30 ماه برطرف خواهند شد. -برنامه‌های پروداکشن تنها باید از انتشارهای _Active LTS_ یا _Maintenance LTS_ استفاده کنند. - -## برنامه زمانبندی انتشار - -![Releases](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -جزئیات کامل در مورد زمانبندی انتشار Node.js در [گیت‌هاب](https://github.com/nodejs/release#release-schedule) موجود است. - -## به دنبال آخرین انتشار از یک برنچ نسخه هستید؟ - - diff --git a/apps/site/pages/fr/about/previous-releases.mdx b/apps/site/pages/fr/about/previous-releases.mdx deleted file mode 100644 index e3cb336e98516..0000000000000 --- a/apps/site/pages/fr/about/previous-releases.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Versions de Node.js -layout: about ---- - -# Versions de Node.js - -Les versions majeures de Node.js passent au statut de version _Current_ pendant six mois, ce qui donne aux auteurs de bibliothèques le temps de les prendre en charge. -Après six mois, les versions impaires (9, 11, etc.) ne sont plus supportées, et les versions paires (10, 12, etc.) passent au statut _Active LTS_ et sont prêtes pour une utilisation générale. -Le statut de la version _LTS_ correspond à un "support à long terme", qui garantit généralement que les bogues critiques seront corrigés pendant une durée totale de 30 mois. -Les applications de production ne doivent utiliser que les versions _Active LTS_ ou _Maintenance LTS_. - -## Calendrier de sortie - -![Releases](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Tous les détails concernant le calendrier des versions de Node.js sont disponibles [sur GitHub](https://github.com/nodejs/release#release-schedule). - -### Support Commercial - -Le support commercial pour les versions dépassant la phase de maintenance est disponible auprès de notre partenaire OpenJS Ecosystem Sustainability Program [HeroDevs](https://www.herodevs.com/support/node-nes?utm_source=NodeJS+&utm_medium=Link&utm_campaign=Version_support_page). - -## Vous cherchez la dernière version d'une branche de version ? - - - -## Méthodes d'installation officielles ou communautaires - -Le site web de Node.js propose plusieurs méthodes d'installation non interactives, notamment des interfaces en ligne de commande (CLI), des gestionnaires de paquets de systèmes d'exploitation (par exemple, `brew`) et des gestionnaires de versions de Node.js (par exemple, `nvm`). - -Pour mettre en valeur et promouvoir les contributions de la communauté, le projet Node.js a introduit une page de téléchargement révisée classant les méthodes d'installation en deux catégories : "Officielle" et "Communautaire". Les utilisateurs bénéficient ainsi d'une plus grande flexibilité et d'un plus grand choix. Pour plus de clarté, nous avons défini des critères pour chaque catégorie. - -### Méthodes d'installation officielles - -Les méthodes d'installation désignées comme "Officielles" doivent satisfaire aux exigences suivantes : - -| Exigences (Méthodes d'installation officielles) | -| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Les nouvelles versions de Node.js doivent être disponibles en même temps que la version officielle. | -| Les responsables de projet doivent avoir une relation étroite avec le projet Node.js, y compris des canaux de communication directs. | -| La méthode d'installation doit télécharger les binaires officiels fournis par le projet Node.js. | -| La méthode d'installation ne doit pas construire à partir des sources lorsque des binaires préconstruits sont disponibles, et ne doit pas non plus modifier les binaires officiels. | - -### Méthodes d'installation de la communauté - -Les méthodes d'installation communautaires incluses dans la page de téléchargement en libre-service (/download) doivent également respecter un ensemble minimum de critères : - -- _Prise en charge des versions :_\* Doit prendre en charge toutes les versions de Node.js actuellement prises en charge et qui ne sont pas en fin de vie. -- **Compatibilité avec les systèmes d'exploitation :** Doit fonctionner sur au moins un système d'exploitation officiellement pris en charge. -- **Prise en charge étendue du système d'exploitation :** Ne peut être limité à un sous-ensemble de distributions ou de versions du système d'exploitation. - - Par exemple, une méthode d'installation revendiquant la compatibilité avec "Windows" doit fonctionner sur "Windows 10", "Windows 11", et toutes leurs éditions (y compris les versions serveur). - - De même, une méthode d'installation revendiquant la compatibilité avec "Linux" doit pouvoir être installée sur toutes les distributions Linux majeures, et pas seulement sur un sous-ensemble spécifique. Elle ne peut pas s'appuyer sur des gestionnaires de paquets spécifiques à une distribution comme `apt` ou `dnf`. -- **Libre et Open Source:** Doit être libre d'utilisation et open source, ne doit pas être vendu comme un produit commercial, et ne doit pas être un service payant. diff --git a/apps/site/pages/id/about/previous-releases.mdx b/apps/site/pages/id/about/previous-releases.mdx deleted file mode 100644 index 834aab1490e88..0000000000000 --- a/apps/site/pages/id/about/previous-releases.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Rilisan Node.js -layout: about ---- - -# Rilisan Node.js - -Versi Node.js utama memasuki status rilis saat ini selama enam bulan, yang memberikan waktu bagi penulis perpustakaan untuk menambahkan dukungan untuk versi tersebut. Setelah enam bulan, rilis bernomor ganjil (9, 11, dst.) menjadi tidak didukung, dan rilis bernomor genap (10, 12, dst.) berpindah ke status LTS Aktif dan siap untuk penggunaan umum. Status rilis LTS adalah "dukungan jangka panjang", yang biasanya menjamin bahwa bug kritis akan diperbaiki selama total 30 bulan. Aplikasi produksi hanya boleh menggunakan rilis LTS Aktif atau LTS Pemeliharaan. - -## Jadwal rilis - -![Releases](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Detail lengkap mengenai jadwal rilis Node.js tersedia [di GitHub](https://github.com/nodejs/release#release-schedule). - -### Dukungan Komersial - -Dukungan komersial untuk versi yang melewati fase Pemeliharaan tersedia melalui mitra Program Keberlanjutan Ekosistem OpenJS kami [HeroDevs](https://herodevs.com/). - -## Mencari rilis terbaru dari cabang versi? - - - -## Metode Instalasi Resmi vs. Komunitas - -Situs web Node.js menyediakan beberapa metode instalasi non-interaktif, termasuk antarmuka baris perintah (CLI), manajer paket sistem operasi (OS) (misalnya, `brew`), dan manajer versi Node.js (misalnya, `nvm`). - -Untuk menyoroti dan mempromosikan kontribusi komunitas, proyek Node.js memperkenalkan halaman Unduhan yang telah direvisi yang mengkategorikan metode instalasi sebagai "Resmi" atau "Komunitas." Hal ini memberikan fleksibilitas dan pilihan yang lebih besar kepada pengguna. Untuk memastikan kejelasan, kami telah menetapkan kriteria untuk setiap kategori. - -### Metode Instalasi Resmi - -Metode instalasi yang ditetapkan sebagai “Resmi” harus memenuhi persyaratan berikut: - -| Persyaratan (Metode Instalasi Resmi) | -| :----------------------------------------------------------------------------------------------------------------------------------- | -| Rilis Node.js baru harus tersedia bersamaan dengan rilis resmi. | -| Pengelola proyek harus memiliki hubungan dekat dengan proyek Node.js, termasuk saluran komunikasi langsung. | -| Metode instalasi harus unduhan biner resmi yang dibundel oleh proyek Node.js. | -| Metode instalasi tidak boleh dibuild dari sumber, jika biner yang telah dibuild tersedia, dan tidak boleh pula mengubah biner resmi. | - -### Metode Instalasi Komunitas - -Metode instalasi komunitas yang disertakan pada halaman unduhan swalayan (/download) juga harus mematuhi serangkaian kriteria minimum: - -- **Dukungan Versi:** Harus mendukung semua versi Node.js yang saat ini didukung, bukan versi End-of-Life (EOL). -- **Kompatibilitas OS:** Harus berfungsi pada setidaknya satu Sistem Operasi (OS) yang didukung secara resmi. -- **Dukungan OS yang Luas:** Tidak dapat dibatasi pada sebagian distribusi atau versi OS. - - Misalnya, metode instalasi yang mengklaim kompatibilitas dengan “Windows” harus berfungsi pada “Windows 10”, “Windows 11”, dan semua edisinya (termasuk versi server). - - Demikian pula, metode instalasi yang mengklaim kompatibilitas dengan "Linux" harus dapat diinstal pada semua distribusi Linux utama, bukan hanya sebagian kecil saja. Metode ini tidak dapat bergantung pada pengelola paket khusus distribusi seperti `apt` atau `dnf`. -- **Gratis dan Sumber Terbuka:** Harus gratis digunakan dan bersumber terbuka, tidak boleh dijual sebagai produk komersial, dan tidak boleh menjadi layanan berbayar. diff --git a/apps/site/pages/ja/about/previous-releases.mdx b/apps/site/pages/ja/about/previous-releases.mdx deleted file mode 100644 index afbd03ce87b87..0000000000000 --- a/apps/site/pages/ja/about/previous-releases.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Node.js リリース -layout: about ---- - -# Node.js リリース - -Node.jsのメジャーバージョンは6か月間 _Current_ ステータスとなり、ライブラリー開発者にサポートを追加する時間を与えます。6か月後、奇数番号のバージョン(9、11など)はサポートが終了し、偶数番号のバージョン(10、12など)が _Active LTS_ ステータスに移行し、一般公開向けの準備が整います。_LTS_ ステータスとは「長期間サポート」であり、通常は合計30か月間の重要なバグ修正が保証されます。プロダクションのアプリケーションでは _Active LTS_ または _Maintenance LTS_ ステータスのバージョンのみを利用してください。 - -## リリーススケジュール - -![Releases](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Node.jsのリリーススケジュールに関する詳しい情報は[GitHub](https://github.com/nodejs/release#release-schedule)で確認できます。 - -### 商用サポート - -私たちのOpenJSエコシステム持続可能性プログラムのパートナーである[HeroDevs](https://www.herodevs.com/support/node-nes?utm_source=NodeJS+&utm_medium=Link&utm_campaign=Version_support_page)からメンテナンスを終了したバージョンの商用サポートを受けることができます。 - -## 各バージョンの最新のリリース - - - -## 公式版とコミュニティ版のインストール方法 - -Node.jsのウェブサイトではコマンドラインインターフェイス(CLI)、オペレーティングシステム(OS)、パッケージマネージャー(`brew`など)、Node.jsのバージョンマネージャー(`nvm`など)などの非対話的なインストール方法をいくつか提供しています。 - -コミュニティへの貢献を促進するためにNode.jsプロジェクトではインストール方法を「公式版」か「コミュニティ版」のどちらかに分類したダウンロードページを提供しています。これによりユーザーはより柔軟にインストール方法を選択できるようになりました。この内容を明確にするために各カテゴリーの基準を次のように定義しています。 - -### 公式版インストール方法 - -「公式版」に指定されたインストール方法は次の要件を満たさなければなりません: - -| 要件(公式版インストール方法) | -| :---------------------------------------------------------------------------------------------------------------------- | -| Node.jsの新しいリリースは公式リリースと同時に利用可能できなければならない。 | -| プロジェクトメンテナーはNode.jsと直接的なコミュニケーションも含めた密接な関係でなければらなない。 | -| Node.jsプロジェクトによって同梱されている公式バイナリーをダウンロードさせるインストール方法になっていなければならない。 | -| ビルド済みのバイナリーが利用可能な場合はソースからビルドしてはならず、公式のバイナリーを変更してはならない。 | - -### コミュニティ版インストール方法 - -セルフサービスのダウンロードページ(/download)に含まれるコミュニティ版のインストール方法も次の最低限の基準に従わなければなりません: - -- **バージョンサポート:** 現在サポートされているEOL(End-of-Life)以外の Node.jsのバージョンをすべてサポートする必要がある。 -- **OSの互換性:** 少なくとも1つの公式にサポートされているオペレーティングシステム(OS)上で機能しなければならない。 -- **幅広いOSサポート:** OSのディストリビューションやバージョンのサブセットに制限されることがないこと。 - - 例えば「Windows」との互換性を謳うインストール方法は「Windows 10」、「Windows 11」、およびそれらのすべてのエディション(サーバー版を含む)で機能しなければならない。 - - 同様に「Linux」との互換性を謳うインストー ル方法は特定のサブセットだけでなく、すべての主要なLinuxディストリビュー ションにインストールできなければない。`apt`や`dnf`のようなディストリビューション固有のパッケージマネージャに依存することはできない。 -- **フリー&オープンソース:** 自由に利用できるオープンソースでなければならず、商用製品として販売されてはならない。また有料サービスであってもならない。 diff --git a/apps/site/pages/ko/about/previous-releases.mdx b/apps/site/pages/ko/about/previous-releases.mdx deleted file mode 100644 index 041e833284221..0000000000000 --- a/apps/site/pages/ko/about/previous-releases.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Node.js 릴리스 -layout: about ---- - -# Node.js 릴리스 - -Node.js 주요 버전은 _Current_ 릴리스 상태로 6개월 동안 유지되며, 이 기간 동안 라이브러리 작성자들이 해당 버전에 대한 지원을 추가할 시간을 제공합니다. -6개월 후, 홀수 버전(9, 11 등)은 지원이 중단되고, 짝수 버전(10, 12 등)은 Active LTS 상태로 전환되어 일반 사용에 적합해집니다. -_LTS_ 릴리스 상태는 "장기 지원(long-term support)"을 의미하며, 일반적으로 총 30개월 동안 중요한 버그가 수정될 것을 보장합니다. -프로덕션 애플리케이션은 _Active LTS_ 또는 _Maintenance LTS_ 릴리스만 사용해야 합니다. - -## 릴리스 일정 - -![릴리스 일정](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Node.js 출시 일정에 대한 자세한 내용은 [GitHub](https://github.com/nodejs/release#release-schedule) 에서 확인할 수 있습니다. - -### Commercial Support - -유지 관리(Maintenance) 단계가 지난 버전에 대한 상업적 지원은 OpenJS Ecosystem Sustainability Program의 파트너인 [HeroDevs](https://herodevs.com/)를 통해 제공됩니다. - -## 최신 릴리스 브랜치를 찾고 계신가요? - - - -## 공식 버전 대 커뮤니티 버전 - -Node.js 웹사이트에서는 CLI, 운영 체제 패키지 매니저(예: apt), 또는 Node.js 버전 관리자(nvm 등)를 통해 대화형 입력 없이 Node.js를 설치할 수 있는 다양한 방법을 제공합니다. - -Node.js 프로젝트는 커뮤니티의 노력을 알리고 활성화하기 위해 "공식" 및 "커뮤니티" 설치 방법을 모두 나열한 새로운 다운로드 페이지를 선보였습니다. 이 페이지는 사용자들에게 더 다양한 옵션과 유연성을 제공합니다. -이번 변화와 함께, "공식"과 "커뮤니티" 설치 방법이라는 개념을 도입했습니다. "공식"으로 간주되기 위해 설치 방법은 다음 요건을 충족해야 합니다: - -| 요구사항 | -| ---------------------------------------------------------------------------------------------------------------------- | -| 새로운 Node.js 릴리스는 공식 릴리스와 동시에 제공되어야 합니다. | -| 프로젝트 유지 관리자는 Node.js와 직접적인 소통을 포함한 긴밀한 관계를 유지합니다. | -| 설치 방법은 Node.js 프로젝트에서 제공하는 공식 바이너리 번들을 다운로드합니다. | -| 설치 방법은 바이너리가 제공되는 경우 소스에서 빌드하지 않으며, Node.js에서 제공하는 공식 바이너리를 변경하지 않습니다. | diff --git a/apps/site/pages/pt/about/previous-releases.mdx b/apps/site/pages/pt/about/previous-releases.mdx deleted file mode 100644 index 7ee88e88e6ec5..0000000000000 --- a/apps/site/pages/pt/about/previous-releases.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Lançamentos da Node.js -layout: about ---- - -# Lançamentos da Node.js - -As principais versões da Node.js entram no estado de lançamento _Atual (Current)_ por seis meses, o que dá aos autores de bibliotecas tempo para adicionar suporte a estas. Depois de seis meses, as versões de número ímpares (9, 11, etc.) deixam de ser suportadas e as versões de números pares (10, 12, etc) passam para o estado _SLP Ativo (Active LTS)_ e estão prontas para uso geral. O estado de lançamento _SLP (LTS)_ é “suporte de longo prazo”, o que normalmente garante que os erros de programação críticos serão corrigidos durante um total de 30 meses. As aplicações de produção apenas devem usar os lançamentos _SLP Ativo (Active LTS)_ ou _SLP de Manutenção (Maintenance LTS)_. - -## Calendário de Lançamento - -![Lançamentos](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Todos os detalhes sobre o calendário de lançamento da Node.js estão disponíveis [na GitHub](https://github.com/nodejs/release#release-schedule). - -### Apoio Comercial - -O apoio comercial para versões após a fase de manutenção está disponível através do nosso parceiro [HeroDevs](https://herodevs.com/) do Programa de Sustentabilidade do Ecossistema OpenJS. - -## Procura pelo lançamento mais recente do ramo de uma versão? - - - -## Oficial ou Comunitário - -O sítio da Node.js oferece vários métodos de instalação que permitem que a Node.js seja instalada duma maneira não interativa, por exemplo, através das interfaces de linha de comando, gestores de pacotes do sistema operativo (como o `apt`) ou gestores de versões da Node.js (como o `nvm`). - -O projeto Node.js, numa tentativa de popularizar e publicitar os esforços da comunidade, introduziu uma nova página de Descargas que lista os métodos de instalação Oficial e Comunitário, proporcionando mais versatilidade e opções aos utilizadores. Com essa mudança, introduzimos o conceito de métodos de instalação “Oficial” e “Comunitário”. Para ser considerado “Oficial”, o método de instalação deve atender aos seguintes requisitos: - -| Requisitos | -| ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| As novas versões da Node.js devem estar disponíveis em simultâneo com o lançamento oficial | -| Os responsáveis pela manutenção dos projetos têm uma relação estreita com a Node.js, incluindo comunicação direta | -| O método de instalação descarrega os binários oficiais empacotados pelo projeto Node.js | -| O método de instalação **não** compila a partir da fonte quando os binários estão disponíveis, nem altera os binários oficiais fornecidos pela Node.js | diff --git a/apps/site/pages/ro/about/previous-releases.mdx b/apps/site/pages/ro/about/previous-releases.mdx deleted file mode 100644 index 8d9de69b67cca..0000000000000 --- a/apps/site/pages/ro/about/previous-releases.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Lansări Node.js -layout: about ---- - -# Lansări Node.js - -Versiunile majore de Node.js intră în stadiul de lansare _curent_ pentru șase luni, oferind astfel autorilor de biblioteci timp de asistență. -După șase luni, versiunile cu număr impar (9, 11 etc.) devin neacceptate, iar versiunile cu număr par (10, 12 etc.) trec în stadiul _Activ LTS_ și sunt pregătite pentru utilizarea generală. -Stadiul de lansare LTS reprezintă „asistență pe termen lung” și garantează, în general, că problemele critice vor fi remediate pe o perioadă totală de 30 de luni. -Aplicațiile de producție ar trebui să folosească doar lansările _Activ LTS_ sau _Întreținere LTS_. - -## Programul de lansări - -![Lansări](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Detaliile complete cu privire la programul de lansări Node.js sunt disponibile [pe GitHub](https://github.com/nodejs/release#release-schedule). - -### Suport comercial - -Asistența comercială pentru versiunile care au depășit faza de întreținere este disponibilă prin intermediul partenerului nostru din cadrul Programului de sustenabilitate a ecosistemului OpenJS [HeroDevs](https://www.herodevs.com/support/node-nes?utm_source=NodeJS+&utm_medium=Link&utm_campaign=Version_support_page). - -## Cauți cea mai recentă lansare dintr-o ramură de versiune? - - - -## Oficial vs. metodele de instalare ale comunității - -Site-ul web Node.js oferă mai multe metode de instalare neinteractive, inclusiv interfețe din linia de comandă (CLI), manageri de pachete pentru sistemul de operare (OS) (de exemplu, `brew`) și manageri de versiuni Node.js (de exemplu, `nvm`). - -Pentru a evidenția și promova contribuțiile comunității, proiectul Node.js a introdus o pagină de descărcări revizuită, care clasifică metodele de instalare fie ca „Oficiale”, fie ca „Comunitate”. Aceasta oferă utilizatorilor o flexibilitate și o gamă mai mare de opțiuni. Pentru a asigura claritatea, am definit criterii pentru fiecare categorie. - -### Metodele oficiale de instalare - -Metodele de instalare desemnate ca „oficiale” trebuie să îndeplinească următoarele cerințe: - -| Cerințe (metoda oficială de instalare) | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Noile versiuni Node.js trebuie să fie disponibile simultan cu lansarea oficială. | -| Responsabilii de întreținerea proiectului trebuie să aibă o relație strânsă cu proiectul Node.js, inclusiv pe canalele de comunicare directă. | -| Metoda de instalare trebuie să descarce fișierele binare oficiale incluse în pachetul proiectului Node.js. | -| Metoda de instalare nu trebuie să se compileze de la sursă atunci când sunt disponibile binare pre-compilate și nici nu trebuie să modifice binarele oficiale. | - -### Metodele de instalare ale comunității - -Metodele de instalare ale comunității, incluse pe pagina de descărcare self-service (/download), trebuie să respecte și un set minim de criterii: - -- **Compatibilitate versiune:** Trebuie să fie compatibile cu toate versiunile Node.js care nu sunt la sfârșitul perioadei de viață (EOL) și care sunt acceptate în prezent. -- **Compatibilitate cu sistemul de operare:** Trebuie să funcționeze pe cel puțin un sistem de operare (OS) acceptat oficial. -- **Suport extins pentru sisteme de operare:** Nu poate fi limitat la un subset de distribuții sau versiuni de sisteme de operare. - - De exemplu, o metodă de instalare care pretinde că este compatibilă cu „Windows” trebuie să funcționeze pe „Windows 10”, „Windows 11” și toate edițiile acestora (inclusiv versiunile de server). - - În mod similar, o metodă de instalare care pretinde compatibilitate cu „Linux” trebuie să poată fi instalată pe toate distribuțiile majore de Linux, nu doar pe un subset specific. Nu se poate baza pe manageri de pachete specifici distribuției, cum ar fi `apt` sau `dnf`. -- **Gratuit și cu sursă deschisă:** Trebuie să fie gratuit și cu sursă deschisă, să nu fie vândut ca produs comercial și să nu fie un serviciu plătit. diff --git a/apps/site/pages/tr/about/previous-releases.mdx b/apps/site/pages/tr/about/previous-releases.mdx deleted file mode 100644 index e8b13c47f847e..0000000000000 --- a/apps/site/pages/tr/about/previous-releases.mdx +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Node.js Sürümleri -layout: about ---- - -Node.js Sürümleri - -Ana Node.js sürümleri altı ay boyunca Mevcut yayın durumuna girer, bu da kütüphane yazarlarına destek eklemeleri için zaman tanır. -Altı ayın ardından, tek sayılı sürümler (9, 11, vb.) desteklenmez hale gelir ve çift sayılı sürümler (10, 12, vb.) Etkin LTS durumuna geçer ve genel kullanıma hazırdır. -LTS yayın durumu "uzun vadeli destek" anlamına gelir ve genellikle kritik hataların toplamda 30 ay boyunca düzeltileceğini garanti eder. -Üretim uygulamaları yalnızca Etkin LTS veya Bakım LTS sürümlerini kullanmalıdır. - -## Yayın Takvimi - -![Yayınlar](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Node.js sürüm takvimine ilişkin tüm ayrıntılar [GitHub'da](https://github.com/nodejs/release#release-schedule) mevcuttur. - -### Ticari Destek - -Bakım aşamasını geçmiş sürümler için ticari destek, OpenJS Ekosistem Sürdürülebilirlik Programı ortağımız [HeroDevs](https://herodevs.com/) aracılığıyla sağlanmaktadır. - -## Bir sürüm dalının en son sürümünü mü arıyorsunuz? - - diff --git a/apps/site/pages/uk/about/previous-releases.mdx b/apps/site/pages/uk/about/previous-releases.mdx deleted file mode 100644 index 2578a748c4b7a..0000000000000 --- a/apps/site/pages/uk/about/previous-releases.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Релізи Node.js -layout: about ---- - -# Релізи Node.js - -Основні версії Node.js мають статус релізу _Current_ протягом шести місяців, що дає час розробникам бібліотек надати їм підтримку. -Через шість місяців непарні релізи (9, 11 тощо) більше не підтримуватимуться, а парні релізи (10, 12 тощо) отримають статус _Active LTS_ та стануть готовими до загального використання. -Статус релізу _LTS_ означає «довгострокова підтримка (ДСП)», тобто критичні помилки будуть виправлятися впродовж 30 місяців. -Застосунки в клієнтському середовищі повинні використовувати лише релізи _Active LTS_ та _Maintenance LTS_. - -## Розклад релізів - -![Релізи](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -Усі деталі, які стосуються розкладу релізів Node.js, доступні [на GitHub](https://github.com/nodejs/release#release-schedule). - -### Комерційна підтримка - -Комерційна підтримка для версій після фази Maintenance доступна з нашим партнером програми OpenJS Ecosystem Sustainability [HeroDevs](https://www.herodevs.com/support/node-nes?utm_source=NodeJS+&utm_medium=Link&utm_campaign=Version_support_page). - -## Шукаєте останній реліз гілки версії? - - - -## Офіційні та спільнотні методи установки - -Вебсайт Node.js пропонує кілька неінтерактивних методів установки, як-от інтерфейси командного рядка (CLI), менеджери пакетів ОС (напр. `brew`) та менеджери версій Node.js (напр. `nvm`). - -Аби показати та просувати внески спільноти, проєкт Node.js представляє нову сторінку завантажень, яка поділяє методи установки на «офіційні» та «спільнотні». Це надає користувачам більше гнучкості та вибору, а для зрозумілості ми створили критерії для кожної категорії. - -### Офіційні методи установки - -«Офіційні» методи установки повинні виконувати наступні вимоги: - -| Вимоги до офіційних методів установки | -| :------------------------------------------------------------------------------------------------------------------------------------------------- | -| Нові релізи Node.js повинні бути доступні одразу після офіційного релізу. | -| Супроводжувачі проєкту повинні мати близькі зв'язки з проєктом Node.js, у тому числі й пряме спілкування. | -| Метод установки повинний завантажувати офіційні бінарні файли, зібрані проєктом Node.js. | -| Метод установки не повинний будувати з вихідного коду, коли доступні вже збудовані бінарні файли, а також не має змінювати офіційні бінарні файли. | - -### Спільнотні методи установки - -Спільнотні методи установки, які містяться на самообслуговуваній сторінці завантажень (/download), також мають відповідати мінімальному набору критеріїв: - -- **Підтримка версій:** Повинні підтримувати всі версії Node.js, які не мають статусу End-of-Life (EOL). -- **Сумісність ОС:** Повинні працювати на принаймні одній офіційно підтримуваній операційній системі (ОС). -- **Широка підтримка ОС:** Не можуть обмежуватися лише кількома дистрибутивами чи версіями ОС. - - Наприклад, якщо метод установки заявляє, що підтримує «Windows», він повинний працювати на «Windows 10», «Windows 11» та всіх їхніх випусках (включно із серверними версіями). - - Схожим чином, якщо метод установки заявляє, що підтримує «Linux», він повинний працювати на всіх великих дистрибутивах Linux, а не лише на конкретних. Також він не може покладатися на менеджери пакетів, специфічних для деяких дистрибутивів, як-от `apt` чи `dnf`. -- **Вільність і відкритість вихідного коду:** Повинні бути вільними для використання та мати відкритий вихідний код, не можуть продаватися як комерційний продукт та не можуть бути платним сервісом. diff --git a/apps/site/pages/zh-cn/about/previous-releases.mdx b/apps/site/pages/zh-cn/about/previous-releases.mdx deleted file mode 100644 index 263d26491bd71..0000000000000 --- a/apps/site/pages/zh-cn/about/previous-releases.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Node.js 版本 -layout: about ---- - -Node.js 版本 - -主要的 Node.js 版本在 6 个月的时间内进入 Current 发布状态,这给了库作者时间来为它们添加支持。 -个月后,奇数版本(9、11 等)变为不支持,偶数版本(10、12 等)移至 Active LTS 状态,可以用于一般用途。 -LTS 发布状态为“长期支持”,通常保证关键错误将被修复,共计 30 个月。 -生产应用程序应仅使用 Active LTS 或 Maintenance LTS 发布版本。 - -## 发布计划 - -![Releases](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -有关 Node.js 发布计划的详细信息可在 [GitHub](https://github.com/nodejs/release#release-schedule) 上找到。 - -## 正在寻找某个版本的最新版? - - diff --git a/apps/site/pages/zh-tw/about/previous-releases.mdx b/apps/site/pages/zh-tw/about/previous-releases.mdx deleted file mode 100644 index d223786edcb90..0000000000000 --- a/apps/site/pages/zh-tw/about/previous-releases.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Node.js 版本 -layout: about ---- - -# Node.js 版本 - -Node.js 的主要版本在釋出後六個月內皆處於最新 (Current) 狀態,讓函式庫作者有時間為其新增支援功能。六個月後,奇數編號的釋出版本 (如 9、11 等) 會停止支援,而偶數編號的釋出版本 (如 10、12 等) 會進入活躍 LTS (Active LTS) 狀態,開放一般大眾使用。LTS 狀態代表「長期支援」,在 30 個月內發現的重大錯誤通常都會得到修復。生產環境的應用程式僅應使用活躍 LTS 或維護 LTS (Maintenance LTS) 版本。 - -## 釋出時間表 - -![版本釋出](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true) - -關於 Node.js 的詳細釋出時間表請見 [Github](https://github.com/nodejs/release#release-schedule)。 - -### 商用支援 - -我們的 OpenJS Ecosystem Sustainability Program 夥伴 [HeroDevs](https://herodevs.com/) 針對已脫離維護階段的版本提供商用支援。 - -## 在找某個主要版本的最新版嗎? - - - -## 比較官方及社群提供的安裝方法 - -Node.js 網站提供數種免介入的安裝方法,包括命令列介面 (CLIs)、作業系統的套件管理程式(如:`brew`)及 Node.js 版本管理程式(如:`nvm`)。 - -為強調並促進社群貢獻,Node.js 專案引入了改版的下載頁面,將安裝方法分為「官方」及「社群」以提供使用者更多彈性及選擇。為區分清楚,我們定義了各類別的條件。 - -### 官方安裝方法 - -指定為「官方」的安裝方法需滿足下列條件: - -| 條件(官方安裝方法) | -| :--------------------------------------------------------------------------------- | -| 必須與官方同時釋出新版 Node.js | -| 專案維護者與 Node.js 保持密切聯繫,例如有直接的溝通管道 | -| 該安裝方法需下載由 Node.js 專案打包的官方二進位檔 | -| 該安裝方法不可在有預先建置的二進位檔時,仍自行編譯原始碼,也不可修改官方的二進位檔 | - -### 社群提供的安裝方法 - -下載頁面 (/download) 列出的社群安裝方法,也必須遵守下列的最低條件: - -- **版本支援**: 須支援所有仍受到支援、未結束生命週期 (EOL) 的 Node.js 版本 -- **作業系統相容性**:須可運作於至少一種官方支援的作業系統 -- **廣泛作業系統支援**:不可侷限於一部分作業系統發行版或版本 - - 例如,一項宣稱相容「Windows」的安裝方法,須可運作於包含伺服器版在內所有「Windows 10」、「Windows 11」版本 (edition) - - 類似地,一項宣稱相容「Linux」的安裝方法,須可安裝於所有主要的 Linux 發行版,而非限於其中一部分。該安裝方法不可依賴特定發行版的套件管理程式,如 `apt` 或 `dnf` -- **自由且開放源碼**:須可自由使用並開放原始碼,不可被作為商業產品販售,且不可為付費使用的服務 diff --git a/apps/site/providers/releaseModalProvider.tsx b/apps/site/providers/releaseModalProvider.tsx deleted file mode 100644 index 8f94aba9fe5ff..0000000000000 --- a/apps/site/providers/releaseModalProvider.tsx +++ /dev/null @@ -1,45 +0,0 @@ -'use client'; - -import { createContext, useState } from 'react'; -import type { FC, PropsWithChildren } from 'react'; - -import ReleaseModal from '#site/components/Downloads/ReleaseModal'; -import type { NodeRelease } from '#site/types'; - -type ReleaseModalContextType = { - activeRelease: NodeRelease | null; - openModal: (activeRelease: NodeRelease) => void; - closeModal: () => void; -}; - -export const ReleaseModalContext = createContext({ - activeRelease: null, - openModal: () => {}, - closeModal: () => {}, -}); - -export const ReleaseModalProvider: FC = ({ children }) => { - const [activeRelease, setValue] = useState(null); - - const openModal = (activeRelease: NodeRelease) => { - setValue(activeRelease); - }; - - const closeModal = () => { - setValue(null); - }; - - return ( - - {children} - - {activeRelease && ( - - )} - - ); -}; diff --git a/apps/site/redirects.json b/apps/site/redirects.json index 02cc24e0f0ca2..f69bf838b62b4 100644 --- a/apps/site/redirects.json +++ b/apps/site/redirects.json @@ -339,6 +339,10 @@ { "source": "/:locale/discord", "destination": "https://discord.gg/vUsrbjd" + }, + { + "source": "/:locale/esp/herodevs", + "destination": "https://www.herodevs.com/support/node-nes?utm_source=NodeJS+&utm_medium=Link&utm_campaign=Nodejs_eol_support" } ], "internal": [] diff --git a/apps/site/types/index.ts b/apps/site/types/index.ts index 38f5767b732db..615f7a365cff1 100644 --- a/apps/site/types/index.ts +++ b/apps/site/types/index.ts @@ -13,3 +13,4 @@ export * from './calendar'; export * from './author'; export * from './download'; export * from './userAgent'; +export * from './vulnerabilities'; diff --git a/apps/site/types/vulnerabilities.ts b/apps/site/types/vulnerabilities.ts new file mode 100644 index 0000000000000..44ae897b35ae4 --- /dev/null +++ b/apps/site/types/vulnerabilities.ts @@ -0,0 +1,15 @@ +export type Severity = 'unknown' | 'low' | 'medium' | 'high' | 'critical'; +export interface Vulnerability { + cve: Array; + url?: string; + vulnerable: string; + patched?: string; + description: string; + overview: string; + affectedEnvironments: Array; + severity: Severity; +} + +export interface GroupedVulnerabilities { + [majorVersion: string]: Array; +} diff --git a/docs/translation.md b/docs/translation.md index 32f428a95d81e..e5b05e3836a94 100644 --- a/docs/translation.md +++ b/docs/translation.md @@ -60,6 +60,14 @@ If you're making a new Component and adding Translation Keys for your Component, - Translation Keys should be in Camel Case only. - The values of each Translation Key should follow the [ICU Message Syntax](https://next-intl-docs.vercel.app/docs/usage/messages#rendering-icu-messages) - All new Translation keys should be added at the bottom of the `i18n/locales/en.json` file. Since this makes it easier for Translators to notice that there are new Translation keys to be translated. +- Reference the full path to the key within your Component. This helps with static analysis, even at the cost of verbosity. For example: + +```tsx +❌ const t = useTranslations('components.common.myComponent'); +❌ t('copyButton.title'); +✅ const t = useTranslations(); +✅ t('components.common.myComponent.copyButton.title'); +``` #### Notes about Translation Keys diff --git a/packages/i18n/src/locales/en.json b/packages/i18n/src/locales/en.json index cadcca42859f3..d7080ae9f2048 100644 --- a/packages/i18n/src/locales/en.json +++ b/packages/i18n/src/locales/en.json @@ -176,6 +176,41 @@ "unsupportedVersionWarning": "This version is out of maintenance. Please use a supported version. Understand EOL support.", "ltsVersionFeaturesNotice": "Want new features sooner? Get the latest Node.js version instead and try the latest improvements!" }, + "eolAlert": { + "intro": "Commercial support for versions past the Maintenance LTS phase is available through our", + "partner": "partner" + }, + "eolChip": { + "severity": { + "unknown": "Unknown", + "low": "Low", + "medium": "Medium", + "high": "High", + "critical": "Critical" + } + }, + "eolModal": { + "title": "Node.js v{version} ({codename}) has reached EOL", + "titleWithoutCodename": "Node.js v{version} has reached EOL", + "vulnerabilitiesMessage": "There are {count}+ known security issues (CVEs) associated with this Node.js release. CVEs (Common Vulnerabilities and Exposures) are identifiers for publicly reported security flaws. Clicking a CVE link will take you to more technical details, such as how the vulnerability works.", + "noVulnerabilitiesMessage": "There are currently no known CVEs (Common Vulnerabilities and Exposures) associated with this Node.js release. However, that doesn't mean it's completely secure—some vulnerabilities may not yet be discovered or publicly disclosed. If this release is outdated or unsupported, it's still a good idea to consider upgrading to ensure you benefit from the latest fixes and security improvements.", + "blogLinkText": "Blog", + "showUnknownSeverities": "Show vulnerabilities of unknown severity", + "table": { + "cves": "CVE(s)", + "severity": "Severity", + "overview": "Overview", + "details": "Details" + } + }, + "eolTable": { + "version": "Version", + "codename": "Codename", + "releaseDate": "Released at", + "lastUpdated": "Last updated", + "vulnerabilities": "Vulnerabilities", + "details": "Details" + }, "minorReleasesTable": { "version": "Version", "links": "Links", diff --git a/packages/ui-components/src/Common/AlertBox/index.stories.tsx b/packages/ui-components/src/Common/AlertBox/index.stories.tsx index 5b0c4326b152b..85f1962c59653 100644 --- a/packages/ui-components/src/Common/AlertBox/index.stories.tsx +++ b/packages/ui-components/src/Common/AlertBox/index.stories.tsx @@ -95,6 +95,21 @@ export const WithIcon: Story = { }, }; +export const NoTitle: Story = { + args: { + level: 'info', + children: ( +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, + quasi doloremque. Totam, earum velit, sunt voluptates fugiat beatae + praesentium quis magni explicabo repudiandae nam aut molestias ex ad + sequi eum! +

+ ), + size: 'default', + }, +}; + export default { component: AlertBox, argTypes: { diff --git a/packages/ui-components/src/Common/AlertBox/index.tsx b/packages/ui-components/src/Common/AlertBox/index.tsx index de4b1d3a5d634..f4db57546dd8c 100644 --- a/packages/ui-components/src/Common/AlertBox/index.tsx +++ b/packages/ui-components/src/Common/AlertBox/index.tsx @@ -5,7 +5,7 @@ import styles from './index.module.css'; type AlertBoxProps = PropsWithChildren<{ level: 'info' | 'success' | 'warning' | 'danger' | 'neutral'; - title: string; + title?: string; size?: 'default' | 'small'; }>; diff --git a/packages/ui-components/src/Common/Badge/index.tsx b/packages/ui-components/src/Common/Badge/index.tsx index c5d2e6991880c..15e12e2e8e058 100644 --- a/packages/ui-components/src/Common/Badge/index.tsx +++ b/packages/ui-components/src/Common/Badge/index.tsx @@ -3,7 +3,7 @@ import type { FC, HTMLAttributes, PropsWithChildren } from 'react'; import styles from './index.module.css'; -type BadgeKind = 'default' | 'warning' | 'error' | 'info' | 'neutral'; +export type BadgeKind = 'default' | 'warning' | 'error' | 'info' | 'neutral'; type BadgeSize = 'small' | 'medium'; type BadgeProps = HTMLAttributes & { diff --git a/packages/ui-components/src/Common/BaseButton/index.module.css b/packages/ui-components/src/Common/BaseButton/index.module.css index fda005bcf9daa..55e850ca06100 100644 --- a/packages/ui-components/src/Common/BaseButton/index.module.css +++ b/packages/ui-components/src/Common/BaseButton/index.module.css @@ -142,4 +142,54 @@ @apply bg-green-600/20; } } + + &.warning { + @apply shadow-xs + border-warning-600 + bg-warning-600 + rounded-sm + border + text-white; + + &:hover:not([aria-disabled='true']) { + @apply border-warning-700 + bg-warning-700 + text-white; + } + + &:focus { + @apply border-warning-700 + bg-warning-700; + } + + &[aria-disabled='true'] { + @apply bg-warning-600 + opacity-50; + } + } + + &.info { + @apply shadow-xs + border-info-600 + bg-info-600 + rounded-sm + border + text-white; + + &:hover:not([aria-disabled='true']) { + @apply border-info-700 + bg-info-700 + text-white; + } + + &:focus { + @apply border-info-700 + bg-info-700; + } + + &[aria-disabled='true'] { + @apply bg-info-600 + opacity-50; + } + } } diff --git a/packages/ui-components/src/Common/BaseButton/index.stories.tsx b/packages/ui-components/src/Common/BaseButton/index.stories.tsx index 36ffb058a914f..67e8012ae1c87 100644 --- a/packages/ui-components/src/Common/BaseButton/index.stories.tsx +++ b/packages/ui-components/src/Common/BaseButton/index.stories.tsx @@ -33,6 +33,15 @@ export const Secondary: Story = { }, }; +export const Warning: Story = { + args: { + kind: 'warning', + children: 'Get security support for EOL versions ', + disabled: false, + size: 'default', + }, +}; + export const Special: Story = { args: { kind: 'special', diff --git a/packages/ui-components/src/Common/BaseButton/index.tsx b/packages/ui-components/src/Common/BaseButton/index.tsx index 383c6f8d9dd53..a20645c02bfdd 100644 --- a/packages/ui-components/src/Common/BaseButton/index.tsx +++ b/packages/ui-components/src/Common/BaseButton/index.tsx @@ -9,7 +9,7 @@ export type ButtonProps = ( | AnchorHTMLAttributes | ButtonHTMLAttributes ) & { - kind?: 'neutral' | 'primary' | 'secondary' | 'special'; + kind?: 'neutral' | 'primary' | 'secondary' | 'special' | 'warning' | 'info'; size?: 'default' | 'small'; disabled?: boolean; as?: LinkLike;