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.
This commit is contained in:
6
.github/workflows/workflow.yml
vendored
6
.github/workflows/workflow.yml
vendored
@@ -9,6 +9,12 @@ jobs:
|
|||||||
name: ʦ TypeScript
|
name: ʦ TypeScript
|
||||||
timeout-minutes: 8
|
timeout-minutes: 8
|
||||||
runs-on: ubuntu-latest
|
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:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { DatabaseWebhookHandlerService } from '@kit/database-webhooks';
|
|||||||
const webhooksSecret = z
|
const webhooksSecret = z
|
||||||
.string({
|
.string({
|
||||||
description: `The secret used to verify the webhook signature`,
|
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)
|
.min(1)
|
||||||
.parse(process.env.SUPABASE_DB_WEBHOOK_SECRET);
|
.parse(process.env.SUPABASE_DB_WEBHOOK_SECRET);
|
||||||
|
|||||||
@@ -7,22 +7,30 @@ const AppConfigSchema = z
|
|||||||
name: z
|
name: z
|
||||||
.string({
|
.string({
|
||||||
description: `This is the name of your SaaS. Ex. "Makerkit"`,
|
description: `This is the name of your SaaS. Ex. "Makerkit"`,
|
||||||
|
required_error: `Please provide the variable NEXT_PUBLIC_PRODUCT_NAME`,
|
||||||
})
|
})
|
||||||
.min(1),
|
.min(1),
|
||||||
title: z
|
title: z
|
||||||
.string({
|
.string({
|
||||||
description: `This is the default title tag of your SaaS.`,
|
description: `This is the default title tag of your SaaS.`,
|
||||||
|
required_error: `Please provide the variable NEXT_PUBLIC_SITE_TITLE`,
|
||||||
})
|
})
|
||||||
.min(1),
|
.min(1),
|
||||||
description: z.string({
|
description: z.string({
|
||||||
description: `This is the default description of your SaaS.`,
|
description: `This is the default description of your SaaS.`,
|
||||||
|
required_error: `Please provide the variable NEXT_PUBLIC_SITE_DESCRIPTION`,
|
||||||
}),
|
}),
|
||||||
url: z.string().url({
|
url: z
|
||||||
|
.string({
|
||||||
|
required_error: `Please provide the variable NEXT_PUBLIC_SITE_URL`,
|
||||||
|
})
|
||||||
|
.url({
|
||||||
message: `Please provide a valid URL. Example: 'https://example.com'`,
|
message: `Please provide a valid URL. Example: 'https://example.com'`,
|
||||||
}),
|
}),
|
||||||
locale: z
|
locale: z
|
||||||
.string({
|
.string({
|
||||||
description: `This is the default locale of your SaaS.`,
|
description: `This is the default locale of your SaaS.`,
|
||||||
|
required_error: `Please provide the variable NEXT_PUBLIC_DEFAULT_LOCALE`,
|
||||||
})
|
})
|
||||||
.default('en'),
|
.default('en'),
|
||||||
theme: z.enum(['light', 'dark', 'system']),
|
theme: z.enum(['light', 'dark', 'system']),
|
||||||
|
|||||||
@@ -1,17 +1,43 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
const FeatureFlagsSchema = z.object({
|
const FeatureFlagsSchema = z.object({
|
||||||
enableThemeToggle: z.boolean(),
|
enableThemeToggle: z.boolean({
|
||||||
enableAccountDeletion: z.boolean(),
|
description: 'Enable theme toggle in the user interface.',
|
||||||
enableTeamDeletion: z.boolean(),
|
required_error: 'Provide the variable NEXT_PUBLIC_ENABLE_THEME_TOGGLE',
|
||||||
enableTeamAccounts: z.boolean(),
|
}),
|
||||||
enableTeamCreation: z.boolean(),
|
enableAccountDeletion: z.boolean({
|
||||||
enablePersonalAccountBilling: z.boolean(),
|
description: 'Enable account deletion.',
|
||||||
enableTeamAccountBilling: z.boolean(),
|
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({
|
const featuresFlagConfig = FeatureFlagsSchema.parse({
|
||||||
enableThemeToggle: true,
|
enableThemeToggle: getBoolean(
|
||||||
|
process.env.NEXT_PUBLIC_ENABLE_THEME_TOGGLE,
|
||||||
|
true,
|
||||||
|
),
|
||||||
enableAccountDeletion: getBoolean(
|
enableAccountDeletion: getBoolean(
|
||||||
process.env.NEXT_PUBLIC_ENABLE_ACCOUNT_DELETION,
|
process.env.NEXT_PUBLIC_ENABLE_ACCOUNT_DELETION,
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -2,8 +2,16 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
export const StripeServerEnvSchema = z
|
export const StripeServerEnvSchema = z
|
||||||
.object({
|
.object({
|
||||||
secretKey: z.string().min(1),
|
secretKey: z
|
||||||
webhooksSecret: z.string().min(1),
|
.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(
|
.refine(
|
||||||
(schema) => {
|
(schema) => {
|
||||||
|
|||||||
@@ -76,8 +76,16 @@ export async function deletePersonalAccountAction(formData: FormData) {
|
|||||||
function getEmailSettingsFromEnvironment() {
|
function getEmailSettingsFromEnvironment() {
|
||||||
return z
|
return z
|
||||||
.object({
|
.object({
|
||||||
fromEmail: z.string().email(),
|
fromEmail: z
|
||||||
productName: z.string().min(1),
|
.string({
|
||||||
|
required_error: 'Provide the variable EMAIL_SENDER',
|
||||||
|
})
|
||||||
|
.email(),
|
||||||
|
productName: z
|
||||||
|
.string({
|
||||||
|
required_error: 'Provide the variable NEXT_PUBLIC_PRODUCT_NAME',
|
||||||
|
})
|
||||||
|
.min(1),
|
||||||
})
|
})
|
||||||
.parse({
|
.parse({
|
||||||
fromEmail: process.env.EMAIL_SENDER,
|
fromEmail: process.env.EMAIL_SENDER,
|
||||||
|
|||||||
@@ -1,49 +1,28 @@
|
|||||||
|
import 'server-only';
|
||||||
|
|
||||||
import { z } from 'zod';
|
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({
|
export const SmtpConfigSchema = z.object({
|
||||||
user: z.string({
|
user: z.string({
|
||||||
description:
|
description:
|
||||||
'This is the email account to send emails from. This is specific to the email provider.',
|
'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({
|
pass: z.string({
|
||||||
description: 'This is the password for the email account',
|
description: 'This is the password for the email account',
|
||||||
|
required_error: `Please provide the variable EMAIL_PASSWORD`,
|
||||||
}),
|
}),
|
||||||
host: z.string({
|
host: z.string({
|
||||||
description: 'This is the SMTP host for the email provider',
|
description: 'This is the SMTP host for the email provider',
|
||||||
|
required_error: `Please provide the variable EMAIL_HOST`,
|
||||||
}),
|
}),
|
||||||
port: z.number({
|
port: z.number({
|
||||||
description:
|
description:
|
||||||
'This is the port for the email provider. Normally 587 or 465.',
|
'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(),
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user