import { defineConfig, loadEnv } from 'vite'; import react from '@vitejs/plugin-react'; import { VitePWA } from 'vite-plugin-pwa'; import path from 'path'; // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); const aiBaseUrl = (env.VITE_OPENAI_BASE_URL || 'https://openrouter.ai/api/v1').replace(/\/$/, ''); let proxyTarget = 'https://openrouter.ai'; let proxyPathPrefix = '/api/v1'; try { const parsed = new URL(aiBaseUrl); proxyTarget = parsed.origin; proxyPathPrefix = parsed.pathname.replace(/\/$/, '') || ''; } catch { // keep defaults } return { plugins: [ react(), VitePWA({ registerType: 'autoUpdate', includeAssets: [ 'favicon.ico', 'favicon-16x16.png', 'favicon-32x32.png', 'apple-touch-icon.png', 'logo/mainlogo.png', ], manifest: { name: 'نویا', short_name: 'نویا', description: 'پلتفرم روان‌شناسی و سلامت روان نویا', theme_color: '#0a0f1d', background_color: '#070b14', display: 'standalone', orientation: 'portrait', scope: '/', start_url: '/', dir: 'rtl', lang: 'fa', icons: [ { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' } ] }, workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'] } }) ], resolve: { alias: { '@': path.resolve(__dirname, './src') } }, server: { proxy: { // Browser → Vite → local Backend (avoids CORS on localhost) '/api/backend': { target: 'http://localhost:3001', changeOrigin: true, rewrite: (requestPath) => requestPath.replace(/^\/api\/backend/, ''), }, // Browser → Vite → OpenRouter (avoids CORS / blocked browser routes on LAN) '/api/ai': { target: proxyTarget, changeOrigin: true, secure: true, timeout: 180_000, proxyTimeout: 180_000, rewrite: (requestPath) => requestPath.replace(/^\/api\/ai/, proxyPathPrefix), configure: (proxy) => { proxy.on('proxyReq', (proxyReq, req) => { // Avoid forwarding browser Origin; set stable OpenRouter attribution headers proxyReq.removeHeader('origin'); proxyReq.setHeader('HTTP-Referer', 'https://novya.app'); proxyReq.setHeader('X-Title', 'Novya'); if (!proxyReq.getHeader('user-agent')) { proxyReq.setHeader( 'User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36' ); } // NOTE: do NOT use import.meta.env here — undefined in Node proxy callbacks console.log('[AI Proxy]', req.method, req.url, '→', proxyTarget + proxyPathPrefix); }); proxy.on('error', (err, _req, res) => { console.error('[AI Proxy] Error:', err.message); const socket = res as { headersSent?: boolean; writeHead?: (code: number, headers: Record) => void; end?: (body: string) => void; }; if (socket && !socket.headersSent && typeof socket.writeHead === 'function') { socket.writeHead(502, { 'Content-Type': 'application/json' }); socket.end?.( JSON.stringify({ error: 'AI proxy error', message: String(err.message || err) }) ); } }); } } } } }; });