98 lines
4.0 KiB
TypeScript
98 lines
4.0 KiB
TypeScript
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,
|
|
);
|
|
});
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
});
|