From b430020dbe2e09c8fd4de4140203dfe6f4542c28 Mon Sep 17 00:00:00 2001 From: MattIPv4 Date: Fri, 6 Feb 2026 16:23:48 +0000 Subject: [PATCH 1/4] Use fetchWithRetry for nodevu fetch calls --- apps/site/next-data/generators/majorNodeReleases.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/site/next-data/generators/majorNodeReleases.mjs b/apps/site/next-data/generators/majorNodeReleases.mjs index 0a9a06e8cd5e4..108bc14156160 100644 --- a/apps/site/next-data/generators/majorNodeReleases.mjs +++ b/apps/site/next-data/generators/majorNodeReleases.mjs @@ -2,11 +2,13 @@ import nodevu from '@nodevu/core'; +import { fetchWithRetry } from '#site/util/fetch'; + /** * Filters Node.js release data to return only major releases with documented support. */ export default async function getMajorNodeReleases() { - const nodevuData = await nodevu({ fetch }); + const nodevuData = await nodevu({ fetch: fetchWithRetry }); return Object.entries(nodevuData).filter(([version, { support }]) => { // Filter out those without documented support From 2476983d53cb2e529ae701a21244b14f6cf8cfc4 Mon Sep 17 00:00:00 2001 From: MattIPv4 Date: Fri, 6 Feb 2026 16:28:33 +0000 Subject: [PATCH 2/4] Avoid node: import in fetch util --- apps/site/util/fetch.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/site/util/fetch.ts b/apps/site/util/fetch.ts index 61378982c6616..64d224328d395 100644 --- a/apps/site/util/fetch.ts +++ b/apps/site/util/fetch.ts @@ -1,5 +1,3 @@ -import { setTimeout } from 'node:timers/promises'; - type RetryOptions = RequestInit & { maxRetry?: number; delay?: number; @@ -28,7 +26,7 @@ export const fetchWithRetry = async ( throw e; } - await setTimeout(delay * i); + await new Promise(resolve => setTimeout(resolve, delay * i)); } } }; From 645cf7909184b8dc74e474020d1ba60af1ba7652 Mon Sep 17 00:00:00 2001 From: MattIPv4 Date: Fri, 6 Feb 2026 16:30:23 +0000 Subject: [PATCH 3/4] Add missing await to fetch util --- apps/site/util/fetch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/site/util/fetch.ts b/apps/site/util/fetch.ts index 64d224328d395..753903b5cc473 100644 --- a/apps/site/util/fetch.ts +++ b/apps/site/util/fetch.ts @@ -15,7 +15,7 @@ export const fetchWithRetry = async ( ) => { for (let i = 1; i <= maxRetry; i++) { try { - return fetch(url, options); + return await fetch(url, options); } catch (e) { console.debug( `fetch of ${url} failed at ${Date.now()}, attempt ${i}/${maxRetry}`, From 55f54bb43edcc89134d821a524bdb4a33c297bac Mon Sep 17 00:00:00 2001 From: MattIPv4 Date: Fri, 6 Feb 2026 16:38:55 +0000 Subject: [PATCH 4/4] Avoid unsafe access to e.cause.code --- apps/site/util/fetch.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/site/util/fetch.ts b/apps/site/util/fetch.ts index 753903b5cc473..b998879503ef1 100644 --- a/apps/site/util/fetch.ts +++ b/apps/site/util/fetch.ts @@ -3,11 +3,12 @@ type RetryOptions = RequestInit & { delay?: number; }; -type FetchError = { - cause: { - code: string; - }; -}; +const isTimeoutError = (e: unknown): boolean => + e instanceof Error && + typeof e.cause === 'object' && + e.cause !== null && + 'code' in e.cause && + e.cause.code === 'ETIMEDOUT'; export const fetchWithRetry = async ( url: string, @@ -22,7 +23,7 @@ export const fetchWithRetry = async ( e ); - if (i === maxRetry || (e as FetchError).cause.code !== 'ETIMEDOUT') { + if (i === maxRetry || !isTimeoutError(e)) { throw e; }