import tailwindcss from "@tailwindcss/vite"; import react from "@vitejs/plugin-react"; import path from "node:path"; import { defineConfig, loadEnv } from "vite"; export default defineConfig(({ mode }) => { /** * Secrets for the dev proxy, read WITHOUT the `VITE_` prefix on purpose. * * Vite only exposes `VITE_`-prefixed variables to client code, so anything * named plainly here stays in the Node process running the dev server and * never reaches the bundle. The ingest service's token is injected into the * proxied request below, server-side, exactly the way the old console handles * its Hasura admin secret. * * Put it in `.env.local` (gitignored): * * INGEST_TOKEN=... */ const env = loadEnv(mode, process.cwd(), ""); const ingestToken = (env["INGEST_TOKEN"] ?? "").trim(); const ingestHeader = (env["INGEST_AUTH_HEADER"] ?? "Authorization").trim(); const ingestScheme = (env["INGEST_AUTH_SCHEME"] ?? "Bearer").trim(); return { plugins: [react(), tailwindcss()], /** * A build stamp, shown at the foot of the account menu. * * This exists because of a real and expensive failure: work was verified here, * reported as done, and looked at on a machine running an older copy — twice, * over four days, with no way for either side to tell. A dev server and a * stale folder are indistinguishable from the screen. Now they are not. */ define: { __BUILD_STAMP__: JSON.stringify( new Date().toISOString().replace("T", " ").slice(0, 16).concat(" UTC"), ), }, resolve: { alias: { "@": path.resolve(import.meta.dirname, "./src") } }, server: { // 3100, not 3000: the OLD console (daily_merchant_web) runs its dev server // on 3000. Sharing a port means whichever starts first wins it, and you end // up looking at the wrong app while wondering why nothing changed. port: 3100, strictPort: true, proxy: { "/fiesta": { target: "https://fiesta.nearle.app", changeOrigin: true, secure: true, rewrite: (p) => p.replace(/^\/fiesta/, ""), }, /** * The catalogue ingest service. * * Proxied for the same reason as Fiesta, plus one more: this is a * different origin entirely, so calling it from the browser would need * `Access-Control-Allow-Origin` for localhost:3100 on their side. Going * through the dev server makes it same-origin and removes the question * from development. * * It does NOT remove it from production. A deployed console calls the * service directly, so CORS has to be configured there before this ships * — otherwise it works on every developer machine and fails the moment it * is deployed, which is the worst order to find out. */ "/ingest": { target: "https://mcp.nearle.ai.in", changeOrigin: true, secure: true, rewrite: (p) => p.replace(/^\/ingest/, ""), configure: (proxy) => { // The credential is attached HERE, not in the app. // // The service answered the first real upload with 401, so it wants // one. A token the browser holds is a token you have published — the // bundle is served to anyone who opens the console — so it is added // on this side of the proxy and the client never sees it. // // This covers development only. A deployed console talks to the // service directly, and the same reasoning says the token cannot // travel with it: production needs the call relayed through Fiesta, // or an endpoint that accepts the console user's own session. proxy.on("proxyReq", (proxyReq) => { if (!ingestToken) return; proxyReq.setHeader( ingestHeader, ingestScheme ? `${ingestScheme} ${ingestToken}` : ingestToken, ); }); }, }, }, }, }; });