Files
icons/src/env.mjs
2023-02-17 03:07:53 -06:00

82 lines
2.9 KiB
JavaScript

/* eslint-disable @typescript-eslint/ban-ts-comment */
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.
*/
const server = z.object({
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_`.
*/
const client = z.object({
NEXT_PUBLIC_APP_URL: z.string().transform(url => {
// Add a HTTPS url prefix automatically, for vercel.
if (!(url.startsWith("http://") || url.startsWith("https://")))
return `https://${url}`;
return url;
})
// NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
});
/**
* You can't destruct `process.env` as a regular object in the Next.js
* edge runtimes (e.g. middlewares) or client-side so we need to destruct manually.
* @type {Record<keyof z.infer<typeof server> | keyof z.infer<typeof client>, string | undefined>}
*/
const processEnv = {
NODE_ENV: process.env.NODE_ENV,
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_VERCEL_URL ?? process.env.NEXT_PUBLIC_APP_URL
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
};
// Don't touch the part below
// --------------------------
const merged = server.merge(client);
/** @type z.infer<merged>
* @ts-ignore - can't type this properly in jsdoc */
let env = process.env;
if (!!process.env.SKIP_ENV_VALIDATION == false) {
const isServer = typeof window === "undefined";
const parsed = isServer
? merged.safeParse(processEnv) // on server we can validate all env vars
: client.safeParse(processEnv); // on client we can only validate the ones that are exposed
if (parsed.success === false) {
console.error(
"❌ Invalid environment variables:",
parsed.error.flatten().fieldErrors,
);
throw new Error("Invalid environment variables");
}
/** @type z.infer<merged>
* @ts-ignore - can't type this properly in jsdoc */
env = new Proxy(parsed.data, {
get(target, prop) {
if (typeof prop !== "string") return undefined;
// Throw a descriptive error if a server-side env var is accessed on the client
// Otherwise it would just be returning `undefined` and be annoying to debug
if (!isServer && !prop.startsWith("NEXT_PUBLIC_"))
throw new Error(
process.env.NODE_ENV === "production"
? "❌ Attempted to access a server-side environment variable on the client"
: `❌ Attempted to access server-side environment variable '${prop}' on the client`,
);
/* @ts-ignore - can't type this properly in jsdoc */
return target[prop];
},
});
}
export {env};