const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const webpush = require('web-push'); const ENV_PATH = path.join(__dirname, '..', '.env'); function loadEnv() { const env = {}; if (fs.existsSync(ENV_PATH)) { for (const line of fs.readFileSync(ENV_PATH, 'utf8').split('\n')) { const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/); if (m && !line.trim().startsWith('#')) env[m[1]] = m[2].replace(/^["']|["']$/g, ''); } } return env; } function saveEnv(env) { const lines = []; for (const [k, v] of Object.entries(env)) lines.push(`${k}=${v}`); fs.writeFileSync(ENV_PATH, lines.join('\n') + '\n', 'utf8'); } function ensure(key, generator) { if (process.env[key] || env[key]) return process.env[key] || env[key]; const value = generator(); env[key] = value; saveEnv(env); return value; } const env = loadEnv(); function ensureVapidPair() { if ((process.env.VAPID_PUBLIC_KEY || env.VAPID_PUBLIC_KEY) && (process.env.VAPID_PRIVATE_KEY || env.VAPID_PRIVATE_KEY)) { return { publicKey: process.env.VAPID_PUBLIC_KEY || env.VAPID_PUBLIC_KEY, privateKey: process.env.VAPID_PRIVATE_KEY || env.VAPID_PRIVATE_KEY, }; } const pair = webpush.generateVAPIDKeys(); env.VAPID_PUBLIC_KEY = pair.publicKey; env.VAPID_PRIVATE_KEY = pair.privateKey; saveEnv(env); return pair; } const vapid = ensureVapidPair(); const config = { port: Number(process.env.PORT || env.PORT || 3000), apiKey: process.env.DEEPSEEK_API_KEY || env.DEEPSEEK_API_KEY || '', appPassword: process.env.APP_PASSWORD || env.APP_PASSWORD || '', model: process.env.MODEL || env.MODEL || 'deepseek-v4-flash', thinking: process.env.THINKING || env.THINKING || 'enabled', baseUrl: process.env.DEEPSEEK_BASE_URL || env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com', sessionSecret: ensure('SESSION_SECRET', () => crypto.randomBytes(32).toString('hex')), vapidPublicKey: vapid.publicKey, vapidPrivateKey: vapid.privateKey, }; module.exports = { config };