Files
trade-frontend/apps/visualizer/vite.config.ts

159 lines
4.9 KiB
TypeScript

import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
const DIR = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(DIR, '../..');
type BasicAuth = { username: string; password: string };
function stripTrailingSlashes(p: string): string {
const out = p.replace(/\/+$/, '');
return out || '/';
}
function readApiReadToken(): string | undefined {
if (process.env.API_READ_TOKEN) return process.env.API_READ_TOKEN;
const p = path.join(ROOT, 'tokens', 'read.json');
if (!fs.existsSync(p)) return undefined;
try {
const raw = fs.readFileSync(p, 'utf8');
const json = JSON.parse(raw) as { token?: string };
return json?.token ? String(json.token) : undefined;
} catch {
return undefined;
}
}
function parseBasicAuth(value: string | undefined): BasicAuth | undefined {
const raw = String(value || '').trim();
if (!raw) return undefined;
const idx = raw.indexOf(':');
if (idx <= 0) return undefined;
const username = raw.slice(0, idx).trim();
const password = raw.slice(idx + 1);
if (!username || !password) return undefined;
return { username, password };
}
function readProxyBasicAuth(): BasicAuth | undefined {
const fromEnv = parseBasicAuth(process.env.API_PROXY_BASIC_AUTH);
if (fromEnv) return fromEnv;
const fileRaw = String(process.env.API_PROXY_BASIC_AUTH_FILE || '').trim();
if (!fileRaw) return undefined;
const p = path.isAbsolute(fileRaw) ? fileRaw : path.join(ROOT, fileRaw);
if (!fs.existsSync(p)) return undefined;
try {
const raw = fs.readFileSync(p, 'utf8');
const json = JSON.parse(raw) as { username?: string; password?: string };
const username = typeof json?.username === 'string' ? json.username.trim() : '';
const password = typeof json?.password === 'string' ? json.password : '';
if (!username || !password) return undefined;
return { username, password };
} catch {
return undefined;
}
}
const apiReadToken = readApiReadToken();
const proxyBasicAuth = readProxyBasicAuth();
const apiProxyTarget = process.env.API_PROXY_TARGET || 'http://localhost:8787';
function parseUrl(v: string): URL | undefined {
try {
return new URL(v);
} catch {
return undefined;
}
}
const apiProxyTargetUrl = parseUrl(apiProxyTarget);
const apiProxyTargetPath = stripTrailingSlashes(apiProxyTargetUrl?.pathname || '/');
const apiProxyTargetEndsWithApi = apiProxyTargetPath.endsWith('/api');
function inferUiProxyTarget(apiTarget: string): string | undefined {
try {
const u = new URL(apiTarget);
const p = stripTrailingSlashes(u.pathname || '/');
if (!p.endsWith('/api')) return undefined;
const basePath = p.slice(0, -'/api'.length) || '/';
u.pathname = basePath;
u.search = '';
u.hash = '';
const out = u.toString();
return out.endsWith('/') ? out.slice(0, -1) : out;
} catch {
return undefined;
}
}
const uiProxyTarget =
process.env.FRONTEND_PROXY_TARGET ||
process.env.UI_PROXY_TARGET ||
process.env.AUTH_PROXY_TARGET ||
inferUiProxyTarget(apiProxyTarget) ||
(apiProxyTargetUrl && apiProxyTargetPath === '/' ? stripTrailingSlashes(apiProxyTargetUrl.toString()) : undefined);
function applyProxyBasicAuth(proxyReq: any) {
if (!proxyBasicAuth) return false;
const b64 = Buffer.from(`${proxyBasicAuth.username}:${proxyBasicAuth.password}`, 'utf8').toString('base64');
proxyReq.setHeader('Authorization', `Basic ${b64}`);
return true;
}
function rewriteSetCookieForLocalDevHttp(proxyRes: any) {
const v = proxyRes?.headers?.['set-cookie'];
if (!v) return;
const rewrite = (cookie: string) => {
let out = cookie.replace(/;\s*secure\b/gi, '');
out = out.replace(/;\s*domain=[^;]+/gi, '');
out = out.replace(/;\s*samesite=none\b/gi, '; SameSite=Lax');
return out;
};
proxyRes.headers['set-cookie'] = Array.isArray(v) ? v.map(rewrite) : rewrite(String(v));
}
const proxy: Record<string, any> = {
'/api': {
target: apiProxyTarget,
changeOrigin: true,
rewrite: (p: string) => (apiProxyTargetEndsWithApi ? p.replace(/^\/api/, '') : p),
configure: (p: any) => {
p.on('proxyReq', (proxyReq: any) => {
if (applyProxyBasicAuth(proxyReq)) return;
if (apiReadToken) proxyReq.setHeader('Authorization', `Bearer ${apiReadToken}`);
});
},
},
};
if (uiProxyTarget) {
for (const prefix of ['/whoami', '/auth', '/logout']) {
proxy[prefix] = {
target: uiProxyTarget,
changeOrigin: true,
configure: (p: any) => {
p.on('proxyReq', (proxyReq: any) => {
applyProxyBasicAuth(proxyReq);
});
p.on('proxyRes', (proxyRes: any) => {
rewriteSetCookieForLocalDevHttp(proxyRes);
});
},
};
}
}
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
strictPort: true,
proxy,
},
});