/** * Gateway proxy endpoints for the brain graph knowledge-graph visualizer. * * Exposes GET /v1/brain-graph and GET /v1/brain-graph-ui through the gateway * for dedicated auth handling. * * The brain-graph-ui endpoint proxies plain HTML from the daemon and injects * an auth token meta tag before returning the page to the client. The daemon * has no knowledge of the token — the gateway owns the entire auth surface. * * Short-term approach: the gateway injects a `` tag * into the proxied HTML. Longer-term, the brain-graph route should return * only JSON data so clients (which already have proper auth) render the UI * themselves, eliminating the need for embedded tokens entirely. See ATL-307. */ import { proxyForwardToResponse } from "@vellumai/assistant-client"; import { mintServiceToken, mintUiPageToken, } from "../../auth/token-exchange.js"; import type { GatewayConfig } from "../../config.js"; import { fetchImpl } from "../../fetch.js"; import { getLogger } from "../../logger.js"; const log = getLogger("brain-graph-proxy"); export function createBrainGraphProxyHandler(config: GatewayConfig) { async function proxyTo(req: Request, path: string): Promise { const start = performance.now(); const response = await proxyForwardToResponse(req, { baseUrl: config.assistantRuntimeBaseUrl, path, serviceToken: mintServiceToken(), timeoutMs: config.runtimeTimeoutMs, fetchImpl, }); const duration = Math.round(performance.now() - start); if (response.status >= 400) { log.warn( { status: response.status, duration, path }, "Brain graph proxy upstream error", ); } else { log.info( { status: response.status, duration, path }, "Brain graph proxy completed", ); } return response; } async function handleBrainGraph(req: Request): Promise { return proxyTo(req, "/v1/brain-graph"); } async function handleBrainGraphUI(req: Request): Promise { const response = await proxyTo(req, "/v1/brain-graph-ui"); if (!response.ok) return response; const html = await response.text(); const token = mintUiPageToken(); const escapedToken = token .replace(/&/g, "&") .replace(/"/g, """) .replace(//g, ">"); const metaTag = ` \n`; const injected = html.replace("", `${metaTag}`); const headers = new Headers(response.headers); headers.delete("content-length"); return new Response(injected, { status: response.status, headers, }); } return { handleBrainGraph, handleBrainGraphUI }; }