From 7a7b6fcec891452383839330a936334cf2bcc384 Mon Sep 17 00:00:00 2001 From: "InstaWP Engineer (bot)" Date: Fri, 10 Jul 2026 10:11:13 +0000 Subject: [PATCH] fix: local connectivity check fails on valid networks (302 redirect) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit checkPlaygroundConnectivity() HEAD-fetched downloads.w.org, which 302-redirects to wordpress.org/download/. Following that redirect is fragile: on some networks the HEAD-follow errors out, and a GET-follow downloads the full target page and times out — so `instawp local create` reported "Cannot reach WordPress download servers" despite working connectivity (curl -I and https.get, neither of which follow the redirect, both succeed). Fix: add redirect:'manual' to both reachability probes. Any response (including the 302) proves the host is reachable, which is all the check needs — matching curl -I / https.get behaviour. Smallest change; existing "no throw => reachable" logic is unchanged. Reproduced locally on Node 22: HEAD-follow OK but GET-follow ETIMEDOUT; HEAD/GET with redirect:'manual' both return 302 fast. Verified the patched probe returns null (reachable). Co-Authored-By: Claude Opus 4.8 --- src/lib/local-env.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/local-env.ts b/src/lib/local-env.ts index 4d9c218..ed0c3e6 100644 --- a/src/lib/local-env.ts +++ b/src/lib/local-env.ts @@ -60,7 +60,10 @@ export async function checkPlaygroundConnectivity(): Promise { try { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 8000); - await fetch('https://downloads.w.org', { signal: controller.signal, method: 'HEAD' }); + // redirect:'manual' — downloads.w.org 302-redirects to wordpress.org/download/. Following it is + // fragile (HEAD-follow fails on some networks; GET-follow downloads the whole target and times out), + // so we don't follow: any response (incl. the 302) proves the host is reachable, which is all we test. + await fetch('https://downloads.w.org', { signal: controller.signal, method: 'HEAD', redirect: 'manual' }); clearTimeout(timer); return null; } catch { @@ -68,7 +71,7 @@ export async function checkPlaygroundConnectivity(): Promise { try { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 8000); - await fetch('https://downloads.wordpress.org', { signal: controller.signal, method: 'HEAD' }); + await fetch('https://downloads.wordpress.org', { signal: controller.signal, method: 'HEAD', redirect: 'manual' }); clearTimeout(timer); return 'downloads.w.org is unreachable from your network (downloads.wordpress.org works).\n' + 'WordPress Playground CLI requires access to downloads.w.org.\n' +