Files
musicshare/apps/api/src/env.ts
T
chrisandClaude Opus 5.5 68ec5a8d99 Slim song cards with an expand arrow, and lyrics
Feed and profile cards now show one slim line (small artwork, title,
artist, Open button) with the progress bar and reactions. The arrow
opens the rest: album, your other services, Share, and lyrics.

Lyrics come from LRCLIB (open source; LRCLIB_URL can point at a
self-hosted copy, or be empty to turn lyrics off). The server looks each
song up once and caches it, including misses (retried after a week).
Timed lyrics follow along with the song; otherwise the first lines show
with "All lyrics".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:19:56 -04:00

62 lines
2.5 KiB
TypeScript

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,
/** Lyrics come from LRCLIB (open source, self-hostable). Point this at your own instance, or set it empty to turn lyrics off. */
LRCLIB_URL: z
.string()
.default('https://lrclib.net')
.transform((v) => v.replace(/\/+$/, '')),
/** 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).
*/
/** Outgoing email (password resets). Without SMTP_HOST, emails are only logged. */
SMTP_HOST: optional,
SMTP_PORT: z.coerce.number().default(465),
SMTP_USER: optional,
SMTP_PASSWORD: optional,
MAIL_FROM: z.string().default('musicshare <app@musicshare.binarygnome.com>'),
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);
export const mailConfigured = Boolean(env.SMTP_HOST);