From 34d2602132c080ac7c38ba426d9fa044aef34f5e Mon Sep 17 00:00:00 2001 From: Viktor Vaczi Date: Sat, 4 Jul 2026 11:39:38 +0200 Subject: [PATCH] fix(demo): POST waitlist to canonical www host to avoid preflight redirect The demo (demo.pcbjam.com) cross-posts the waitlist to the marketing site's serverless endpoint. It targeted the apex pcbjam.com, which 308-redirects to www on Vercel; a CORS preflight can't follow redirects, so the OPTIONS failed ("Redirect is not allowed for a preflight request") and the POST never landed. Point the waitlist target at the canonical www host. www.pcbjam.com already returns 204 with access-control-allow-origin: https://demo.pcbjam.com, so the preflight passes. Landing/version-badge link stays on the apex. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01REwWZGkAz1AZUJw8yqxkCN --- scripts/deploy/build-demo.mjs | 9 ++++++++- web/standalone/.env.example | 6 ++++-- web/standalone/src/lib/config.ts | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/scripts/deploy/build-demo.mjs b/scripts/deploy/build-demo.mjs index 243c9c3..6fdb84b 100644 --- a/scripts/deploy/build-demo.mjs +++ b/scripts/deploy/build-demo.mjs @@ -58,7 +58,14 @@ function parseArgs(argv) { a.cdn = a.cdn.replace(/\/+$/, ""); a.repo = a.repo.replace(/\/+$/, ""); a.landing = a.landing.replace(/\/+$/, ""); - a.waitlist = a.waitlist || `${a.landing}/api/waitlist`; + // The cross-origin demo POSTs the waitlist to the marketing site's serverless + // endpoint. The apex (pcbjam.com) 308-redirects to www on Vercel, and a CORS + // preflight can't follow redirects, so the demo must hit the canonical www host + // directly. Derive from --landing for custom/staging hosts, but pin the + // production apex to www. (Landing/version-badge link stays on the apex.) + const waitlistHost = + a.landing === "https://pcbjam.com" ? "https://www.pcbjam.com" : a.landing; + a.waitlist = a.waitlist || `${waitlistHost}/api/waitlist`; return a; } diff --git a/web/standalone/.env.example b/web/standalone/.env.example index cc9f321..16828e8 100644 --- a/web/standalone/.env.example +++ b/web/standalone/.env.example @@ -34,11 +34,13 @@ VITE_WASM_ROOT=/wasm # Marketing / landing page the version badge links to (default https://pcbjam.com). # VITE_LANDING_URL=https://pcbjam.com -# Where the in-editor waitlist form POSTs (default https://pcbjam.com/api/waitlist). +# Where the in-editor waitlist form POSTs (default https://www.pcbjam.com/api/waitlist). # The demo is static with no backend, so it cross-posts to the landing site's # serverless endpoint, which must send CORS for this origin (see # site/src/pages/api/waitlist.ts). Same JSON contract {email, source, company_url}. -# VITE_WAITLIST_URL=https://pcbjam.com/api/waitlist +# Use the canonical www host: the apex 308-redirects to www and a CORS preflight +# can't follow redirects. +# VITE_WAITLIST_URL=https://www.pcbjam.com/api/waitlist # Plausible analytics. Unset ⇒ no tracking (dev/checkout default). Set the # data-domain to enable; override the script URL only if the default plausible.io diff --git a/web/standalone/src/lib/config.ts b/web/standalone/src/lib/config.ts index 32f938f..c651d5f 100644 --- a/web/standalone/src/lib/config.ts +++ b/web/standalone/src/lib/config.ts @@ -54,9 +54,11 @@ export const LANDING_URL = ( * Where the in-editor waitlist form POSTs. The demo is a fully static deploy with * no backend, so it cross-posts to the landing site's serverless endpoint (which * sends CORS for this origin). Same JSON contract as site/src/pages/api/waitlist.ts. + * Targets the canonical www host: the apex 308-redirects to www on Vercel, and a + * CORS preflight can't follow a redirect (so the apex would break the POST). */ export const WAITLIST_URL = - import.meta.env.VITE_WAITLIST_URL || "https://pcbjam.com/api/waitlist"; + import.meta.env.VITE_WAITLIST_URL || "https://www.pcbjam.com/api/waitlist"; /** * Plausible analytics (privacy-friendly, cookieless). Off unless a domain is set