From 2048783bd26f7f0522357a3ab1e74e6f560a221c Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sun, 24 Jul 2022 17:41:06 +0200 Subject: [PATCH] fix: clarify some comments and rename some files in env (#245) * fix: clarify some comments and rename some files in env * fix: filenames in installer * fix: import in next.config * fix: import after filechange * fix: forgotten rename Co-authored-by: Shoubhit Dash --- src/installers/envVars.ts | 12 +++---- template/addons/env/auth-prisma-schema.mjs | 33 +++++++++++++++++++ template/addons/env/auth-schema.mjs | 31 +++++++++++++++++ template/addons/env/env-auth.mjs | 25 -------------- template/addons/env/env-prisma-auth.mjs | 27 --------------- template/addons/env/env-prisma.mjs | 23 ------------- template/addons/env/prisma-schema.mjs | 29 ++++++++++++++++ .../addons/next-auth/api-handler-prisma.ts | 2 +- template/addons/next-auth/api-handler.ts | 2 +- template/addons/prisma/client.ts | 2 +- template/base/next.config.mjs | 2 +- .../src/env/{client-env.mjs => client.mjs} | 7 ++-- template/base/src/env/env-schema.mjs | 22 ------------- template/base/src/env/schema.mjs | 28 ++++++++++++++++ .../src/env/{server-env.mjs => server.mjs} | 9 +++-- 15 files changed, 142 insertions(+), 112 deletions(-) create mode 100644 template/addons/env/auth-prisma-schema.mjs create mode 100644 template/addons/env/auth-schema.mjs delete mode 100644 template/addons/env/env-auth.mjs delete mode 100644 template/addons/env/env-prisma-auth.mjs delete mode 100644 template/addons/env/env-prisma.mjs create mode 100644 template/addons/env/prisma-schema.mjs rename template/base/src/env/{client-env.mjs => client.mjs} (79%) delete mode 100644 template/base/src/env/env-schema.mjs create mode 100644 template/base/src/env/schema.mjs rename template/base/src/env/{server-env.mjs => server.mjs} (72%) diff --git a/src/installers/envVars.ts b/src/installers/envVars.ts index a00ccc0f0f..592ae63f46 100644 --- a/src/installers/envVars.ts +++ b/src/installers/envVars.ts @@ -16,26 +16,26 @@ export const envVariablesInstaller: Installer = async ({ switch (true) { case usingAuth && usingPrisma: - envFile = "env-prisma-auth.mjs"; + envFile = "auth-prisma-schema.mjs"; break; case usingAuth: - envFile = "env-auth.mjs"; + envFile = "auth-schema.mjs"; break; case usingPrisma: - envFile = "env-prisma.mjs"; + envFile = "prisma-schema.mjs"; break; } if (!envFile) return; const envSchemaSrc = path.join(envAssetDir, envFile); - const envSchemaDest = path.join(projectDir, "src/env/env-schema.mjs"); + const envSchemaDest = path.join(projectDir, "src/env/schema.mjs"); - const envExample = path.join(projectDir, ".env-example"); + const envExampleSrc = path.join(projectDir, ".env-example"); const envDest = path.join(projectDir, ".env"); await Promise.all([ fs.copy(envSchemaSrc, envSchemaDest, { overwrite: true }), - fs.rename(envExample, envDest), + fs.rename(envExampleSrc, envDest), ]); }; diff --git a/template/addons/env/auth-prisma-schema.mjs b/template/addons/env/auth-prisma-schema.mjs new file mode 100644 index 0000000000..5871158c2c --- /dev/null +++ b/template/addons/env/auth-prisma-schema.mjs @@ -0,0 +1,33 @@ +// @ts-check +import { z } from "zod"; + +/** + * Specify your server-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + */ +export const serverSchema = z.object({ + DATABASE_URL: z.string().url(), + NODE_ENV: z.enum(["development", "test", "production"]), + NEXTAUTH_SECRET: z.string(), + NEXTAUTH_URL: z.string().url(), + DISCORD_CLIENT_ID: z.string(), + DISCORD_CLIENT_SECRET: z.string(), +}); + +/** + * Specify your client-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + * To expose them to the client, prefix them with `NEXT_PUBLIC_`. + */ +export const clientSchema = z.object({ + // NEXT_PUBLIC_BAR: z.string(), +}); + +/** + * You can't destruct `process.env` as a regular object, so you have to do + * it manually here. This is because Next.js evaluates this at build time, + * and only used environment variables are included in the build. + */ +export const clientEnv = { + // NEXT_PUBLIC_BAR: process.env.NEXT_PUBLIC_BAR, +}; diff --git a/template/addons/env/auth-schema.mjs b/template/addons/env/auth-schema.mjs new file mode 100644 index 0000000000..173f7a7b0d --- /dev/null +++ b/template/addons/env/auth-schema.mjs @@ -0,0 +1,31 @@ +// @ts-check +import { z } from "zod"; + +/** + * Specify your server-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + */ +export const serverSchema = z.object({ + NEXTAUTH_SECRET: z.string(), + NEXTAUTH_URL: z.string().url(), + DISCORD_CLIENT_ID: z.string(), + DISCORD_CLIENT_SECRET: z.string(), +}); + +/** + * Specify your client-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + * To expose them to the client, prefix them with `NEXT_PUBLIC_`. + */ +export const clientSchema = z.object({ + // NEXT_PUBLIC_BAR: z.string(), +}); + +/** + * You can't destruct `process.env` as a regular object, so you have to do + * it manually here. This is because Next.js evaluates this at build time, + * and only used environment variables are included in the build. + */ +export const clientEnv = { + // NEXT_PUBLIC_BAR: process.env.NEXT_PUBLIC_BAR, +}; diff --git a/template/addons/env/env-auth.mjs b/template/addons/env/env-auth.mjs deleted file mode 100644 index 0d01f1f054..0000000000 --- a/template/addons/env/env-auth.mjs +++ /dev/null @@ -1,25 +0,0 @@ -// @ts-check -import { z } from "zod"; - -export const serverEnvSchema = z.object({ - NEXTAUTH_SECRET: z.string(), - NEXTAUTH_URL: z.string().url(), - DISCORD_CLIENT_ID: z.string(), - DISCORD_CLIENT_SECRET: z.string(), -}); - -export const clientEnvSchema = z.object({ - // Specify your client-side environment variables schema here - // Be sure to name your environment variables with the prefix "NEXT_PUBLIC_" -}); - -/** - * Next.js client-side environment variables are evaluated at build time, - * so only environment variables actually used will be included. - * - * Define your client-side environment variables in this object to - * be able to use autocompletion and destructuring in your code. - */ -export const clientEnv = { - // NEXT_PUBLIC_FOO: process.env.NEXT_PUBLIC_FOO, -}; diff --git a/template/addons/env/env-prisma-auth.mjs b/template/addons/env/env-prisma-auth.mjs deleted file mode 100644 index 97bc1d1e13..0000000000 --- a/template/addons/env/env-prisma-auth.mjs +++ /dev/null @@ -1,27 +0,0 @@ -// @ts-check -import { z } from "zod"; - -export const serverEnvSchema = z.object({ - DATABASE_URL: z.string().url(), - NODE_ENV: z.enum(["development", "test", "production"]), - NEXTAUTH_SECRET: z.string(), - NEXTAUTH_URL: z.string().url(), - DISCORD_CLIENT_ID: z.string(), - DISCORD_CLIENT_SECRET: z.string(), -}); - -export const clientEnvSchema = z.object({ - // Specify your client-side environment variables schema here - // Be sure to name your environment variables with the prefix "NEXT_PUBLIC_" -}); - -/** - * Next.js client-side environment variables are evaluated at build time, - * so only environment variables actually used will be included. - * - * Define your client-side environment variables in this object to - * be able to use autocompletion and destructuring in your code. - */ -export const clientEnv = { - // NEXT_PUBLIC_FOO: process.env.NEXT_PUBLIC_FOO, -}; diff --git a/template/addons/env/env-prisma.mjs b/template/addons/env/env-prisma.mjs deleted file mode 100644 index 4f6c3290c3..0000000000 --- a/template/addons/env/env-prisma.mjs +++ /dev/null @@ -1,23 +0,0 @@ -// @ts-check -import { z } from "zod"; - -export const serverEnvSchema = z.object({ - DATABASE_URL: z.string().url(), - NODE_ENV: z.enum(["development", "test", "production"]), -}); - -export const clientEnvSchema = z.object({ - // Specify your client-side environment variables schema here - // Be sure to name your environment variables with the prefix "NEXT_PUBLIC_" -}); - -/** - * Next.js client-side environment variables are evaluated at build time, - * so only environment variables actually used will be included. - * - * Define your client-side environment variables in this object to - * be able to use autocompletion and destructuring in your code. - */ -export const clientEnv = { - // NEXT_PUBLIC_FOO: process.env.NEXT_PUBLIC_FOO, -}; diff --git a/template/addons/env/prisma-schema.mjs b/template/addons/env/prisma-schema.mjs new file mode 100644 index 0000000000..4927fa4c4d --- /dev/null +++ b/template/addons/env/prisma-schema.mjs @@ -0,0 +1,29 @@ +// @ts-check +import { z } from "zod"; + +/** + * Specify your server-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + */ +export const serverSchema = z.object({ + DATABASE_URL: z.string().url(), + NODE_ENV: z.enum(["development", "test", "production"]), +}); + +/** + * Specify your client-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + * To expose them to the client, prefix them with `NEXT_PUBLIC_`. + */ +export const clientSchema = z.object({ + // NEXT_PUBLIC_BAR: z.string(), +}); + +/** + * You can't destruct `process.env` as a regular object, so you have to do + * it manually here. This is because Next.js evaluates this at build time, + * and only used environment variables are included in the build. + */ +export const clientEnv = { + // NEXT_PUBLIC_BAR: process.env.NEXT_PUBLIC_BAR, +}; diff --git a/template/addons/next-auth/api-handler-prisma.ts b/template/addons/next-auth/api-handler-prisma.ts index d0aa1ac5c3..bcead858bb 100644 --- a/template/addons/next-auth/api-handler-prisma.ts +++ b/template/addons/next-auth/api-handler-prisma.ts @@ -4,7 +4,7 @@ import DiscordProvider from "next-auth/providers/discord"; // Prisma adapter for NextAuth, optional and can be removed import { PrismaAdapter } from "@next-auth/prisma-adapter"; import { prisma } from "../../../server/db/client"; -import { env } from "../../../env/server-env.mjs"; +import { env } from "../../../env/server.mjs"; export const authOptions: NextAuthOptions = { // Include user.id on session diff --git a/template/addons/next-auth/api-handler.ts b/template/addons/next-auth/api-handler.ts index 4df761d3dc..2d1d2dab47 100644 --- a/template/addons/next-auth/api-handler.ts +++ b/template/addons/next-auth/api-handler.ts @@ -1,6 +1,6 @@ import NextAuth, { type NextAuthOptions } from "next-auth"; import DiscordProvider from "next-auth/providers/discord"; -import { env } from "../../../env/server-env.mjs"; +import { env } from "../../../env/server.mjs"; export const authOptions: NextAuthOptions = { // Include user.id on session diff --git a/template/addons/prisma/client.ts b/template/addons/prisma/client.ts index 55b1b5bcad..da43a335e2 100644 --- a/template/addons/prisma/client.ts +++ b/template/addons/prisma/client.ts @@ -1,6 +1,6 @@ // src/server/db/client.ts import { PrismaClient } from "@prisma/client"; -import { env } from "../../env/server-env.mjs"; +import { env } from "../../env/server.mjs"; declare global { var prisma: PrismaClient | undefined; diff --git a/template/base/next.config.mjs b/template/base/next.config.mjs index 87fd7a0c4f..0e4a215b88 100644 --- a/template/base/next.config.mjs +++ b/template/base/next.config.mjs @@ -1,4 +1,4 @@ -import { env } from "./src/env/server-env.mjs"; +import { env } from "./src/env/server.mjs"; /** * Don't be scared of the generics here. diff --git a/template/base/src/env/client-env.mjs b/template/base/src/env/client.mjs similarity index 79% rename from template/base/src/env/client-env.mjs rename to template/base/src/env/client.mjs index d2bc2d15b6..8fd8a9ac1b 100644 --- a/template/base/src/env/client-env.mjs +++ b/template/base/src/env/client.mjs @@ -1,7 +1,7 @@ // @ts-check -import { clientEnv, clientEnvSchema } from "./env-schema.mjs"; +import { clientEnv, clientSchema } from "./schema.mjs"; -const _clientEnv = clientEnvSchema.safeParse(clientEnv); +const _clientEnv = clientSchema.safeParse(clientEnv); export const formatErrors = ( /** @type {import('zod').ZodFormattedError,string>} */ @@ -22,6 +22,9 @@ if (!_clientEnv.success) { throw new Error("Invalid environment variables"); } +/** + * Validate that client-side environment variables are exposed to the client. + */ for (let key of Object.keys(_clientEnv.data)) { if (!key.startsWith("NEXT_PUBLIC_")) { console.warn("❌ Invalid public environment variable name:", key); diff --git a/template/base/src/env/env-schema.mjs b/template/base/src/env/env-schema.mjs deleted file mode 100644 index c2089eb417..0000000000 --- a/template/base/src/env/env-schema.mjs +++ /dev/null @@ -1,22 +0,0 @@ -// @ts-check -import { z } from "zod"; - -export const serverEnvSchema = z.object({ - // Specify your environment variables schema here -}); - -export const clientEnvSchema = z.object({ - // Specify your client-side environment variables schema here - // Be sure to name your environment variables with the prefix "NEXT_PUBLIC_" -}); - -/** - * Next.js client-side environment variables are evaluated at build time, - * so only environment variables actually used will be included. - * - * Define your client-side environment variables in this object to - * be able to use autocompletion and destructuring in your code. - */ -export const clientEnv = { - // NEXT_PUBLIC_FOO: process.env.NEXT_PUBLIC_FOO, -}; diff --git a/template/base/src/env/schema.mjs b/template/base/src/env/schema.mjs new file mode 100644 index 0000000000..cd2d6c1a30 --- /dev/null +++ b/template/base/src/env/schema.mjs @@ -0,0 +1,28 @@ +// @ts-check +import { z } from "zod"; + +/** + * Specify your server-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + */ +export const serverSchema = z.object({ + // FOO: z.string(), +}); + +/** + * Specify your client-side environment variables schema here. + * This way you can ensure the app isn't built with invalid env vars. + * To expose them to the client, prefix them with `NEXT_PUBLIC_`. + */ +export const clientSchema = z.object({ + // NEXT_PUBLIC_BAR: z.string(), +}); + +/** + * You can't destruct `process.env` as a regular object, so you have to do + * it manually here. This is because Next.js evaluates this at build time, + * and only used environment variables are included in the build. + */ +export const clientEnv = { + // NEXT_PUBLIC_BAR: process.env.NEXT_PUBLIC_BAR, +}; diff --git a/template/base/src/env/server-env.mjs b/template/base/src/env/server.mjs similarity index 72% rename from template/base/src/env/server-env.mjs rename to template/base/src/env/server.mjs index 12846f4f75..16433b0ed8 100644 --- a/template/base/src/env/server-env.mjs +++ b/template/base/src/env/server.mjs @@ -3,10 +3,10 @@ * This file is included in `/next.config.mjs` which ensures the app isn't built with invalid env vars. * It has to be a `.mjs`-file to be imported there. */ -import { serverEnvSchema } from "./env-schema.mjs"; -import { env as clientEnv, formatErrors } from "./client-env.mjs"; +import { serverSchema } from "./schema.mjs"; +import { env as clientEnv, formatErrors } from "./client.mjs"; -const _serverEnv = serverEnvSchema.safeParse(process.env); +const _serverEnv = serverSchema.safeParse(process.env); if (!_serverEnv.success) { console.error( @@ -16,6 +16,9 @@ if (!_serverEnv.success) { throw new Error("Invalid environment variables"); } +/** + * Validate that server-side environment variables are not exposed to the client. + */ for (let key of Object.keys(_serverEnv.data)) { if (key.startsWith("NEXT_PUBLIC_")) { console.warn("❌ You are exposing a server-side env-variable:", key);