import 'dotenv/config'; import { z } from 'zod'; const optional = z .string() .optional() .transform((v) => (v ? v : undefined)); const schema = z.object({ NODE_ENV: z.string().default('development'), DATABASE_URL: z.string().default('postgres://musicshare:musicshare@localhost:5447/musicshare'), REDIS_URL: z.string().default('redis://localhost:6380'), PORT: z.coerce.number().default(4000), WEB_URL: z.string().default('http://localhost:3737'), API_PUBLIC_URL: z.string().default('http://127.0.0.1:4000'), COOKIE_SECURE: z .string() .default('false') .transform((v) => v === 'true'), TOKEN_ENCRYPTION_KEY: z .string() .refine((v) => Buffer.from(v, 'base64').length === 32, 'TOKEN_ENCRYPTION_KEY must be 32 bytes, base64-encoded'), SPOTIFY_CLIENT_ID: optional, SPOTIFY_CLIENT_SECRET: optional, LASTFM_API_KEY: optional, /** Enables "Sign in with Last.fm" (web auth). Without it, users type their username. */ LASTFM_SHARED_SECRET: optional, ODESLI_API_KEY: optional, /** Apple Music (MusicKit): Team ID, MusicKit key ID, and the key's .p8 contents (newlines may be written as \n). */ APPLE_TEAM_ID: optional, APPLE_MUSICKIT_KEY_ID: optional, APPLE_MUSICKIT_PRIVATE_KEY: optional, /** Identifies this app to Plex. Keep it stable: changing it invalidates users' Plex authorizations. */ PLEX_CLIENT_ID: z.string().default('musicshare-dev'), /** * Allow Jellyfin/Plex server URLs on private networks. Only enable for local * dev or self-hosting: in a hosted deployment it lets users make the server * request internal addresses (SSRF). */ ALLOW_PRIVATE_SERVER_URLS: z .string() .default('false') .transform((v) => v === 'true'), }); export const env = schema.parse(process.env); export const spotifyConfigured = Boolean(env.SPOTIFY_CLIENT_ID && env.SPOTIFY_CLIENT_SECRET); export const appleMusicConfigured = Boolean(env.APPLE_TEAM_ID && env.APPLE_MUSICKIT_KEY_ID && env.APPLE_MUSICKIT_PRIVATE_KEY);