From b91867e717374cd3d6aec4d78d9b977df38b728f Mon Sep 17 00:00:00 2001 From: Yiannis Date: Wed, 18 Mar 2026 18:21:12 +0200 Subject: [PATCH] fix: complete Stripe key handling for self-hosted and billing safety --- packages/billing/lib/stripe.ts | 6 +++++- packages/server/lib/controllers/v1/getEnvJs.ts | 2 +- packages/types/lib/web/env.ts | 2 +- .../webapp/src/pages/Team/Billing/components/Plans.tsx | 8 +++++++- packages/webapp/src/utils/stripe.ts | 2 +- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/billing/lib/stripe.ts b/packages/billing/lib/stripe.ts index 9a55d9eec8..11a6c34660 100644 --- a/packages/billing/lib/stripe.ts +++ b/packages/billing/lib/stripe.ts @@ -3,7 +3,11 @@ import Stripe from 'stripe'; import { envs } from './envs.js'; export function getStripe() { - return new Stripe(envs.STRIPE_SECRET_KEY!, { + if (!envs.STRIPE_SECRET_KEY) { + throw new Error('STRIPE_SECRET_KEY is required to initialize Stripe'); + } + + return new Stripe(envs.STRIPE_SECRET_KEY, { apiVersion: '2025-05-28.basil', typescript: true, telemetry: false diff --git a/packages/server/lib/controllers/v1/getEnvJs.ts b/packages/server/lib/controllers/v1/getEnvJs.ts index 2d92651a84..2caf22d74d 100644 --- a/packages/server/lib/controllers/v1/getEnvJs.ts +++ b/packages/server/lib/controllers/v1/getEnvJs.ts @@ -28,7 +28,7 @@ export const getEnvJs = asyncWrapper((_, res) => { publicPosthogKey: envs.PUBLIC_POSTHOG_KEY || '', publicPosthogHost: envs.PUBLIC_POSTHOG_HOST || '', publicLogoDevKey: envs.PUBLIC_LOGODEV_KEY || '', - publicStripeKey: envs.PUBLIC_STRIPE_KEY || '', + publicStripeKey: envs.PUBLIC_STRIPE_KEY || undefined, isCloud, isHosted, isEnterprise, diff --git a/packages/types/lib/web/env.ts b/packages/types/lib/web/env.ts index 99604acff3..c86c448beb 100644 --- a/packages/types/lib/web/env.ts +++ b/packages/types/lib/web/env.ts @@ -8,7 +8,7 @@ export interface WindowEnv { publicPosthogKey: string; publicPosthogHost: string; publicLogoDevKey: string; - publicStripeKey: string; + publicStripeKey: string | undefined; isCloud: boolean; isHosted: boolean; isEnterprise: boolean; diff --git a/packages/webapp/src/pages/Team/Billing/components/Plans.tsx b/packages/webapp/src/pages/Team/Billing/components/Plans.tsx index 54c7c76351..5c7083ab5d 100644 --- a/packages/webapp/src/pages/Team/Billing/components/Plans.tsx +++ b/packages/webapp/src/pages/Team/Billing/components/Plans.tsx @@ -242,7 +242,13 @@ const PlanChangeDialog: React.FC<{ if ('paymentIntent' in res.json.data) { res.json.data.paymentIntent; const stripe = await stripePromise; - const result = await stripe!.confirmCardPayment(res.json.data.paymentIntent.client_secret); + if (!stripe) { + setLoading(false); + toast({ title: 'Stripe is not configured for this deployment', variant: 'error' }); + return; + } + + const result = await stripe.confirmCardPayment(res.json.data.paymentIntent.client_secret); if (result.error) { console.error({ error: result.error }); diff --git a/packages/webapp/src/utils/stripe.ts b/packages/webapp/src/utils/stripe.ts index 821d5826ef..ebaf795d58 100644 --- a/packages/webapp/src/utils/stripe.ts +++ b/packages/webapp/src/utils/stripe.ts @@ -3,4 +3,4 @@ import { loadStripe } from '@stripe/stripe-js'; import { globalEnv } from './env'; const stripePublishableKey = globalEnv.publicStripeKey; -export const stripePromise = loadStripe(stripePublishableKey); +export const stripePromise = stripePublishableKey ? loadStripe(stripePublishableKey) : Promise.resolve(null);