feat(visualizer): add layers + fast timeframe switching
This commit is contained in:
@@ -61,7 +61,18 @@ function readProxyBasicAuth(): BasicAuth | undefined {
|
||||
|
||||
const apiReadToken = readApiReadToken();
|
||||
const proxyBasicAuth = readProxyBasicAuth();
|
||||
const apiProxyTarget = process.env.API_PROXY_TARGET || 'http://localhost:8787';
|
||||
const apiProxyTarget =
|
||||
process.env.API_PROXY_TARGET ||
|
||||
process.env.VISUALIZER_PROXY_TARGET ||
|
||||
process.env.TRADE_UI_URL ||
|
||||
process.env.TRADE_VPS_URL ||
|
||||
'https://trade.mpabi.pl';
|
||||
|
||||
function isLocalHost(hostname: string | undefined): boolean {
|
||||
const h = String(hostname || '').trim().toLowerCase();
|
||||
if (!h) return false;
|
||||
return h === 'localhost' || h === '127.0.0.1' || h === '0.0.0.0';
|
||||
}
|
||||
|
||||
function parseUrl(v: string): URL | undefined {
|
||||
try {
|
||||
@@ -71,9 +82,17 @@ function parseUrl(v: string): URL | undefined {
|
||||
}
|
||||
}
|
||||
|
||||
function toOrigin(u: URL | undefined): string | undefined {
|
||||
if (!u) return undefined;
|
||||
return `${u.protocol}//${u.host}`;
|
||||
}
|
||||
|
||||
const apiProxyTargetUrl = parseUrl(apiProxyTarget);
|
||||
const apiProxyOrigin = toOrigin(apiProxyTargetUrl);
|
||||
const apiProxyTargetPath = stripTrailingSlashes(apiProxyTargetUrl?.pathname || '/');
|
||||
const apiProxyTargetEndsWithApi = apiProxyTargetPath.endsWith('/api');
|
||||
const apiProxyIsLocal = isLocalHost(apiProxyTargetUrl?.hostname);
|
||||
const apiProxyForceBearer = process.env.API_PROXY_FORCE_BEARER === '1' || process.env.API_PROXY_USE_READ_TOKEN === '1';
|
||||
|
||||
function inferUiProxyTarget(apiTarget: string): string | undefined {
|
||||
try {
|
||||
@@ -97,7 +116,12 @@ const uiProxyTarget =
|
||||
process.env.AUTH_PROXY_TARGET ||
|
||||
inferUiProxyTarget(apiProxyTarget) ||
|
||||
(apiProxyTargetUrl && apiProxyTargetPath === '/' ? stripTrailingSlashes(apiProxyTargetUrl.toString()) : undefined);
|
||||
const uiProxyOrigin = toOrigin(parseUrl(uiProxyTarget || ''));
|
||||
|
||||
const graphqlProxyTarget = process.env.GRAPHQL_PROXY_TARGET || process.env.HASURA_PROXY_TARGET || uiProxyTarget;
|
||||
const graphqlProxyOrigin = toOrigin(parseUrl(graphqlProxyTarget || ''));
|
||||
const graphqlProxyBasicAuthEnabled =
|
||||
process.env.GRAPHQL_PROXY_BASIC_AUTH === '1' || process.env.HASURA_PROXY_BASIC_AUTH === '1';
|
||||
function applyProxyBasicAuth(proxyReq: any) {
|
||||
if (!proxyBasicAuth) return false;
|
||||
const b64 = Buffer.from(`${proxyBasicAuth.username}:${proxyBasicAuth.password}`, 'utf8').toString('base64');
|
||||
@@ -105,6 +129,12 @@ function applyProxyBasicAuth(proxyReq: any) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function applyProxyOrigin(proxyReq: any, origin: string | undefined) {
|
||||
if (!origin) return;
|
||||
// Some upstreams (notably WS endpoints) validate Origin and may drop the connection when it doesn't match.
|
||||
proxyReq.setHeader('Origin', origin);
|
||||
}
|
||||
|
||||
function rewriteSetCookieForLocalDevHttp(proxyRes: any) {
|
||||
const v = proxyRes?.headers?.['set-cookie'];
|
||||
if (!v) return;
|
||||
@@ -124,13 +154,37 @@ const proxy: Record<string, any> = {
|
||||
rewrite: (p: string) => (apiProxyTargetEndsWithApi ? p.replace(/^\/api/, '') : p),
|
||||
configure: (p: any) => {
|
||||
p.on('proxyReq', (proxyReq: any) => {
|
||||
applyProxyOrigin(proxyReq, apiProxyOrigin);
|
||||
if (applyProxyBasicAuth(proxyReq)) return;
|
||||
if (apiReadToken) proxyReq.setHeader('Authorization', `Bearer ${apiReadToken}`);
|
||||
if ((apiProxyIsLocal || apiProxyForceBearer) && apiReadToken) proxyReq.setHeader('Authorization', `Bearer ${apiReadToken}`);
|
||||
});
|
||||
p.on('proxyReqWs', (proxyReq: any) => {
|
||||
applyProxyOrigin(proxyReq, apiProxyOrigin);
|
||||
applyProxyBasicAuth(proxyReq);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (graphqlProxyTarget) {
|
||||
for (const prefix of ['/graphql', '/graphql-ws']) {
|
||||
proxy[prefix] = {
|
||||
target: graphqlProxyTarget,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
configure: (p: any) => {
|
||||
p.on('proxyReq', (proxyReq: any) => {
|
||||
applyProxyOrigin(proxyReq, graphqlProxyOrigin);
|
||||
if (graphqlProxyBasicAuthEnabled) applyProxyBasicAuth(proxyReq);
|
||||
});
|
||||
p.on('proxyReqWs', (proxyReq: any) => {
|
||||
applyProxyOrigin(proxyReq, graphqlProxyOrigin);
|
||||
if (graphqlProxyBasicAuthEnabled) applyProxyBasicAuth(proxyReq);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
if (uiProxyTarget) {
|
||||
for (const prefix of ['/whoami', '/auth', '/logout']) {
|
||||
proxy[prefix] = {
|
||||
@@ -138,6 +192,7 @@ if (uiProxyTarget) {
|
||||
changeOrigin: true,
|
||||
configure: (p: any) => {
|
||||
p.on('proxyReq', (proxyReq: any) => {
|
||||
applyProxyOrigin(proxyReq, uiProxyOrigin);
|
||||
applyProxyBasicAuth(proxyReq);
|
||||
});
|
||||
p.on('proxyRes', (proxyRes: any) => {
|
||||
@@ -152,7 +207,7 @@ export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
port: 5173,
|
||||
strictPort: true,
|
||||
strictPort: false,
|
||||
proxy,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user