File size: 2,587 Bytes
00a912e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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