@
All checks were successful
Deploy to Production / deploy (push) Successful in 1m25s

fix(billing): correct Stripe API version + harden checkout; clarify wizard secrets

- Stripe apiVersion was pinned to 2025-10-29.acacia, but stripe@22 is built
  for 2026-04-22.dahlia — where ui_mode embedded_page exists. The mismatch
  made the embedded checkout create call fail/hang, surfacing in the browser
  as an opaque CORS error (CF returns a 5xx without our ACAO header). Pin to
  dahlia + add a 20s client timeout so any failure returns a readable 502.
- new-server wizard: step 1 now warns not to paste API keys into the prompt;
  the credentials section (which already collects each secret in its own
  encrypted field) is relabelled and its empty state invites adding one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
Marco Sadjadi
2026-05-31 12:08:05 +02:00
parent 1349dc1dc0
commit 4687c8be52
2 changed files with 25 additions and 7 deletions

View File

@@ -10,9 +10,20 @@ import { getRedis } from './redis.js';
*/
export const stripe: Stripe | null = config.STRIPE_SECRET_KEY
? new Stripe(config.STRIPE_SECRET_KEY, {
// biome-ignore lint/suspicious/noExplicitAny: SDK type lags behind real API version strings
apiVersion: '2025-10-29.acacia' as any,
// Must match the version the installed SDK (stripe@22) is built against —
// its types expose ui_mode: 'embedded_page', which only exists from this
// version on. Pinning the older '2025-10-29.acacia' made Stripe reject the
// embedded checkout create call (acacia still used ui_mode: 'embedded').
apiVersion: '2026-04-22.dahlia',
typescript: true,
// Fail fast + visibly. Without a tight timeout, a wedged Stripe call (bad
// version, egress hiccup) hangs past Cloudflare's ~100s edge limit, and
// CF returns its own 5xx WITHOUT our CORS headers — which surfaces in the
// browser as an opaque "No Access-Control-Allow-Origin" error instead of
// the real failure. 20s keeps us well inside the edge limit so the handler
// returns a proper 502 (with CORS) the client can actually read.
timeout: 20_000,
maxNetworkRetries: 2,
})
: null;