Skip to content

Commit 5d6b589

Browse files
committed
feat: implement environment variable validation using zod
1 parent 30a7a1d commit 5d6b589

File tree

6 files changed

+46
-17
lines changed

6 files changed

+46
-17
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ RYBBIT_ANALYTICS_URL=
5050

5151
> [!NOTE]
5252
> - To get the Spotify API credentials, you need to create a Spotify Developer account and create a new application. After creating the application, you will get the client ID and client secret. Don't forget to set the redirect URL to `https://YOUR_DOMAIN/api/spotify/callback` where `YOUR_DOMAIN` is the domain where you are hosting the website.
53-
> - To get the Spotify refresh token, after you have set the client ID, client secret, and redirect URL, skip this step and start the server **in development mode** with **pnpm run dev**. The server will automatically start at `http://localhost:3000`. Visit `http://localhost:3000/api/spotify` and log in with your Spotify account. After logging in, you will be redirected to `http://localhost:3000/api/spotify/callback`. The refresh token will be displayed on the page. Copy the refresh token and paste it in the `.env` file. After pasting the refresh token, restart the server. With this implementation, every 1 hour the server will automatically get a new access token using the refresh token and display your recently played tracks on the website. If you want to get rid of "recently played tracks" functionality, you can just use empty .env file.
53+
> - To get the Spotify refresh token, after you have set the client ID, client secret, and redirect URL, skip this step and start the server **in development mode** with **pnpm run dev**. The server will automatically start at `http://localhost:3000`. Visit `http://localhost:3000/api/spotify` and log in with your Spotify account. After logging in, you will be redirected to `http://localhost:3000/api/spotify/callback`. The refresh token will be displayed on the page. Copy the refresh token and paste it in the `.env` file. After pasting the refresh token, restart the server. With this implementation, every 1 hour the server will automatically get a new access token using the refresh token and display your recently played tracks on the website. If you want to get rid of "recently played tracks" functionality, you can just use empty values for `SPOTIFY_CLIENT_ID`, `SPOTIFY_CLIENT_SECRET`, `SPOTIFY_REDIRECT_URL`, and `SPOTIFY_REFRESH_TOKEN` in the `.env` file.
5454
> - I'm using [Rybbit](https://www.rybbit.io) for analytics. You can create an account and get the site ID and URL from there. If you don't want to use Rybbit, you can just leave the `RYBBIT_ANALYTICS_SITE_ID` and `RYBBIT_ANALYTICS_URL` fields empty in the `.env` file. We don't support any other analytics providers at the moment.
5555
5656
6. Start the server:

instrumentation.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import validateEnvironmentVariables from '@/utils/validateEnvironmentVariables';
2+
3+
export function register() {
4+
validateEnvironmentVariables();
5+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"react-icons": "^5.3.0",
4343
"react-syntax-highlighter": "^15.6.1",
4444
"react-use": "^17.5.1",
45-
"tailwind-merge": "^2.5.4"
45+
"tailwind-merge": "^2.5.4",
46+
"zod": "^3.24.4"
4647
},
4748
"devDependencies": {
4849
"@commitlint/cli": "^19.5.0",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

types/global.d.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

utils/validateEnvironmentVariables.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { z } from 'zod';
2+
3+
const envVariables = z.object({
4+
NODE_ENV: z.enum(['development', 'production']),
5+
SPOTIFY_CLIENT_ID: z.string().optional(),
6+
SPOTIFY_CLIENT_SECRET: z.string().optional(),
7+
SPOTIFY_REDIRECT_URL: z.string().url().optional(),
8+
SPOTIFY_REFRESH_TOKEN: z.string().optional(),
9+
RYBBIT_ANALYTICS_SITE_ID: z.string().optional(),
10+
RYBBIT_ANALYTICS_URL: z.string().url().optional()
11+
});
12+
13+
export default function validateEnvironmentVariables() {
14+
const parsedEnv = envVariables.safeParse(process.env);
15+
16+
if (!parsedEnv.success) {
17+
console.error('Invalid environment variables:');
18+
console.error(parsedEnv.error.format());
19+
20+
throw new Error('Invalid environment variables');
21+
}
22+
}
23+
24+
declare global {
25+
// eslint-disable-next-line @typescript-eslint/no-namespace
26+
namespace NodeJS {
27+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
28+
interface ProcessEnv extends z.infer<typeof envVariables> { }
29+
}
30+
}

0 commit comments

Comments
 (0)