diff --git a/apps/client/src/features/acadenice/database-view/services/bridge-client.ts b/apps/client/src/features/acadenice/database-view/services/bridge-client.ts index e0ef267a..3d2d4fc5 100644 --- a/apps/client/src/features/acadenice/database-view/services/bridge-client.ts +++ b/apps/client/src/features/acadenice/database-view/services/bridge-client.ts @@ -17,17 +17,16 @@ import axios, { AxiosInstance } from "axios"; -/** Resolved bridge base URL: per-instance override > env var > default. */ +/** Resolved bridge base URL: per-instance override > env var > same-origin proxy default. + * + * In dev, the Vite server proxies `/bridge/*` to `http://localhost:4000/*` (see vite.config.ts). + * Same-origin = the auth cookie is sent automatically without CORS gymnastics. + * In prod, set VITE_BRIDGE_URL at build time to an absolute URL behind your reverse proxy + * (or keep `/bridge` and proxy server-side). + */ export function resolveBridgeUrl(bridgeUrlOverride?: string | null): string { - // Vite exposes import.meta.env at build time. The double cast is required - // because ImportMeta has no index signature in TypeScript's strict mode, - // but at runtime Vite replaces the env values. const metaEnv = (import.meta as unknown as { env?: { VITE_BRIDGE_URL?: string } }).env; - return ( - bridgeUrlOverride ?? - metaEnv?.VITE_BRIDGE_URL ?? - "http://localhost:4000" - ); + return bridgeUrlOverride ?? metaEnv?.VITE_BRIDGE_URL ?? "/bridge"; } /** Attempt to read the auth token from JS-accessible cookie or jotai storage. */ @@ -58,7 +57,11 @@ export function createBridgeClient(bridgeUrl: string): AxiosInstance { }); instance.interceptors.request.use((config) => { - const token = readTokenFromCookie(); + // Priority: cookie token (prod) > VITE_BRIDGE_TOKEN env (dev fallback) + const cookieToken = readTokenFromCookie(); + const metaEnv = (import.meta as unknown as { env?: { VITE_BRIDGE_TOKEN?: string } }).env; + const envToken = metaEnv?.VITE_BRIDGE_TOKEN; + const token = cookieToken || envToken; if (token) { config.headers["Authorization"] = `Bearer ${token}`; } diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts index e6f9de48..4965ced0 100644 --- a/apps/client/vite.config.ts +++ b/apps/client/vite.config.ts @@ -16,6 +16,7 @@ export default defineConfig(({ mode }) => { BILLING_TRIAL_DAYS, POSTHOG_HOST, POSTHOG_KEY, + VITE_BRIDGE_TOKEN, } = loadEnv(mode, envPath, ""); return { @@ -31,6 +32,7 @@ export default defineConfig(({ mode }) => { BILLING_TRIAL_DAYS, POSTHOG_HOST, POSTHOG_KEY, + VITE_BRIDGE_TOKEN, }, APP_VERSION: JSON.stringify(process.env.npm_package_version), }, @@ -70,6 +72,16 @@ export default defineConfig(({ mode }) => { ws: true, rewriteWsOrigin: true, }, + "/bridge": { + target: process.env.VITE_BRIDGE_PROXY_TARGET || "http://localhost:4000", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/bridge/, ""), + }, + "/bridge-events": { + target: process.env.VITE_BRIDGE_PROXY_TARGET || "http://localhost:4000", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/bridge-events/, "/api/events"), + }, }, }, };