diff --git a/src/components/Bars.tsx b/src/components/Bars.tsx index 8eff784..11b57bc 100644 --- a/src/components/Bars.tsx +++ b/src/components/Bars.tsx @@ -16,6 +16,7 @@ import { RecentCommits } from "./RecentCommits"; import { ActivityHeatmap } from "./ActivityHeatmap"; import { DarkModeToggle } from "./DarkModeToggle"; import { SkeletonBox, SkeletonText } from "./SkeletonLoader"; +import { env } from "~/env/client"; interface GitCommit { sha: string; @@ -384,7 +385,10 @@ export function LeftBar() {

- Freno.dev + + {env.VITE_DOMAIN.split("://")[1].charAt(0).toUpperCase() + + env.VITE_DOMAIN.split("://")[1].slice(1)} +

diff --git a/src/env/client.ts b/src/env/client.ts new file mode 100644 index 0000000..e9972b0 --- /dev/null +++ b/src/env/client.ts @@ -0,0 +1,104 @@ +import { z } from "zod"; + +const clientEnvSchema = z.object({ + // Client-side environment variables (VITE_ prefixed) + VITE_DOMAIN: z.string().min(1), + VITE_AWS_BUCKET_STRING: z.string().min(1), + VITE_GOOGLE_CLIENT_ID: z.string().min(1), + VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE: z.string().min(1), + VITE_GITHUB_CLIENT_ID: z.string().min(1), + VITE_WEBSOCKET: z.string().min(1) +}); + +// Type inference +export type ClientEnv = z.infer; + +// Validation function for client-side with detailed error messages +export const validateClientEnv = ( + envVars: Record +): ClientEnv => { + try { + return clientEnvSchema.parse(envVars); + } catch (error) { + if (error instanceof z.ZodError) { + const formattedErrors = error.format(); + const missingVars = Object.entries(formattedErrors) + .filter( + ([key, value]) => + key !== "_errors" && + typeof value === "object" && + value._errors?.length > 0 && + value._errors[0] === "Required" + ) + .map(([key, _]) => key); + + const invalidVars = Object.entries(formattedErrors) + .filter( + ([key, value]) => + key !== "_errors" && + typeof value === "object" && + value._errors?.length > 0 && + value._errors[0] !== "Required" + ) + .map(([key, value]) => ({ + key, + error: value._errors[0] + })); + + let errorMessage = "Client environment validation failed:\n"; + + if (missingVars.length > 0) { + errorMessage += `Missing required variables: ${missingVars.join(", ")}\n`; + } + + if (invalidVars.length > 0) { + errorMessage += "Invalid values:\n"; + invalidVars.forEach(({ key, error }) => { + errorMessage += ` ${key}: ${error}\n`; + }); + } + + console.error(errorMessage); + throw new Error(errorMessage); + } + console.error( + "Client environment validation failed with unknown error:", + error + ); + throw new Error("Client environment validation failed with unknown error"); + } +}; + +// Validate and export environment variables directly +// This happens once at module load time on the client +const validateAndExportEnv = (): ClientEnv => { + try { + const validated = validateClientEnv(import.meta.env); + console.log("✅ Client environment validation successful"); + return validated; + } catch (error) { + console.error("❌ Client environment validation failed:", error); + throw error; + } +}; + +export const env = validateAndExportEnv(); + +// Helper function to check if a variable is missing +export const isMissingEnvVar = (varName: string): boolean => { + return !import.meta.env[varName] || import.meta.env[varName]?.trim() === ""; +}; + +// Helper function to get all missing client environment variables +export const getMissingEnvVars = (): string[] => { + const requiredClientVars = [ + "VITE_DOMAIN", + "VITE_AWS_BUCKET_STRING", + "VITE_GOOGLE_CLIENT_ID", + "VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE", + "VITE_GITHUB_CLIENT_ID", + "VITE_WEBSOCKET" + ]; + + return requiredClientVars.filter((varName) => isMissingEnvVar(varName)); +};