Essential environment variable parsing ^& validation

This commit is contained in:
Xevion
2023-02-23 20:39:23 -06:00
parent daa4a434fc
commit f0c5a21ab5
3 changed files with 68 additions and 0 deletions

18
src/env/schema.mjs vendored Normal file
View File

@@ -0,0 +1,18 @@
// @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({
API_KEY: z.string(),
CRONITOR_ACCOUNT_ID: z.string(),
CRONITOR_JOB_ID: z.string(),
LIFE360_USERNAME: z.string(),
LIFE360_PASSWORD: z.string(),
LIFE360_MEMBER_ID: z.string(),
MAX_DISTANCE: z.coerce.number().positive(),
CENTER_LATITUDE: z.coerce.number().min(-90).max(90),
CENTER_LONGITUDE: z.coerce.number().min(-180).max(180),
});

40
src/env/server.mjs vendored Normal file
View File

@@ -0,0 +1,40 @@
// @ts-check
/**
* 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 { serverSchema } from "./schema.mjs";
import { formatErrors } from "./util.mjs";
const _serverEnv = serverSchema.safeParse({
API_KEY: process.env.API_KEY,
CRONITOR_ACCOUNT_ID: process.env.CRONITOR_ACCOUNT_ID,
CRONITOR_JOB_ID: process.env.CRONITOR_JOB_ID,
LIFE360_USERNAME: process.env.LIFE360_USERNAME,
LIFE360_PASSWORD: process.env.LIFE360_PASSWORD,
LIFE360_MEMBER_ID: process.env.LIFE360_MEMBER_ID,
MAX_DISTANCE: process.env.MAX_DISTANCE,
CENTER_LATITUDE: process.env.CENTER_LATITUDE,
CENTER_LONGITUDE: process.env.CENTER_LONGITUDE,
});
if (_serverEnv.success === false) {
console.error(
"❌ Invalid environment variables:\n",
...formatErrors(_serverEnv.error.format())
);
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);
throw new Error("You are exposing a server-side env-variable");
}
}
export const env = { ..._serverEnv.data };

10
src/env/util.mjs vendored Normal file
View File

@@ -0,0 +1,10 @@
export const formatErrors = (
/** @type {import('zod').ZodFormattedError<Map<string,string>,string>} */
errors,
) =>
Object.entries(errors)
.map(([name, value]) => {
if (value && "_errors" in value)
return `${name}: ${value._errors.join(", ")}\n`;
})
.filter(Boolean);