Skip to content

Commit 6a3b0bb

Browse files
committed
fix(fetch): fixup generators and add error handling
1 parent 43ffe41 commit 6a3b0bb

File tree

5 files changed

+97
-95
lines changed

5 files changed

+97
-95
lines changed
Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
1+
import { OPENCOLLECTIVE_MEMBERS_URL } from '#site/next.constants.mjs';
2+
13
/**
24
* Fetches supporters data from Open Collective API, filters active backers,
35
* and maps it to the Supporters type.
46
*
5-
* @returns {Promise<Array<import('#site/types/supporters')>>} Array of supporters
7+
* @returns {Promise<Array<import('#site/types/supporters').OpenCollectiveSupporter>>} Array of supporters
68
*/
7-
async function fetchOpenCollectiveData() {
8-
const endpoint = 'https://opencollective.com/nodejs/members/all.json';
9-
10-
const response = await fetch(endpoint);
11-
12-
const payload = await response.json();
13-
14-
const members = payload
15-
.filter(({ role, isActive }) => role === 'BACKER' && isActive)
16-
.sort((a, b) => b.totalAmountDonated - a.totalAmountDonated)
17-
.map(({ name, website, image, profile }) => ({
18-
name,
19-
image,
20-
url: website,
21-
profile,
22-
source: 'opencollective',
23-
}));
24-
25-
return members;
26-
}
27-
28-
export default fetchOpenCollectiveData;
9+
export default () =>
10+
fetch(OPENCOLLECTIVE_MEMBERS_URL)
11+
.then(response => response.json())
12+
.then(payload =>
13+
payload
14+
.filter(({ role, isActive }) => role === 'BACKER' && isActive)
15+
.sort((a, b) => b.totalAmountDonated - a.totalAmountDonated)
16+
.map(({ name, website, image, profile }) => ({
17+
name,
18+
image,
19+
url: website,
20+
profile,
21+
source: 'opencollective',
22+
}))
23+
)
24+
.catch(() => []);

apps/site/next-data/generators/vulnerabilities.mjs

Lines changed: 62 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -8,86 +8,76 @@ const RANGE_REGEX = /([<>]=?)\s*(\d+)(?:\.(\d+))?/;
88
*
99
* @returns {Promise<import('#site/types/vulnerabilities').GroupedVulnerabilities>} Grouped vulnerabilities
1010
*/
11-
export default async function generateVulnerabilityData() {
12-
const response = await fetch(VULNERABILITIES_URL);
11+
export default () =>
12+
fetch(VULNERABILITIES_URL)
13+
.then(response => response.json())
14+
.then(payload => {
15+
/** @type {Array<import('#site/types/vulnerabilities').RawVulnerability>} */
16+
const data = Object.values(payload);
17+
18+
/** @type {Promise<import('#site/types/vulnerabilities').GroupedVulnerabilities> */
19+
const grouped = {};
20+
21+
// Helper function to add vulnerability to a major version group
22+
const addToGroup = (majorVersion, vulnerability) => {
23+
grouped[majorVersion] ??= [];
24+
grouped[majorVersion].push(vulnerability);
25+
};
26+
27+
// Helper function to process version patterns
28+
const processVersion = (version, vulnerability) => {
29+
// Handle 0.X versions (pre-semver)
30+
if (/^0\.\d+(\.x)?$/.test(version)) {
31+
addToGroup('0', vulnerability);
32+
33+
return;
34+
}
35+
36+
// Handle simple major.x patterns (e.g., 12.x)
37+
if (/^\d+\.x$/.test(version)) {
38+
const majorVersion = version.split('.')[0];
1339

14-
/** @type {Array<import('#site/types/vulnerabilities').RawVulnerability>} */
15-
const data = Object.values(await response.json());
16-
17-
/** @type {Promise<import('#site/types/vulnerabilities').GroupedVulnerabilities> */
18-
const grouped = {};
19-
20-
// Helper function to add vulnerability to a major version group
21-
const addToGroup = (majorVersion, vulnerability) => {
22-
grouped[majorVersion] ??= [];
23-
grouped[majorVersion].push(vulnerability);
24-
};
25-
26-
// Helper function to process version patterns
27-
const processVersion = (version, vulnerability) => {
28-
// Handle 0.X versions (pre-semver)
29-
if (/^0\.\d+(\.x)?$/.test(version)) {
30-
addToGroup('0', vulnerability);
31-
32-
return;
33-
}
34-
35-
// Handle simple major.x patterns (e.g., 12.x)
36-
if (/^\d+\.x$/.test(version)) {
37-
const majorVersion = version.split('.')[0];
40+
addToGroup(majorVersion, vulnerability);
3841

39-
addToGroup(majorVersion, vulnerability);
42+
return;
43+
}
4044

41-
return;
42-
}
45+
// Handle version ranges (>, >=, <, <=)
46+
const rangeMatch = RANGE_REGEX.exec(version);
4347

44-
// Handle version ranges (>, >=, <, <=)
45-
const rangeMatch = RANGE_REGEX.exec(version);
48+
if (rangeMatch) {
49+
const [, operator, majorVersion] = rangeMatch;
4650

47-
if (rangeMatch) {
48-
const [, operator, majorVersion] = rangeMatch;
51+
const majorNum = parseInt(majorVersion, 10);
4952

50-
const majorNum = parseInt(majorVersion, 10);
53+
switch (operator) {
54+
case '>=':
55+
case '>':
56+
case '<=':
57+
addToGroup(majorVersion, vulnerability);
5158

52-
switch (operator) {
53-
case '>=':
54-
case '>':
55-
case '<=':
56-
addToGroup(majorVersion, vulnerability);
59+
break;
60+
case '<':
61+
// Add to all major versions below the specified version
62+
for (let i = majorNum - 1; i >= 0; i--) {
63+
addToGroup(i.toString(), vulnerability);
64+
}
5765

58-
break;
59-
case '<':
60-
// Add to all major versions below the specified version
61-
for (let i = majorNum - 1; i >= 0; i--) {
62-
addToGroup(i.toString(), vulnerability);
66+
break;
6367
}
68+
}
69+
};
6470

65-
break;
71+
for (const { ref, ...vulnerability } of Object.values(data)) {
72+
vulnerability.url = ref;
73+
// Process all potential versions from the vulnerable field
74+
const versions = vulnerability.vulnerable.split(' || ').filter(Boolean);
75+
76+
for (const version of versions) {
77+
processVersion(version, vulnerability);
78+
}
6679
}
67-
}
68-
};
69-
70-
for (const vulnerability of Object.values(data)) {
71-
const parsedVulnerability = {
72-
cve: vulnerability.cve,
73-
url: vulnerability.ref,
74-
vulnerable: vulnerability.vulnerable,
75-
patched: vulnerability.patched,
76-
description: vulnerability.description,
77-
overview: vulnerability.overview,
78-
affectedEnvironments: vulnerability.affectedEnvironments,
79-
severity: vulnerability.severity,
80-
};
81-
82-
// Process all potential versions from the vulnerable field
83-
const versions = parsedVulnerability.vulnerable
84-
.split(' || ')
85-
.filter(Boolean);
86-
87-
for (const version of versions) {
88-
processVersion(version, parsedVulnerability);
89-
}
90-
}
91-
92-
return grouped;
93-
}
80+
81+
return grouped;
82+
})
83+
.catch(() => ({}));

apps/site/next.constants.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,9 @@ export const EOL_VERSION_IDENTIFIER = 'End-of-life';
213213
*/
214214
export const VULNERABILITIES_URL =
215215
'https://raw.githubusercontent.com/nodejs/security-wg/main/vuln/core/index.json';
216+
217+
/**
218+
* The location of the OpenCollective data
219+
*/
220+
export const OPENCOLLECTIVE_MEMBERS_URL =
221+
'https://opencollective.com/nodejs/members/all.json';

apps/site/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ export * from './download';
1616
export * from './userAgent';
1717
export * from './vulnerabilities';
1818
export * from './page';
19+
export * from './supporters';

apps/site/types/supporters.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export type Supporter = {
2+
name: string;
3+
image: string;
4+
url: string;
5+
profile: string;
6+
source: string;
7+
};
8+
9+
export type OpenCollectiveSupporter = Supporter & { source: 'opencollective' };

0 commit comments

Comments
 (0)