Zod validated config for security and ease of getting started

This commit is contained in:
Kalle
2026-06-15 14:12:15 +03:00
parent 215243e071
commit 75179e5077
46 changed files with 386 additions and 275 deletions

View File

@@ -1,4 +1,5 @@
import type { z } from "zod";
import { ServerConfig } from "~/config.server";
import { STAFF_DISCORD_IDS } from "~/features/admin/admin-constants";
import * as UserRepository from "~/features/user-page/UserRepository.server";
import { dateToDatabaseTimestamp } from "~/utils/dates";
@@ -52,7 +53,7 @@ const DEFAULT_RETRY_AFTER_SECONDS = 10;
const MAX_RETRY_AFTER_SECONDS = 60;
async function fetchPatronData(urlToFetch: string) {
if (!process.env.PATREON_ACCESS_TOKEN) {
if (!ServerConfig.patreon.accessToken) {
throw new Error("Missing Patreon access token");
}
@@ -61,7 +62,7 @@ async function fetchPatronData(urlToFetch: string) {
urlToFetch,
{
headers: {
Authorization: `Bearer ${process.env.PATREON_ACCESS_TOKEN}`,
Authorization: `Bearer ${ServerConfig.patreon.accessToken}`,
},
},
30_000,

View File

@@ -1,6 +1,6 @@
import { logger } from "~/utils/logger";
import { getToken, purgeCachedToken } from "./token";
import { getTwitchEnvVars } from "./utils";
import { getTwitchEnvVars } from "./utils.server";
const MAX_RATE_LIMIT_RETRIES = 5;
const MAX_RATE_LIMIT_WAIT_MS = 60_000;

View File

@@ -1,7 +1,7 @@
import { cachified } from "@epic-web/cachified";
import { cache } from "~/utils/cache.server";
import { tokenResponseSchema } from "./schemas";
import { getTwitchEnvVars } from "./utils";
import { getTwitchEnvVars } from "./utils.server";
async function getFreshToken() {
const { TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET } = getTwitchEnvVars();

View File

@@ -0,0 +1,16 @@
import { ServerConfig } from "~/config.server";
import invariant from "~/utils/invariant";
export const hasTwitchEnvVars = () =>
Boolean(ServerConfig.twitch.clientId && ServerConfig.twitch.clientSecret);
export const getTwitchEnvVars = () => {
const { clientId, clientSecret } = ServerConfig.twitch;
invariant(clientId, "Missing TWITCH_CLIENT_ID env var, showing no streams");
invariant(
clientSecret,
"Missing TWITCH_CLIENT_SECRET env var, showing no streams",
);
return { TWITCH_CLIENT_ID: clientId, TWITCH_CLIENT_SECRET: clientSecret };
};

View File

@@ -1,23 +1,2 @@
import invariant from "~/utils/invariant";
export const hasTwitchEnvVars = () => {
const { TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET } = process.env;
return Boolean(TWITCH_CLIENT_ID && TWITCH_CLIENT_SECRET);
};
export const getTwitchEnvVars = () => {
const { TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET } = process.env;
invariant(
TWITCH_CLIENT_ID,
"Missing TWITCH_CLIENT_ID env var, showing no streams",
);
invariant(
TWITCH_CLIENT_SECRET,
"Missing TWITCH_CLIENT_SECRET env var, showing no streams",
);
return { TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET };
};
export const twitchThumbnailUrlToSrc = (url: string) =>
url.replace("{width}", "640").replace("{height}", "360");