fix(opencode): send x-headroom-project header on all proxied requests (#2868)
## Description The OpenCode transport plugin set `HEADROOM_PROJECT` as a shell env var for child processes but never forwarded it as `x-headroom-project` on the actual proxied HTTP requests. The proxy's `classify_project` only attributes traffic via `x-headroom-project` header or `/p/<name>` URL prefix — without the header, every OpenCode request was unattributed and the Per-Project Savings dashboard showed `0 project(s)` permanently. Fixes #2847. ## Root cause `installHeadroomTransport` was called with only `{ proxyUrl, debug }`. The `project` value was computed and used only in the `shell.env` hook (for subprocess env injection), never threaded through to `mergeFetchHeaders` or `headersForNodeRequest`. ## Changes Made 1. Add `project?: string` to `InstallOptions` and `TransportState`. 2. Resolve the project value once at plugin init (`pluginOptions.project → input.project.id → input.directory`) and pass it to `installHeadroomTransport`. 3. Both header-building seams now set `x-headroom-project` when a project is present: - `mergeFetchHeaders` (wrapped `fetch` path) - `headersForNodeRequest` (wrapped `http.request` / `https.request` path) 4. Reuse the resolved `project` in the `shell.env` hook (removes the duplicate resolution that was there before). ## Changes - `plugins/opencode/src/transport.ts` — `InstallOptions.project`, `TransportState.project`; `mergeFetchHeaders`, `headersForNodeRequest`, `routedNodeOptions`, `withRoutedFetchInput`, `installHeadroomTransport` updated - `plugins/opencode/src/plugin.ts` — resolve `project` once, pass it to transport; reuse in `shell.env` - `plugins/opencode/src/transport.test.ts` — 3 new tests: project header on fetch, project header on https.request, no header when project unset - `headroom/providers/opencode/_dist/entry.opencode.js` — rebuilt with `npm run build:standalone` to match source ## Testing - [x] Unit tests pass - [x] TypeScript typecheck passes - [x] New regression tests added ### Test Output ``` cd plugins/opencode && npm test # 17 passed (14 existing + 3 new) ``` TypeScript build also passes: `npm run typecheck` (no errors). ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature - [ ] Breaking change - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring ## Real Behavior Proof - Environment: OpenCode transport plugin test environment on the current PR head. - Exact command / steps: ran the plugin test suite and TypeScript typecheck after rebuilding the standalone bundle. - Observed result: all 17 tests passed, including project-header coverage for fetch and Node HTTPS paths plus the unset-project control; typechecking passed. - Not tested: a live OpenCode session against a deployed Headroom proxy. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review --------- Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com> Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
This commit is contained in:
committed by
GitHub
parent
2cae0f8eaf
commit
eeb038bc0c
@@ -12487,6 +12487,7 @@ var childProcess = nodeRequire("node:child_process");
|
||||
var fs = nodeRequire("node:fs");
|
||||
var BASE_URL_HEADER = "x-headroom-base-url";
|
||||
var ORIGINAL_PATH_HEADER = "x-headroom-original-path";
|
||||
var PROJECT_HEADER = "x-headroom-project";
|
||||
var PROXY_ENV = "HEADROOM_OPENCODE_TRANSPORT_PROXY_URL";
|
||||
var STATE_KEY = /* @__PURE__ */ Symbol.for("headroom.opencode.transport");
|
||||
function getState() {
|
||||
@@ -12635,7 +12636,7 @@ function requestUrl(input) {
|
||||
}
|
||||
return new URL(String(input));
|
||||
}
|
||||
function mergeFetchHeaders(input, init, upstream, originalPath = void 0) {
|
||||
function mergeFetchHeaders(input, init, upstream, originalPath = void 0, project = void 0) {
|
||||
const headers = new Headers(input instanceof Request ? input.headers : void 0);
|
||||
if (init?.headers) {
|
||||
new Headers(init.headers).forEach((value, key) => headers.set(key, value));
|
||||
@@ -12647,9 +12648,12 @@ function mergeFetchHeaders(input, init, upstream, originalPath = void 0) {
|
||||
if (originalPath) {
|
||||
headers.set(ORIGINAL_PATH_HEADER, originalPath);
|
||||
}
|
||||
if (project) {
|
||||
headers.set(PROJECT_HEADER, project);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
function withRoutedFetchInput(input, init, proxy) {
|
||||
function withRoutedFetchInput(input, init, proxy, project) {
|
||||
const upstream = requestUrl(input);
|
||||
if (!shouldRoute(upstream, proxy)) {
|
||||
return [input, init];
|
||||
@@ -12657,7 +12661,7 @@ function withRoutedFetchInput(input, init, proxy) {
|
||||
const { url: nextUrl, originalPath } = routedUrlForOpenCode(upstream, proxy);
|
||||
const nextInit = {
|
||||
...init,
|
||||
headers: mergeFetchHeaders(input, init, upstream, originalPath)
|
||||
headers: mergeFetchHeaders(input, init, upstream, originalPath, project)
|
||||
};
|
||||
if (input instanceof Request) {
|
||||
return [new Request(nextUrl, input), nextInit];
|
||||
@@ -12703,12 +12707,15 @@ function urlFromRequestOptions(options) {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
function headersForNodeRequest(options, upstream, originalPath) {
|
||||
function headersForNodeRequest(options, upstream, originalPath, project) {
|
||||
const headers = new Headers(options.headers);
|
||||
headers.set(BASE_URL_HEADER, upstream.origin);
|
||||
if (originalPath) {
|
||||
headers.set(ORIGINAL_PATH_HEADER, originalPath);
|
||||
}
|
||||
if (project) {
|
||||
headers.set(PROJECT_HEADER, project);
|
||||
}
|
||||
headers.delete("host");
|
||||
const result = {};
|
||||
headers.forEach((value, key) => {
|
||||
@@ -12716,7 +12723,7 @@ function headersForNodeRequest(options, upstream, originalPath) {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function routedNodeOptions(parts, proxy) {
|
||||
function routedNodeOptions(parts, proxy, project) {
|
||||
if (!parts.url || !shouldRoute(parts.url, proxy)) {
|
||||
return void 0;
|
||||
}
|
||||
@@ -12747,7 +12754,7 @@ function routedNodeOptions(parts, proxy) {
|
||||
hostname: nextUrl.hostname,
|
||||
port: nextUrl.port || void 0,
|
||||
path: `${nextUrl.pathname}${nextUrl.search}`,
|
||||
headers: headersForNodeRequest(parts.options, parts.url, originalPath)
|
||||
headers: headersForNodeRequest(parts.options, parts.url, originalPath, project)
|
||||
};
|
||||
}
|
||||
function wrapRequest(originalHttpRequest, originalHttpsRequest, originalRequest) {
|
||||
@@ -12758,7 +12765,7 @@ function wrapRequest(originalHttpRequest, originalHttpsRequest, originalRequest)
|
||||
}
|
||||
const proxy = normalizeProxyUrl(state.proxyUrl);
|
||||
const parts = splitNodeArgs(args);
|
||||
const nextOptions = routedNodeOptions(parts, proxy);
|
||||
const nextOptions = routedNodeOptions(parts, proxy, state.project);
|
||||
if (!nextOptions) {
|
||||
return Reflect.apply(originalRequest, this, args);
|
||||
}
|
||||
@@ -12794,6 +12801,7 @@ function installHeadroomTransport(options) {
|
||||
if (existing) {
|
||||
existing.refs += 1;
|
||||
existing.proxyUrl = options.proxyUrl;
|
||||
existing.project = options.project;
|
||||
existing.debug = Boolean(options.debug);
|
||||
installProcessEnv(options.proxyUrl);
|
||||
return () => uninstallHeadroomTransport();
|
||||
@@ -12801,6 +12809,7 @@ function installHeadroomTransport(options) {
|
||||
const state = {
|
||||
refs: 1,
|
||||
proxyUrl: options.proxyUrl,
|
||||
project: options.project,
|
||||
debug: Boolean(options.debug),
|
||||
originalFetch: globalThis.fetch,
|
||||
originalHttpRequest: http.request,
|
||||
@@ -12821,7 +12830,7 @@ function installHeadroomTransport(options) {
|
||||
return state.originalFetch(...args);
|
||||
}
|
||||
const proxy = normalizeProxyUrl(current.proxyUrl);
|
||||
const [nextInput, nextInit] = withRoutedFetchInput(args[0], args[1], proxy);
|
||||
const [nextInput, nextInit] = withRoutedFetchInput(args[0], args[1], proxy, current.project);
|
||||
return state.originalFetch(nextInput, nextInit);
|
||||
};
|
||||
http.request = wrapRequest(state.originalHttpRequest, state.originalHttpsRequest, state.originalHttpRequest);
|
||||
@@ -12871,9 +12880,11 @@ function resolveProxyUrl(options) {
|
||||
var HeadroomPlugin = async (input, options = {}) => {
|
||||
const pluginOptions = options;
|
||||
const proxyUrl = resolveProxyUrl(pluginOptions);
|
||||
const project = pluginOptions.project ?? input.project?.id ?? input.directory;
|
||||
const retrieveTool = createHeadroomRetrieveTool({ proxyBaseUrl: proxyUrl });
|
||||
const uninstallTransport = installHeadroomTransport({
|
||||
proxyUrl,
|
||||
project,
|
||||
debug: pluginOptions.debug
|
||||
});
|
||||
return {
|
||||
@@ -12894,7 +12905,7 @@ var HeadroomPlugin = async (input, options = {}) => {
|
||||
"shell.env": async (_input, output) => {
|
||||
output.env.HEADROOM_ACTIVE = "1";
|
||||
output.env.HEADROOM_PROXY_URL = proxyUrl;
|
||||
output.env.HEADROOM_PROJECT = pluginOptions.project ?? input.project.id ?? input.directory;
|
||||
output.env.HEADROOM_PROJECT = project;
|
||||
if (pluginOptions.backend) {
|
||||
output.env.HEADROOM_BACKEND = pluginOptions.backend;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ var childProcess = nodeRequire("node:child_process");
|
||||
var fs = nodeRequire("node:fs");
|
||||
var BASE_URL_HEADER = "x-headroom-base-url";
|
||||
var ORIGINAL_PATH_HEADER = "x-headroom-original-path";
|
||||
var PROJECT_HEADER = "x-headroom-project";
|
||||
var PROXY_ENV = "HEADROOM_OPENCODE_TRANSPORT_PROXY_URL";
|
||||
var STATE_KEY = /* @__PURE__ */ Symbol.for("headroom.opencode.transport");
|
||||
function getState() {
|
||||
@@ -156,7 +157,7 @@ function requestUrl(input) {
|
||||
}
|
||||
return new URL(String(input));
|
||||
}
|
||||
function mergeFetchHeaders(input, init, upstream, originalPath = void 0) {
|
||||
function mergeFetchHeaders(input, init, upstream, originalPath = void 0, project = void 0) {
|
||||
const headers = new Headers(input instanceof Request ? input.headers : void 0);
|
||||
if (init?.headers) {
|
||||
new Headers(init.headers).forEach((value, key) => headers.set(key, value));
|
||||
@@ -168,9 +169,12 @@ function mergeFetchHeaders(input, init, upstream, originalPath = void 0) {
|
||||
if (originalPath) {
|
||||
headers.set(ORIGINAL_PATH_HEADER, originalPath);
|
||||
}
|
||||
if (project) {
|
||||
headers.set(PROJECT_HEADER, project);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
function withRoutedFetchInput(input, init, proxy) {
|
||||
function withRoutedFetchInput(input, init, proxy, project) {
|
||||
const upstream = requestUrl(input);
|
||||
if (!shouldRoute(upstream, proxy)) {
|
||||
return [input, init];
|
||||
@@ -178,7 +182,7 @@ function withRoutedFetchInput(input, init, proxy) {
|
||||
const { url: nextUrl, originalPath } = routedUrlForOpenCode(upstream, proxy);
|
||||
const nextInit = {
|
||||
...init,
|
||||
headers: mergeFetchHeaders(input, init, upstream, originalPath)
|
||||
headers: mergeFetchHeaders(input, init, upstream, originalPath, project)
|
||||
};
|
||||
if (input instanceof Request) {
|
||||
return [new Request(nextUrl, input), nextInit];
|
||||
@@ -224,12 +228,15 @@ function urlFromRequestOptions(options) {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
function headersForNodeRequest(options, upstream, originalPath) {
|
||||
function headersForNodeRequest(options, upstream, originalPath, project) {
|
||||
const headers = new Headers(options.headers);
|
||||
headers.set(BASE_URL_HEADER, upstream.origin);
|
||||
if (originalPath) {
|
||||
headers.set(ORIGINAL_PATH_HEADER, originalPath);
|
||||
}
|
||||
if (project) {
|
||||
headers.set(PROJECT_HEADER, project);
|
||||
}
|
||||
headers.delete("host");
|
||||
const result = {};
|
||||
headers.forEach((value, key) => {
|
||||
@@ -237,7 +244,7 @@ function headersForNodeRequest(options, upstream, originalPath) {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function routedNodeOptions(parts, proxy) {
|
||||
function routedNodeOptions(parts, proxy, project) {
|
||||
if (!parts.url || !shouldRoute(parts.url, proxy)) {
|
||||
return void 0;
|
||||
}
|
||||
@@ -268,7 +275,7 @@ function routedNodeOptions(parts, proxy) {
|
||||
hostname: nextUrl.hostname,
|
||||
port: nextUrl.port || void 0,
|
||||
path: `${nextUrl.pathname}${nextUrl.search}`,
|
||||
headers: headersForNodeRequest(parts.options, parts.url, originalPath)
|
||||
headers: headersForNodeRequest(parts.options, parts.url, originalPath, project)
|
||||
};
|
||||
}
|
||||
function wrapRequest(originalHttpRequest, originalHttpsRequest, originalRequest) {
|
||||
@@ -279,7 +286,7 @@ function wrapRequest(originalHttpRequest, originalHttpsRequest, originalRequest)
|
||||
}
|
||||
const proxy = normalizeProxyUrl(state.proxyUrl);
|
||||
const parts = splitNodeArgs(args);
|
||||
const nextOptions = routedNodeOptions(parts, proxy);
|
||||
const nextOptions = routedNodeOptions(parts, proxy, state.project);
|
||||
if (!nextOptions) {
|
||||
return Reflect.apply(originalRequest, this, args);
|
||||
}
|
||||
@@ -315,6 +322,7 @@ function installHeadroomTransport(options) {
|
||||
if (existing) {
|
||||
existing.refs += 1;
|
||||
existing.proxyUrl = options.proxyUrl;
|
||||
existing.project = options.project;
|
||||
existing.debug = Boolean(options.debug);
|
||||
installProcessEnv(options.proxyUrl);
|
||||
return () => uninstallHeadroomTransport();
|
||||
@@ -322,6 +330,7 @@ function installHeadroomTransport(options) {
|
||||
const state = {
|
||||
refs: 1,
|
||||
proxyUrl: options.proxyUrl,
|
||||
project: options.project,
|
||||
debug: Boolean(options.debug),
|
||||
originalFetch: globalThis.fetch,
|
||||
originalHttpRequest: http.request,
|
||||
@@ -342,7 +351,7 @@ function installHeadroomTransport(options) {
|
||||
return state.originalFetch(...args);
|
||||
}
|
||||
const proxy = normalizeProxyUrl(current.proxyUrl);
|
||||
const [nextInput, nextInit] = withRoutedFetchInput(args[0], args[1], proxy);
|
||||
const [nextInput, nextInit] = withRoutedFetchInput(args[0], args[1], proxy, current.project);
|
||||
return state.originalFetch(nextInput, nextInit);
|
||||
};
|
||||
http.request = wrapRequest(state.originalHttpRequest, state.originalHttpsRequest, state.originalHttpRequest);
|
||||
|
||||
@@ -28,9 +28,14 @@ function resolveProxyUrl(options?: HeadroomOpenCodePluginOptions): string {
|
||||
export const HeadroomPlugin: Plugin = async (input, options = {}) => {
|
||||
const pluginOptions = options as HeadroomOpenCodePluginOptions;
|
||||
const proxyUrl = resolveProxyUrl(pluginOptions);
|
||||
const project =
|
||||
pluginOptions.project ??
|
||||
(input.project as { id?: string } | undefined)?.id ??
|
||||
input.directory;
|
||||
const retrieveTool = createHeadroomRetrieveTool({ proxyBaseUrl: proxyUrl });
|
||||
const uninstallTransport = installHeadroomTransport({
|
||||
proxyUrl,
|
||||
project,
|
||||
debug: pluginOptions.debug,
|
||||
});
|
||||
|
||||
@@ -54,10 +59,7 @@ export const HeadroomPlugin: Plugin = async (input, options = {}) => {
|
||||
"shell.env": async (_input, output) => {
|
||||
output.env.HEADROOM_ACTIVE = "1";
|
||||
output.env.HEADROOM_PROXY_URL = proxyUrl;
|
||||
output.env.HEADROOM_PROJECT =
|
||||
pluginOptions.project ??
|
||||
(input.project as { id?: string }).id ??
|
||||
input.directory;
|
||||
output.env.HEADROOM_PROJECT = project;
|
||||
if (pluginOptions.backend) {
|
||||
output.env.HEADROOM_BACKEND = pluginOptions.backend;
|
||||
}
|
||||
|
||||
@@ -386,6 +386,58 @@ describe("Headroom OpenCode transport", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("sends x-headroom-project header on routed fetch calls when project is set", async () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
const fetchMock = vi.fn(async (..._args: FetchCall) => new Response("ok"));
|
||||
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
||||
|
||||
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1", project: "my-project" });
|
||||
|
||||
await fetch("https://api.anthropic.com/v1/messages", { method: "POST" });
|
||||
|
||||
const headers = new Headers(fetchMock.mock.calls[0][1]?.headers);
|
||||
expect(headers.get("x-headroom-project")).toBe("my-project");
|
||||
|
||||
globalThis.fetch = originalFetch;
|
||||
});
|
||||
|
||||
it("omits x-headroom-project header when project is not set", async () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
const fetchMock = vi.fn(async (..._args: FetchCall) => new Response("ok"));
|
||||
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
||||
|
||||
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
|
||||
|
||||
await fetch("https://api.anthropic.com/v1/messages", { method: "POST" });
|
||||
|
||||
const headers = new Headers(fetchMock.mock.calls[0][1]?.headers);
|
||||
expect(headers.get("x-headroom-project")).toBeNull();
|
||||
|
||||
globalThis.fetch = originalFetch;
|
||||
});
|
||||
|
||||
it("sends x-headroom-project header on routed Node https.request calls when project is set", async () => {
|
||||
const proxy = await proxyServer();
|
||||
installHeadroomTransport({ proxyUrl: proxy.url, project: "my-project" });
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const req = https.request(
|
||||
"https://api.anthropic.com/v1/messages",
|
||||
{ method: "POST" },
|
||||
(res) => {
|
||||
res.resume();
|
||||
res.on("end", resolve);
|
||||
},
|
||||
);
|
||||
req.on("error", reject);
|
||||
req.end("{}");
|
||||
});
|
||||
|
||||
expect(proxy.seen[0].headers["x-headroom-project"]).toBe("my-project");
|
||||
|
||||
await proxy.close();
|
||||
});
|
||||
|
||||
it("restores patched transports only after the final disposer", () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
const originalHttpRequest = http.request;
|
||||
|
||||
@@ -9,6 +9,7 @@ const fs = nodeRequire("node:fs") as typeof import("node:fs");
|
||||
|
||||
const BASE_URL_HEADER = "x-headroom-base-url";
|
||||
const ORIGINAL_PATH_HEADER = "x-headroom-original-path";
|
||||
const PROJECT_HEADER = "x-headroom-project";
|
||||
const PROXY_ENV = "HEADROOM_OPENCODE_TRANSPORT_PROXY_URL";
|
||||
const STATE_KEY = Symbol.for("headroom.opencode.transport");
|
||||
|
||||
@@ -25,12 +26,14 @@ type ChildFork = typeof childProcess.fork;
|
||||
|
||||
interface InstallOptions {
|
||||
proxyUrl: string;
|
||||
project?: string;
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
interface TransportState {
|
||||
refs: number;
|
||||
proxyUrl: string;
|
||||
project: string | undefined;
|
||||
debug: boolean;
|
||||
originalFetch: typeof fetch;
|
||||
originalHttpRequest: HttpRequest;
|
||||
@@ -233,6 +236,7 @@ function mergeFetchHeaders(
|
||||
init: RequestInit | undefined,
|
||||
upstream: URL | undefined,
|
||||
originalPath: string | undefined = undefined,
|
||||
project: string | undefined = undefined,
|
||||
): Headers {
|
||||
const headers = new Headers(input instanceof Request ? input.headers : undefined);
|
||||
if (init?.headers) {
|
||||
@@ -245,10 +249,13 @@ function mergeFetchHeaders(
|
||||
if (originalPath) {
|
||||
headers.set(ORIGINAL_PATH_HEADER, originalPath);
|
||||
}
|
||||
if (project) {
|
||||
headers.set(PROJECT_HEADER, project);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
function withRoutedFetchInput(input: RequestInfo | URL, init: RequestInit | undefined, proxy: URL): FetchArgs {
|
||||
function withRoutedFetchInput(input: RequestInfo | URL, init: RequestInit | undefined, proxy: URL, project: string | undefined): FetchArgs {
|
||||
const upstream = requestUrl(input);
|
||||
if (!shouldRoute(upstream, proxy)) {
|
||||
return [input, init];
|
||||
@@ -257,7 +264,7 @@ function withRoutedFetchInput(input: RequestInfo | URL, init: RequestInit | unde
|
||||
const { url: nextUrl, originalPath } = routedUrlForOpenCode(upstream, proxy);
|
||||
const nextInit = {
|
||||
...init,
|
||||
headers: mergeFetchHeaders(input, init, upstream, originalPath),
|
||||
headers: mergeFetchHeaders(input, init, upstream, originalPath, project),
|
||||
};
|
||||
|
||||
if (input instanceof Request) {
|
||||
@@ -314,12 +321,16 @@ function headersForNodeRequest(
|
||||
options: Record<string, unknown>,
|
||||
upstream: URL,
|
||||
originalPath: string | undefined,
|
||||
project: string | undefined,
|
||||
): Record<string, string> {
|
||||
const headers = new Headers(options.headers as HeadersInit | undefined);
|
||||
headers.set(BASE_URL_HEADER, upstream.origin);
|
||||
if (originalPath) {
|
||||
headers.set(ORIGINAL_PATH_HEADER, originalPath);
|
||||
}
|
||||
if (project) {
|
||||
headers.set(PROJECT_HEADER, project);
|
||||
}
|
||||
headers.delete("host");
|
||||
|
||||
const result: Record<string, string> = {};
|
||||
@@ -329,7 +340,7 @@ function headersForNodeRequest(
|
||||
return result;
|
||||
}
|
||||
|
||||
function routedNodeOptions(parts: NodeRequestParts, proxy: URL): Record<string, unknown> | undefined {
|
||||
function routedNodeOptions(parts: NodeRequestParts, proxy: URL, project: string | undefined): Record<string, unknown> | undefined {
|
||||
if (!parts.url || !shouldRoute(parts.url, proxy)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -362,7 +373,7 @@ function routedNodeOptions(parts: NodeRequestParts, proxy: URL): Record<string,
|
||||
hostname: nextUrl.hostname,
|
||||
port: nextUrl.port || undefined,
|
||||
path: `${nextUrl.pathname}${nextUrl.search}`,
|
||||
headers: headersForNodeRequest(parts.options, parts.url, originalPath),
|
||||
headers: headersForNodeRequest(parts.options, parts.url, originalPath, project),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -379,7 +390,7 @@ function wrapRequest(
|
||||
|
||||
const proxy = normalizeProxyUrl(state.proxyUrl);
|
||||
const parts = splitNodeArgs(args);
|
||||
const nextOptions = routedNodeOptions(parts, proxy);
|
||||
const nextOptions = routedNodeOptions(parts, proxy, state.project);
|
||||
if (!nextOptions) {
|
||||
return Reflect.apply(originalRequest, this, args);
|
||||
}
|
||||
@@ -420,6 +431,7 @@ export function installHeadroomTransport(options: InstallOptions): () => void {
|
||||
if (existing) {
|
||||
existing.refs += 1;
|
||||
existing.proxyUrl = options.proxyUrl;
|
||||
existing.project = options.project;
|
||||
existing.debug = Boolean(options.debug);
|
||||
installProcessEnv(options.proxyUrl);
|
||||
return () => uninstallHeadroomTransport();
|
||||
@@ -428,6 +440,7 @@ export function installHeadroomTransport(options: InstallOptions): () => void {
|
||||
const state: TransportState = {
|
||||
refs: 1,
|
||||
proxyUrl: options.proxyUrl,
|
||||
project: options.project,
|
||||
debug: Boolean(options.debug),
|
||||
originalFetch: globalThis.fetch,
|
||||
originalHttpRequest: http.request,
|
||||
@@ -449,7 +462,7 @@ export function installHeadroomTransport(options: InstallOptions): () => void {
|
||||
return state.originalFetch(...args);
|
||||
}
|
||||
const proxy = normalizeProxyUrl(current.proxyUrl);
|
||||
const [nextInput, nextInit] = withRoutedFetchInput(args[0], args[1], proxy);
|
||||
const [nextInput, nextInit] = withRoutedFetchInput(args[0], args[1], proxy, current.project);
|
||||
return state.originalFetch(nextInput, nextInit);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user