@@ -55,32 +55,28 @@ Where your server and client schemas live for typesafe environment variables
5555``` js
5656// @ts-check
5757import { validateEnvironmentVariables } from " next-validenv" ;
58+
5859import { z } from " zod" ;
5960
6061/**
61- * Specify your server-side environment variables schema here.
62- * This way you can ensure the app isn't built with invalid env vars.
63- * @template {ReturnType<typeof z.object>} T
64- * @param {T} serverSchema
65- * @returns {z.infer<T>}
62+ * Specify your environment variables schema here.
63+ * This way, you can ensure the app isn't built with invalid environment variables.
64+ * By default, environment variables are only available in the Node.js environment, meaning they won't be exposed to the browser. In order to expose a variable to the browser you have to prefix the variable with NEXT_PUBLIC_.
65+ * -> Don't use any Zod .transform() methods in the schema (will cause `implicitly has type 'any'` error) <-
6666 */
67- export const serverSchema = z .object ({
67+ export const schema = z .object ({
6868 NODE_ENV : z .enum ([" development" , " test" , " production" ]),
6969});
7070
7171/**
72- * Specify your client-side environment variables schema here.
73- * This way you can ensure the app isn't built with invalid env vars.
74- * To expose them to the client, prefix them with `NEXT_PUBLIC_`.
75- * @template {ReturnType<typeof z.object>} T
76- * @param {T} serverSchema
77- * @returns {z.infer<T>}
72+ * Environment variable declarations based on the schema help structure your environment variables programmatically.
73+ * @type {{ [k in keyof z.infer<typeof schema>]: z.infer<typeof schema>[k] | undefined }}
7874 */
79- export const clientSchema = z . object ( {
80- // NEXT_PUBLIC_TEST: z.string() ,
81- }) ;
75+ export const env = {
76+ NODE_ENV : process . env . NODE_ENV ,
77+ };
8278
83- export const env = validateEnvironmentVariables (serverSchema, clientSchema );
79+ validateEnvironmentVariables (schema, env );
8480```
8581
8682### Update ~~ ` next.config.js ` ~~ to ` next.config.mjs `
@@ -100,7 +96,7 @@ const config = {
10096export default config ;
10197```
10298
103- ### Create ` environment .d.ts`
99+ ### Create ` env .d.ts`
104100
105101``` js
106102import { env } from " ./env.mjs" ;
@@ -161,141 +157,52 @@ Where your server and client schemas live for typesafe environment variables
161157import { z } from " zod" ;
162158
163159/**
164- * Specify your server-side environment variables schema here.
165- * This way you can ensure the app isn't built with invalid env vars.
166- * @template {ReturnType<typeof z.object>} T
167- * @param {T} serverSchema
168- * @returns {z.infer<T>}
160+ * Specify your environment variables schema here.
161+ * This way, you can ensure the app isn't built with invalid environment variables.
162+ * By default, environment variables are only available in the Node.js environment, meaning they won't be exposed to the browser. In order to expose a variable to the browser you have to prefix the variable with NEXT_PUBLIC_.
163+ * -> Don't use any Zod .transform() methods in the schema (will cause `implicitly has type 'any'` error) <-
169164 */
170- export const serverSchema = z .object ({
165+ export const schema = z .object ({
171166 NODE_ENV : z .enum ([" development" , " test" , " production" ]),
172167});
173168
174169/**
175- * Specify your client-side environment variables schema here.
176- * This way you can ensure the app isn't built with invalid env vars.
177- * To expose them to the client, prefix them with `NEXT_PUBLIC_`.
178- * @template {ReturnType<typeof z.object>} T
179- * @param {T} serverSchema
180- * @returns {z.infer<T>}
170+ * Environment variable declarations based on the schema help structure your environment variables programmatically.
171+ * @type {{ [k in keyof z.infer<typeof schema>]: z.infer<typeof schema>[k] | undefined }}
181172 */
182- export const clientSchema = z . object ( {
183- // NEXT_PUBLIC_TEST: z.string() ,
184- }) ;
173+ export const env = {
174+ NODE_ENV : process . env . NODE_ENV ,
175+ };
185176
186177/**
187178 * --------------------------------
188179 * --------------------------------
189- * DON'T TOUCH ANYTHING BELOW THIS LINE (UNLESS YOU KNOW WHAT YOU'RE DOING)
180+ * Next-ValidEnv Manual Implementation
190181 * --------------------------------
191182 * --------------------------------
192183 */
193184
194- // maps through zod schema keys and returns an object with the safeParse values from process.env[key]
195- export const mapEnvironmentVariablesToObject = (
196- /** @type {ReturnType<typeof z.object>} */ schema
197- ) => {
198- /** @type {{ [key: string]: string | undefined; }} */
199- let env = {};
200-
201- Object .keys (schema .shape ).forEach ((key ) => (env[key] = process .env [key]));
202-
203- return schema .safeParse (env);
204- };
205-
206185export const formatZodErrors = (
207- /** @type {import('zod') .ZodFormattedError<Map<string,string>,string>} */ errors
186+ /** @type z .ZodFormattedError<Map<string, string>, string> */ errors
208187) =>
209188 Object .entries (errors)
210189 .map (([name , value ]) => {
211190 if (value && " _errors" in value)
212191 return ` ${ name} : ${ value ._errors .join (" , " )} \n ` ;
192+
193+ return ;
213194 })
214195 .filter (Boolean );
215196
216- export const formatErrors = (/** @type {(string | undefined)[]} */ errors) =>
217- errors .map ((name ) => ` ${ name} \n ` );
218-
219- /**
220- * @function
221- * @template {ReturnType<typeof z.object>} T
222- * @template {ReturnType<typeof z.object>} K
223- * @param {T} serverSchema
224- * @param {K} clientSchema
225- * @returns {z.infer<T> & z.infer<K>}
226- */
227- export const validateEnvironmentVariables = (serverSchema , clientSchema ) => {
228- let serverEnv = mapEnvironmentVariablesToObject (serverSchema);
229- let clientEnv = mapEnvironmentVariablesToObject (clientSchema);
230-
231- // holds not set environment variable errors for both client and server
232- /** @type {(string | undefined)[]} */ let invalidEnvErrors = [];
233-
234- if (! serverEnv .success ) {
235- invalidEnvErrors = [
236- ... invalidEnvErrors,
237- ... formatZodErrors (serverEnv .error .format ()),
238- ];
239- }
240-
241- if (! clientEnv .success ) {
242- invalidEnvErrors = [
243- ... invalidEnvErrors,
244- ... formatZodErrors (clientEnv .error .format ()),
245- ];
246- }
197+ const safeParsedEnv = schema .safeParse (env);
247198
248- // if one or more environment variables are not set, throw an error
249- if (! serverEnv .success || ! clientEnv .success ) {
250- console .error (" ❌ Invalid environment variables:\n " , ... invalidEnvErrors);
251- throw new Error (" Invalid environment variables" );
252- }
253-
254- // holds server environment variables errors that are exposed to the client
255- /** @type {(string | undefined)[]} */ let exposedServerEnvErrors = [];
256-
257- for (let key of Object .keys (serverEnv .data )) {
258- if (key .startsWith (" NEXT_PUBLIC_" )) {
259- exposedServerEnvErrors = [... exposedServerEnvErrors, key];
260- }
261- }
262-
263- // if one or more server environment variables are exposed to the client, throw an error
264- if (exposedServerEnvErrors .length > 0 ) {
265- console .error (
266- " ❌ You are exposing the following server-side environment variables to the client:\n " ,
267- ... formatErrors (exposedServerEnvErrors)
268- );
269- throw new Error (
270- " You are exposing the following server-side environment variables to the client"
271- );
272- }
273-
274- // holds client environment variables errors that are not exposed to the client
275- /** @type {(string | undefined)[]} */ let notExposedClientEnvErrors = [];
276-
277- for (let key of Object .keys (clientEnv .data )) {
278- if (! key .startsWith (" NEXT_PUBLIC_" )) {
279- notExposedClientEnvErrors = [... notExposedClientEnvErrors, key];
280- }
281- }
282-
283- // if one or more client environment variables are not exposed to the client, throw an error
284- if (notExposedClientEnvErrors .length > 0 ) {
285- console .error (
286- " ❌ All client-side environment variables must begin with 'NEXT_PUBLIC_', you are not exposing the following:\n " ,
287- ... formatErrors (notExposedClientEnvErrors)
288- );
289- throw new Error (
290- " All client-side environment variables must begin with 'NEXT_PUBLIC_', you are not exposing the following:"
291- );
292- }
293-
294- // return both client and server environment variables
295- return { ... serverEnv .data , ... clientEnv .data };
296- };
297-
298- export const env = validateEnvironmentVariables (serverSchema, clientSchema);
199+ if (! safeParsedEnv .success ) {
200+ console .error (
201+ " ❌ Invalid environment variables:\n " ,
202+ ... formatZodErrors (safeParsedEnv .error .format ())
203+ );
204+ throw new Error (" Invalid environment variables" );
205+ }
299206```
300207
301208### Update ~~ ` next.config.js ` ~~ to ` next.config.mjs `
@@ -315,7 +222,7 @@ const config = {
315222export default config ;
316223```
317224
318- ### Create ` environment .d.ts`
225+ ### Create ` env .d.ts`
319226
320227``` js
321228import { env } from " ./env.mjs" ;
0 commit comments