From a549d2d08f0140a04d95c17c377c6219ddcd0bda Mon Sep 17 00:00:00 2001 From: giancarlo Date: Sun, 14 Apr 2024 18:50:09 +0800 Subject: [PATCH] Add detailed error messages for missing environment variables The commit adds detailed error messages for missing environment variables across different configuration files. It updates the zod schema validations in different files, such as feature-flags.config.ts, personal-accounts-server-actions.ts, and others to provide more informative error messages when environment variables are not provided. --- .github/workflows/workflow.yml | 6 +++ apps/web/app/api/db/webhook/route.ts | 1 + apps/web/config/app.config.ts | 14 +++++-- apps/web/config/feature-flags.config.ts | 42 +++++++++++++++---- .../src/schema/stripe-server-env.schema.ts | 12 +++++- .../personal-accounts-server-actions.ts | 12 +++++- .../mailers/src/schema/smtp-config.schema.ts | 41 +++++------------- 7 files changed, 82 insertions(+), 46 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 8904b795d..ceb14ebe6 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -9,6 +9,12 @@ jobs: name: ĘŚ TypeScript timeout-minutes: 8 runs-on: ubuntu-latest + env: + SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} + SUPABASE_DB_WEBHOOK_SECRET: ${{ secrets.SUPABASE_DB_WEBHOOK_SECRET }} + STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }} + STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }} + steps: - uses: actions/checkout@v4 with: diff --git a/apps/web/app/api/db/webhook/route.ts b/apps/web/app/api/db/webhook/route.ts index 21967e4cf..c1ad71794 100644 --- a/apps/web/app/api/db/webhook/route.ts +++ b/apps/web/app/api/db/webhook/route.ts @@ -5,6 +5,7 @@ import { DatabaseWebhookHandlerService } from '@kit/database-webhooks'; const webhooksSecret = z .string({ description: `The secret used to verify the webhook signature`, + required_error: `Provide the variable SUPABASE_DB_WEBHOOK_SECRET. This is used to authenticate the webhook event from Supabase.`, }) .min(1) .parse(process.env.SUPABASE_DB_WEBHOOK_SECRET); diff --git a/apps/web/config/app.config.ts b/apps/web/config/app.config.ts index 36718223f..15057a1db 100644 --- a/apps/web/config/app.config.ts +++ b/apps/web/config/app.config.ts @@ -7,22 +7,30 @@ const AppConfigSchema = z name: z .string({ description: `This is the name of your SaaS. Ex. "Makerkit"`, + required_error: `Please provide the variable NEXT_PUBLIC_PRODUCT_NAME`, }) .min(1), title: z .string({ description: `This is the default title tag of your SaaS.`, + required_error: `Please provide the variable NEXT_PUBLIC_SITE_TITLE`, }) .min(1), description: z.string({ description: `This is the default description of your SaaS.`, + required_error: `Please provide the variable NEXT_PUBLIC_SITE_DESCRIPTION`, }), - url: z.string().url({ - message: `Please provide a valid URL. Example: 'https://example.com'`, - }), + url: z + .string({ + required_error: `Please provide the variable NEXT_PUBLIC_SITE_URL`, + }) + .url({ + message: `Please provide a valid URL. Example: 'https://example.com'`, + }), locale: z .string({ description: `This is the default locale of your SaaS.`, + required_error: `Please provide the variable NEXT_PUBLIC_DEFAULT_LOCALE`, }) .default('en'), theme: z.enum(['light', 'dark', 'system']), diff --git a/apps/web/config/feature-flags.config.ts b/apps/web/config/feature-flags.config.ts index bc2bc2acd..544632888 100644 --- a/apps/web/config/feature-flags.config.ts +++ b/apps/web/config/feature-flags.config.ts @@ -1,17 +1,43 @@ import { z } from 'zod'; const FeatureFlagsSchema = z.object({ - enableThemeToggle: z.boolean(), - enableAccountDeletion: z.boolean(), - enableTeamDeletion: z.boolean(), - enableTeamAccounts: z.boolean(), - enableTeamCreation: z.boolean(), - enablePersonalAccountBilling: z.boolean(), - enableTeamAccountBilling: z.boolean(), + enableThemeToggle: z.boolean({ + description: 'Enable theme toggle in the user interface.', + required_error: 'Provide the variable NEXT_PUBLIC_ENABLE_THEME_TOGGLE', + }), + enableAccountDeletion: z.boolean({ + description: 'Enable account deletion.', + required_error: 'Provide the variable NEXT_PUBLIC_ENABLE_ACCOUNT_DELETION', + }), + enableTeamDeletion: z.boolean({ + description: 'Enable team deletion.', + required_error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_DELETION', + }), + enableTeamAccounts: z.boolean({ + description: 'Enable team accounts.', + required_error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS', + }), + enableTeamCreation: z.boolean({ + description: 'Enable team creation.', + required_error: 'Provide the variable NEXT_PUBLIC_ENABLE_TEAMS_CREATION', + }), + enablePersonalAccountBilling: z.boolean({ + description: 'Enable personal account billing.', + required_error: + 'Provide the variable NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING', + }), + enableTeamAccountBilling: z.boolean({ + description: 'Enable team account billing.', + required_error: + 'Provide the variable NEXT_PUBLIC_ENABLE_ORGANIZATION_BILLING', + }), }); const featuresFlagConfig = FeatureFlagsSchema.parse({ - enableThemeToggle: true, + enableThemeToggle: getBoolean( + process.env.NEXT_PUBLIC_ENABLE_THEME_TOGGLE, + true, + ), enableAccountDeletion: getBoolean( process.env.NEXT_PUBLIC_ENABLE_ACCOUNT_DELETION, false, diff --git a/packages/billing/stripe/src/schema/stripe-server-env.schema.ts b/packages/billing/stripe/src/schema/stripe-server-env.schema.ts index d5e2d4d1f..274cec468 100644 --- a/packages/billing/stripe/src/schema/stripe-server-env.schema.ts +++ b/packages/billing/stripe/src/schema/stripe-server-env.schema.ts @@ -2,8 +2,16 @@ import { z } from 'zod'; export const StripeServerEnvSchema = z .object({ - secretKey: z.string().min(1), - webhooksSecret: z.string().min(1), + secretKey: z + .string({ + required_error: `Please provide the variable STRIPE_SECRET_KEY`, + }) + .min(1), + webhooksSecret: z + .string({ + required_error: `Please provide the variable STRIPE_WEBHOOK_SECRET`, + }) + .min(1), }) .refine( (schema) => { diff --git a/packages/features/accounts/src/server/personal-accounts-server-actions.ts b/packages/features/accounts/src/server/personal-accounts-server-actions.ts index 5a6523429..81dded878 100644 --- a/packages/features/accounts/src/server/personal-accounts-server-actions.ts +++ b/packages/features/accounts/src/server/personal-accounts-server-actions.ts @@ -76,8 +76,16 @@ export async function deletePersonalAccountAction(formData: FormData) { function getEmailSettingsFromEnvironment() { return z .object({ - fromEmail: z.string().email(), - productName: z.string().min(1), + fromEmail: z + .string({ + required_error: 'Provide the variable EMAIL_SENDER', + }) + .email(), + productName: z + .string({ + required_error: 'Provide the variable NEXT_PUBLIC_PRODUCT_NAME', + }) + .min(1), }) .parse({ fromEmail: process.env.EMAIL_SENDER, diff --git a/packages/mailers/src/schema/smtp-config.schema.ts b/packages/mailers/src/schema/smtp-config.schema.ts index 55a97aeb9..9a5094972 100644 --- a/packages/mailers/src/schema/smtp-config.schema.ts +++ b/packages/mailers/src/schema/smtp-config.schema.ts @@ -1,49 +1,28 @@ +import 'server-only'; + import { z } from 'zod'; -/* -const user = process.env.EMAIL_USER; - const pass = process.env.EMAIL_PASSWORD; - const host = process.env.EMAIL_HOST; - const port = Number(process.env.EMAIL_PORT); - const secure = process.env.EMAIL_TLS !== 'false'; - - // validate that we have all the required appConfig - if (!user || !pass || !host || !port) { - throw new Error( - `Missing email configuration. Please add the following environment variables: - EMAIL_USER - EMAIL_PASSWORD - EMAIL_HOST - EMAIL_PORT - `, - ); - } - - return { - host, - port, - secure, - auth: { - user, - pass, - }, - }; - */ - export const SmtpConfigSchema = z.object({ user: z.string({ description: 'This is the email account to send emails from. This is specific to the email provider.', + required_error: `Please provide the variable EMAIL_USER`, }), pass: z.string({ description: 'This is the password for the email account', + required_error: `Please provide the variable EMAIL_PASSWORD`, }), host: z.string({ description: 'This is the SMTP host for the email provider', + required_error: `Please provide the variable EMAIL_HOST`, }), port: z.number({ description: 'This is the port for the email provider. Normally 587 or 465.', + required_error: `Please provide the variable EMAIL_PORT`, + }), + secure: z.boolean({ + description: 'This is whether the connection is secure or not', + required_error: `Please provide the variable EMAIL_TLS`, }), - secure: z.boolean(), });