import 'dotenv/config' import * as z from 'zod/v4' import { TIMING } from '@music-together/shared' import { readFileSync } from 'node:fs' import { resolve, dirname } from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = dirname(fileURLToPath(import.meta.url)) const rootPkg = JSON.parse(readFileSync(resolve(__dirname, '../../../package.json'), 'utf-8')) const envSchema = z.object({ PORT: z.coerce.number().int().positive().default(3001), CLIENT_URL: z.string().default(''), CORS_ORIGINS: z.string().default(''), IDENTITY_SECRET: z.string().min(16).default('dev-identity-secret-change-me'), IDENTITY_TTL_DAYS: z.coerce.number().int().positive().default(30), REJOIN_TTL_MS: z.coerce.number().int().positive().default(TIMING.ROOM_GRACE_PERIOD_MS), IDENTITY_COOKIE_SECURE: z.enum(['true', 'false']).optional(), IDENTITY_COOKIE_SAME_SITE: z.enum(['lax', 'strict', 'none']).default('lax'), IDENTITY_COOKIE_PARTITIONED: z.enum(['true', 'false']).default('false'), AUTO_FALLBACK_ENABLED: z.enum(['true', 'false']).default('true'), QQ_MUSIC_API_URL: z .string() .trim() .refine((value) => !value || URL.canParse(value), 'QQ_MUSIC_API_URL must be a valid absolute URL') .default(''), QQ_MUSIC_API_KEY: z.string().trim().default(''), DATABASE_URL: z.string().default('file:./data/music-together.db'), SERVER_ADMIN_IDS: z.string().default(''), }) const env = envSchema.parse(process.env) const isProd = process.env.NODE_ENV === 'production' const explicitOrigins = [env.CLIENT_URL, ...env.CORS_ORIGINS.split(',')].map((origin) => origin.trim()).filter(Boolean) export const config = { version: rootPkg.version as string, port: env.PORT, isProd, clientUrl: explicitOrigins[0] ?? 'auto', explicitOrigins, room: { gracePeriodMs: TIMING.ROOM_GRACE_PERIOD_MS, }, player: { nextDebounceMs: TIMING.PLAYER_NEXT_DEBOUNCE_MS, }, identity: { secret: env.IDENTITY_SECRET, ttlDays: env.IDENTITY_TTL_DAYS, cookieSecure: env.IDENTITY_COOKIE_SECURE ? env.IDENTITY_COOKIE_SECURE === 'true' : null, cookieSameSite: env.IDENTITY_COOKIE_SAME_SITE, cookiePartitioned: env.IDENTITY_COOKIE_PARTITIONED === 'true', }, rejoin: { ttlMs: env.REJOIN_TTL_MS, }, autoFallback: { enabled: env.AUTO_FALLBACK_ENABLED === 'true', }, qqMusicApi: { url: env.QQ_MUSIC_API_URL, key: env.QQ_MUSIC_API_KEY, }, database: { url: env.DATABASE_URL, }, serverAdminIds: new Set( env.SERVER_ADMIN_IDS.split(',') .map((id) => id.trim()) .filter(Boolean), ), } as const