# www.pcbjam.com The Astro marketing site + blog (`../../site`) on **Cloudflare Pages** (project `pcbjam-site`), with one **Pages Function** for `/api/waitlist`. Both `www.pcbjam.com` and the apex `pcbjam.com` are custom domains on that project and serve identically; the pages emit `canonical=www`, which is what consolidates them for search. ``` push to main (site/**) ──▶ .github/workflows/deploy-site.yml 1. npm ci 2. npm test (vitest — nothing else runs it) 3. astro build → site/dist/ (static; no adapter) 4. wrangler pages deploy → www.pcbjam.com 5. smoke: /api/waitlist preflight == 204 ``` Not tag-gated: content must not wait for a release. The WASM editor ships from `release.yml`; the two are independent. ## Files that carry load ``` site/functions/api/waitlist.ts the only server-side code (Pages Function) site/public/_headers prod response headers, scoped to 3 patterns site/public/_routes.json only /api/* invokes the Function site/wrangler.toml nodejs_compat + pages_build_output_dir site/src/pages/404.astro required — see below ``` Four things here fail **silently** if changed carelessly. Each is asserted by `verify.sh`, and each is asserted because it was a real defect at some point: - **Never widen `_headers` to `/*`.** `../demo/_headers` does exactly that, which is right for the demo and wrong here: a `require-corp` document cannot load the no-COEP YouTube hero iframe, so the landing page must stay un-isolated. - **Keep both URL forms of the Gerber blog post in `_headers`.** Pages serves the trailing-slash form and 308s the bare form to it, and the trailing-slash form is the page's own canonical. Scoping the headers to one form only means search arrivals get a page without `SharedArrayBuffer` and the embedded viewer quietly degrades. That shipped in production for months. - **Never delete `404.astro`.** With no `404.html` in the output, Pages answers every unknown URL with the **homepage at HTTP 200** — a soft 404 that invites indexing junk URLs as the homepage. - **Keep the cross-site form-POST guard** in `waitlist.ts`. Vercel's edge refused those for free; Cloudflare does not, and a cross-site `