Skip to content

fix: dev harness hosted AI via a vite backend proxy, inline AI failure message - #70

Merged
PAMulligan merged 2 commits into
mainfrom
fix/67-dev-harness-backend-proxy
Sep 24, 2026
Merged

PAMulligan merged 2 commits into
mainfrom
fix/67-dev-harness-backend-proxy

Conversation

@PAMulligan

Copy link
Copy Markdown
Contributor

Summary

  • Fixes Dev harness cannot use hosted AI: staging CORS allowlist rejects localhost, failures show only a brief toast #67 — the dev preview harness (dev.html on http://localhost:5173) could not use hosted AI: every backend call went to the staging worker, whose CORS allowlist admits only the extension origin and the staging site, so the browser blocked the response and the "AI suggested" boxes never filled.
  • Root cause confirmed before changing anything: a preflight from Origin: http://localhost:5173 returns 204 with no access-control-allow-origin while the staging-site origin gets one, and the backend's resolveOrigin admits localhost only when ENVIRONMENT === "development".
  • Fix (Option 1 from the issue, no backend change): a /api/backend proxy in vite.config.dev.ts, mirroring the existing /api/anthropic proxy. It forwards only the headers the backend accepts and relays status and body untouched, so the app's error mapping still applies. BACKEND_BASE_URL now resolves through resolveBackendBaseUrl() and points at the proxy only when a development-mode page is served over http(s); the unpacked dev extension (chrome-extension:// pages), the service worker, unit tests and production builds keep their previous targets.
  • Related UX note from the issue: a failed generation now stays visible inside the box (role="alert") until the next attempt or a new suggestion arrives, using the same message as the toast so quota/availability errors from the proxy surface verbatim. H2 headings get it per item, including the slots "Generate All" could not fill. RecommendationBox is unused in the app and was left alone.

Verification

  • New tests: resolveBackendBaseUrl (harness → proxy; extension page, service worker, test and staging modes → staging; production → production) and the proxy middleware driven with fake req/res objects and a stubbed fetch (GET/POST forwarding, header allowlist, error relay, preflight, 502 when the backend is unreachable), plus component tests for the inline message on both boxes.
  • Live in the harness under headless Chrome: analyzed example.com, opened Meta Tags, clicked Regenerate — the AI Suggested Title box filled with a real suggestion via POST /api/backend/ai/generate → 200. With the request aborted, the box showed "Could not reach the AI service." immediately and still 6 s later after the toast was gone.
  • curl through the running harness: /api/backend/health 200, /api/backend/ai/models returns the model list, unknown routes relay staging's 404.
  • 545/545 vitest, tsc --noEmit, eslint . and pnpm build clean.

🤖 Generated with Claude Code

PAMulligan and others added 2 commits September 24, 2026 19:28
The dev preview harness (dev.html on http://localhost:5173) resolved
BACKEND_BASE_URL to the staging worker, whose CORS allowlist admits only
the extension origin and the staging site. The browser blocked every
hosted-AI, license and billing response before the app saw it, so the
"AI suggested" boxes never filled and the only feedback was a brief toast.

Add a /api/backend proxy to vite.config.dev.ts, mirroring the existing
/api/anthropic proxy, and make BACKEND_BASE_URL resolve to it only when a
development-mode page is served over http(s). The unpacked dev extension
(chrome-extension:// pages), the service worker, unit tests and
production builds keep their previous targets. No backend change; the
staging allowlist stays as tight as before.

Refs #67

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
When a generation failed, the "AI suggested" box stayed on its
placeholder and the only feedback was a toast that vanished within
seconds, so a user who looked away saw an empty box and no explanation.

Show the failure inside the box (role="alert") until the next attempt or
a new suggestion arrives, using the same message as the toast so quota
and availability errors from the proxy surface verbatim. H2 headings get
the message per item, including the slots Generate All could not fill.

Refs #67

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@PAMulligan
PAMulligan merged commit 7dff9c8 into main Sep 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dev harness cannot use hosted AI: staging CORS allowlist rejects localhost, failures show only a brief toast

1 participant