mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 20:10:56 +00:00
131 lines
4.2 KiB
TypeScript
131 lines
4.2 KiB
TypeScript
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { createRequire } from "node:module";
|
|
|
|
import { defineConfig } from "vitest/config";
|
|
import { loadEnv, type Plugin } from "vite";
|
|
import react from "@vitejs/plugin-react";
|
|
import tailwindcss from "@tailwindcss/vite";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const require = createRequire(import.meta.url);
|
|
const streamBrowserifyPath = require.resolve("stream-browserify");
|
|
|
|
function createIamApiAdapter(apiBaseUrl: string): Plugin {
|
|
const upstreamBaseUrl = `${apiBaseUrl.replace(/\/+$/, "")}/api`;
|
|
|
|
return {
|
|
name: "iam-api-adapter",
|
|
configureServer(server) {
|
|
server.middlewares.use("/um-api", async (req, res) => {
|
|
const requestPath = req.url ?? "/";
|
|
const normalizedPath = requestPath.replace(/^\/+/, "");
|
|
const targetUrl = new URL(normalizedPath, `${upstreamBaseUrl}/`);
|
|
|
|
try {
|
|
const headers = new Headers();
|
|
for (const [key, value] of Object.entries(req.headers)) {
|
|
if (!value || key.toLowerCase() === "host") {
|
|
continue;
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
for (const item of value) {
|
|
headers.append(key, item);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
headers.set(key, value);
|
|
}
|
|
|
|
const body =
|
|
req.method === "GET" || req.method === "HEAD"
|
|
? undefined
|
|
: await new Promise<Buffer>((resolve, reject) => {
|
|
const chunks: Buffer[] = [];
|
|
req.on("data", (chunk) =>
|
|
chunks.push(
|
|
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk),
|
|
),
|
|
);
|
|
req.on("end", () => resolve(Buffer.concat(chunks)));
|
|
req.on("error", reject);
|
|
});
|
|
|
|
const upstreamResponse = await fetch(targetUrl, {
|
|
method: req.method,
|
|
headers,
|
|
body,
|
|
});
|
|
|
|
if (targetUrl.pathname.endsWith("/auth/me")) {
|
|
const payload = await upstreamResponse.json();
|
|
const unwrappedPayload =
|
|
payload &&
|
|
typeof payload === "object" &&
|
|
"success" in payload &&
|
|
"data" in payload
|
|
? payload.data
|
|
: payload;
|
|
|
|
res.statusCode = upstreamResponse.status;
|
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
res.end(JSON.stringify(unwrappedPayload));
|
|
return;
|
|
}
|
|
|
|
res.statusCode = upstreamResponse.status;
|
|
upstreamResponse.headers.forEach((value, key) => {
|
|
res.setHeader(key, value);
|
|
});
|
|
res.end(Buffer.from(await upstreamResponse.arrayBuffer()));
|
|
} catch (error) {
|
|
server.ssrFixStacktrace(error as Error);
|
|
res.statusCode = 502;
|
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
res.end(
|
|
JSON.stringify({
|
|
message: "Failed to forward IAM request",
|
|
}),
|
|
);
|
|
}
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
export default defineConfig(({ mode }) => {
|
|
const env = loadEnv(mode, __dirname, "");
|
|
const apiBaseUrl =
|
|
env.VITE_BASE_API_URL?.trim() || "http://localhost:3000";
|
|
|
|
return {
|
|
plugins: [react(), tailwindcss(), createIamApiAdapter(apiBaseUrl)],
|
|
resolve: {
|
|
alias: {
|
|
"@": path.resolve(__dirname, "./src"),
|
|
"node:buffer": "buffer",
|
|
"node:stream": streamBrowserifyPath,
|
|
// Resolve from TS source so Vite gets ESM named exports (dist is CommonJS).
|
|
"@edr/types": path.resolve(
|
|
__dirname,
|
|
"../../../packages/types/src/index.ts",
|
|
),
|
|
},
|
|
// Force a single copy of these singletons so MantineProvider context is
|
|
// shared between the backoffice app and @edr/ui-common (which ships its
|
|
// own node_modules copy). Without this, two separate @mantine/core
|
|
// instances are bundled and the context lookup fails at runtime.
|
|
dedupe: ["react", "react-dom", "@mantine/core", "@mantine/hooks"],
|
|
},
|
|
server: {
|
|
port: 5183,
|
|
host: "0.0.0.0",
|
|
},
|
|
test: {
|
|
environment: "node",
|
|
},
|
|
};
|
|
});
|