/// import path from 'node:path' import { exec } from 'node:child_process' import os from 'node:os' import { defineConfig, loadEnv, type Plugin } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' import babel from '@babel/core' import addDataLocator from './plugins/add-data-locator.cjs' function openInIdePlugin(): Plugin { return { name: 'open-in-ide-plugin', apply: 'serve', configureServer(server) { server.middlewares.use((req, res, next) => { const url = req.url?.split('?')[0] if (url === '/api/open-in-ide' && req.method === 'POST') { let body = '' req.on('data', (chunk) => { body += chunk }) req.on('end', () => { try { const { locator } = JSON.parse(body) if (!locator) { res.statusCode = 400 res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({ message: 'Locator is required' })) return } const isWindows = os.platform() === 'win32' const bin = isWindows ? 'antigravity-ide.cmd' : 'antigravity-ide' const cmd = `${bin} -r -g "${locator}"` exec(cmd, (error) => { if (error) { console.error(`[open-in-ide] Error: ${error.message}`) res.statusCode = 500 res.setHeader('Content-Type', 'application/json') res.end( JSON.stringify({ message: 'Failed to open file in IDE', error: error.message, }) ) return } res.statusCode = 200 res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({ success: true })) }) } catch (err) { console.error('[open-in-ide] Error parsing body:', err, 'raw body:', body) res.statusCode = 500 res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({ message: 'Internal server error', error: String(err), rawBody: body })) } }) return } if ( (url === '/api/remote-logs' || url === '/api/remote-network' || url === '/api/dev-storage') && req.method === 'POST' ) { res.statusCode = 200 res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({ ok: true })) return } next() }) }, } } function addDataLocatorPlugin(): Plugin { return { name: 'add-data-locator-plugin', enforce: 'pre', apply: 'serve', transform(code, id) { const cleanId = id.split('?')[0] if (cleanId.includes('node_modules') || !/\.[jt]sx$/.test(cleanId)) { return null } try { const result = babel.transformSync(code, { filename: cleanId, configFile: false, babelrc: false, parserOpts: { plugins: ['jsx', 'typescript'] }, plugins: [addDataLocator], }) if (result?.code) { return { code: result.code, map: result.map } } } catch (err) { console.error('[add-data-locator-plugin] Transform error:', err) } return null }, } } export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), '') /* مقصد بک‌اند برای پراکسیِ dev — همهٔ '/api/*' بدون CORS به این‌جا می‌رود. */ const apiTarget = env.VITE_API_TARGET ?? 'http://localhost:8000' return { plugins: [ openInIdePlugin(), addDataLocatorPlugin(), react(), tailwindcss(), ], resolve: { alias: { '@': path.resolve(__dirname, './src') }, }, server: { proxy: { '/api': { target: apiTarget, changeOrigin: true, }, }, }, test: { environment: 'node', include: ['src/**/*.test.{ts,tsx}'], }, } })