@introspection-sdk/introspection-proxy 0.7.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/index.d.ts +10 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +7 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +19 -2
- package/dist/proxy.js.map +1 -1
- package/dist/tracing.d.ts +14 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +94 -0
- package/dist/tracing.js.map +1 -0
- package/package.json +2 -1
- package/src/index.ts +10 -6
- package/src/proxy.ts +44 -5
- package/src/tracing.ts +106 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
> @introspection-sdk/introspection-proxy@0.
|
|
2
|
+
> @introspection-sdk/introspection-proxy@0.8.1 build /home/runner/work/introspection-js-sdk/introspection-js-sdk/packages/introspection-proxy
|
|
3
3
|
> tsc
|
|
4
4
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@introspection-sdk/introspection-proxy`
|
|
3
3
|
*
|
|
4
|
-
* Lightweight, dependency-minimal
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Lightweight, dependency-minimal helpers for routing `fetch`-based clients
|
|
5
|
+
* through the Introspection egress credential-injection proxy or a standard
|
|
6
|
+
* forward proxy. Depends only on undici and the zero-dependency
|
|
7
|
+
* `@opentelemetry/api` (proxied requests emit `introspection-proxy-call`
|
|
8
|
+
* spans that no-op unless the host process registers a tracer provider — no
|
|
9
|
+
* OTel SDK or provider-SDK dependencies), so it can be used standalone (e.g.
|
|
10
|
+
* alongside the `introspection-pi` instrumentation wrapper) without pulling
|
|
11
|
+
* in the full `introspection-node` surface.
|
|
10
12
|
*/
|
|
11
13
|
export { getProxyDispatcher, createProxyFetch, installProxyFetch, resolveForwardProxyUrl, } from "./proxy.js";
|
|
12
14
|
export type { ProxyFetchOptions } from "./proxy.js";
|
|
15
|
+
export { PROXY_CALL_SPAN_NAME, PROXY_TRACER_NAME } from "./tracing.js";
|
|
16
|
+
export type { ProxyMode } from "./tracing.js";
|
|
13
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACvE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@introspection-sdk/introspection-proxy`
|
|
3
3
|
*
|
|
4
|
-
* Lightweight, dependency-minimal
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Lightweight, dependency-minimal helpers for routing `fetch`-based clients
|
|
5
|
+
* through the Introspection egress credential-injection proxy or a standard
|
|
6
|
+
* forward proxy. Depends only on undici and the zero-dependency
|
|
7
|
+
* `@opentelemetry/api` (proxied requests emit `introspection-proxy-call`
|
|
8
|
+
* spans that no-op unless the host process registers a tracer provider — no
|
|
9
|
+
* OTel SDK or provider-SDK dependencies), so it can be used standalone (e.g.
|
|
10
|
+
* alongside the `introspection-pi` instrumentation wrapper) without pulling
|
|
11
|
+
* in the full `introspection-node` surface.
|
|
10
12
|
*/
|
|
11
13
|
export { getProxyDispatcher, createProxyFetch, installProxyFetch, resolveForwardProxyUrl, } from "./proxy.js";
|
|
14
|
+
export { PROXY_CALL_SPAN_NAME, PROXY_TRACER_NAME } from "./tracing.js";
|
|
12
15
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/proxy.d.ts
CHANGED
|
@@ -3,6 +3,13 @@ export interface ProxyFetchOptions {
|
|
|
3
3
|
egressProxyUrl?: string;
|
|
4
4
|
egressProxyHosts?: string;
|
|
5
5
|
forwardProxyUrl?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Emit an `introspection-proxy-call` OTel span per proxied request
|
|
8
|
+
* (default true). Spans no-op unless the host process registered a tracer
|
|
9
|
+
* provider. Direct requests (no proxy, or `NO_PROXY` hosts) never get a
|
|
10
|
+
* span regardless of this flag.
|
|
11
|
+
*/
|
|
12
|
+
tracing?: boolean;
|
|
6
13
|
}
|
|
7
14
|
export declare function resolveForwardProxyUrl(): string | undefined;
|
|
8
15
|
/**
|
package/dist/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAiBA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAiBA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,QAAQ,CAAC;AAOhB,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAiBD,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAQ3D;AA0BD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,iBAAsB,GAC9B,UAAU,GAAG,SAAS,CAUxB;AAaD,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,KAAK,CAmFd;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,IAAI,CAU7E"}
|
package/dist/proxy.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { Socket } from "node:net";
|
|
17
17
|
import { connect as tlsConnect } from "node:tls";
|
|
18
18
|
import { Agent, EnvHttpProxyAgent, fetch as undiciFetch, } from "undici";
|
|
19
|
+
import { matchesNoProxy, parseNoProxyEntries, tracedProxyCall, } from "./tracing.js";
|
|
19
20
|
function resolveEgressUrl(options) {
|
|
20
21
|
return options.egressProxyUrl ?? process.env.INTROSPECTION_EGRESS_URL;
|
|
21
22
|
}
|
|
@@ -94,8 +95,13 @@ export function createProxyFetch(options = {}) {
|
|
|
94
95
|
: undefined;
|
|
95
96
|
if (!egress && !forward)
|
|
96
97
|
return base;
|
|
98
|
+
const tracing = options.tracing ?? true;
|
|
99
|
+
// Snapshot NO_PROXY once, like EnvHttpProxyAgent does at construction. Used
|
|
100
|
+
// only to decide span emission — undici owns the actual routing.
|
|
101
|
+
const noProxyEntries = parseNoProxyEntries(process.env);
|
|
97
102
|
return (input, init) => {
|
|
98
|
-
const
|
|
103
|
+
const url = new URL(toUrlString(input));
|
|
104
|
+
const hostname = url.hostname.toLowerCase();
|
|
99
105
|
const useEgress = !!egress && egressHosts.size > 0 && egressHosts.has(hostname);
|
|
100
106
|
const dispatcher = useEgress ? egress : forward;
|
|
101
107
|
if (!dispatcher)
|
|
@@ -124,7 +130,18 @@ export function createProxyFetch(options = {}) {
|
|
|
124
130
|
if (useEgress && egressIsPlainHttp) {
|
|
125
131
|
target = downgradeToHttp(target);
|
|
126
132
|
}
|
|
127
|
-
|
|
133
|
+
const execute = () => undiciFetch(target, opts);
|
|
134
|
+
// A forward-dispatched request to a NO_PROXY host goes direct inside
|
|
135
|
+
// EnvHttpProxyAgent — no proxy hop, so no proxy span (in-cluster clients
|
|
136
|
+
// trace those calls themselves as `introspection-api-call`).
|
|
137
|
+
const viaProxy = useEgress || !matchesNoProxy(hostname, url.port, noProxyEntries);
|
|
138
|
+
if (!tracing || !viaProxy)
|
|
139
|
+
return execute();
|
|
140
|
+
const method = (init?.method ??
|
|
141
|
+
(typeof Request !== "undefined" && input instanceof Request
|
|
142
|
+
? input.method
|
|
143
|
+
: "GET")).toUpperCase();
|
|
144
|
+
return tracedProxyCall(useEgress ? "egress" : "forward", method, url, execute);
|
|
128
145
|
};
|
|
129
146
|
}
|
|
130
147
|
export function installProxyFetch(options = {}) {
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,KAAK,EACL,iBAAiB,EAEjB,KAAK,IAAI,WAAW,GAErB,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const PROXY_CALL_SPAN_NAME = "introspection-proxy-call";
|
|
2
|
+
export declare const PROXY_TRACER_NAME = "@introspection-sdk/introspection-proxy";
|
|
3
|
+
export type ProxyMode = "egress" | "forward";
|
|
4
|
+
/**
|
|
5
|
+
* Parse `NO_PROXY`/`no_proxy` into normalized entries. Mirrors undici's
|
|
6
|
+
* `EnvHttpProxyAgent` semantics closely enough to decide span emission —
|
|
7
|
+
* undici still owns the actual routing decision.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseNoProxyEntries(env: NodeJS.ProcessEnv): string[];
|
|
10
|
+
/** Whether `hostname[:port]` matches a `NO_PROXY` entry (i.e. goes direct). */
|
|
11
|
+
export declare function matchesNoProxy(hostname: string, port: string, entries: string[]): boolean;
|
|
12
|
+
/** Run `execute` inside an `introspection-proxy-call` CLIENT span. */
|
|
13
|
+
export declare function tracedProxyCall(mode: ProxyMode, method: string, url: URL, execute: () => Promise<Response>): Promise<Response>;
|
|
14
|
+
//# sourceMappingURL=tracing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,oBAAoB,6BAA6B,CAAC;AAC/D,eAAO,MAAM,iBAAiB,2CAA2C,CAAC;AAE1E,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7C;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,EAAE,CAMpE;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAeT;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAC/B,OAAO,CAAC,QAAQ,CAAC,CAoCnB"}
|
package/dist/tracing.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry span instrumentation for proxied requests.
|
|
3
|
+
*
|
|
4
|
+
* Emits one `introspection-proxy-call` CLIENT span per request that is
|
|
5
|
+
* actually routed through a proxy (egress credential-injection or forward
|
|
6
|
+
* CONNECT). Requests that go direct — no proxy configured, or the host is
|
|
7
|
+
* excluded via `NO_PROXY` — deliberately get no span: in-cluster callers
|
|
8
|
+
* (`NO_PROXY` covers the DP API) already trace those calls at the client
|
|
9
|
+
* layer, so proxy spans and client-layer spans stay mutually exclusive.
|
|
10
|
+
*
|
|
11
|
+
* Depends only on `@opentelemetry/api`: without a registered tracer provider
|
|
12
|
+
* every span here is a no-op, so the package stays safe to load in bare Node
|
|
13
|
+
* processes (e.g. the sandbox `NODE_OPTIONS` preload).
|
|
14
|
+
*
|
|
15
|
+
* Attributes are intentionally lean — transport shape only (method, host,
|
|
16
|
+
* port, query-stripped URL, proxy mode, status). Tenant/task identity is
|
|
17
|
+
* inferred server-side from the request's JWT, or stamped globally by the
|
|
18
|
+
* host process's span processors, never duplicated here. Query strings are
|
|
19
|
+
* stripped because they can carry capability tokens (presigned URLs,
|
|
20
|
+
* share ids).
|
|
21
|
+
*/
|
|
22
|
+
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
23
|
+
export const PROXY_CALL_SPAN_NAME = "introspection-proxy-call";
|
|
24
|
+
export const PROXY_TRACER_NAME = "@introspection-sdk/introspection-proxy";
|
|
25
|
+
/**
|
|
26
|
+
* Parse `NO_PROXY`/`no_proxy` into normalized entries. Mirrors undici's
|
|
27
|
+
* `EnvHttpProxyAgent` semantics closely enough to decide span emission —
|
|
28
|
+
* undici still owns the actual routing decision.
|
|
29
|
+
*/
|
|
30
|
+
export function parseNoProxyEntries(env) {
|
|
31
|
+
const raw = env.NO_PROXY ?? env.no_proxy ?? "";
|
|
32
|
+
return raw
|
|
33
|
+
.split(",")
|
|
34
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
}
|
|
37
|
+
/** Whether `hostname[:port]` matches a `NO_PROXY` entry (i.e. goes direct). */
|
|
38
|
+
export function matchesNoProxy(hostname, port, entries) {
|
|
39
|
+
for (const raw of entries) {
|
|
40
|
+
if (raw === "*")
|
|
41
|
+
return true;
|
|
42
|
+
let entry = raw;
|
|
43
|
+
let entryPort = "";
|
|
44
|
+
const colon = entry.lastIndexOf(":");
|
|
45
|
+
if (colon !== -1 && !entry.slice(colon).includes("]")) {
|
|
46
|
+
entryPort = entry.slice(colon + 1);
|
|
47
|
+
entry = entry.slice(0, colon);
|
|
48
|
+
}
|
|
49
|
+
if (entryPort && entryPort !== port)
|
|
50
|
+
continue;
|
|
51
|
+
if (entry.startsWith("."))
|
|
52
|
+
entry = entry.slice(1);
|
|
53
|
+
if (hostname === entry || hostname.endsWith(`.${entry}`))
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/** Run `execute` inside an `introspection-proxy-call` CLIENT span. */
|
|
59
|
+
export function tracedProxyCall(mode, method, url, execute) {
|
|
60
|
+
const tracer = trace.getTracer(PROXY_TRACER_NAME);
|
|
61
|
+
const port = Number(url.port) || (url.protocol === "https:" ? 443 : 80);
|
|
62
|
+
return tracer.startActiveSpan(PROXY_CALL_SPAN_NAME, {
|
|
63
|
+
kind: SpanKind.CLIENT,
|
|
64
|
+
attributes: {
|
|
65
|
+
"http.request.method": method,
|
|
66
|
+
"server.address": url.hostname,
|
|
67
|
+
"server.port": port,
|
|
68
|
+
"url.full": url.origin + url.pathname,
|
|
69
|
+
"url.path": url.pathname,
|
|
70
|
+
"introspection.proxy.mode": mode,
|
|
71
|
+
},
|
|
72
|
+
}, async (span) => {
|
|
73
|
+
try {
|
|
74
|
+
const response = await execute();
|
|
75
|
+
span.setAttribute("http.response.status_code", response.status);
|
|
76
|
+
if (response.status >= 400) {
|
|
77
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
78
|
+
}
|
|
79
|
+
return response;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
span.recordException(err instanceof Error ? err : String(err));
|
|
83
|
+
span.setStatus({
|
|
84
|
+
code: SpanStatusCode.ERROR,
|
|
85
|
+
message: err instanceof Error ? err.message : String(err),
|
|
86
|
+
});
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
span.end();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=tracing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.js","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@introspection-sdk/introspection-proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Outbound HTTP proxy helpers for routing fetch-based clients through the Introspection egress proxy or a standard forward proxy",
|
|
6
6
|
"engines": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"@opentelemetry/api": "^1.9.0",
|
|
19
20
|
"undici": "^8.7.0"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@introspection-sdk/introspection-proxy`
|
|
3
3
|
*
|
|
4
|
-
* Lightweight, dependency-minimal
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Lightweight, dependency-minimal helpers for routing `fetch`-based clients
|
|
5
|
+
* through the Introspection egress credential-injection proxy or a standard
|
|
6
|
+
* forward proxy. Depends only on undici and the zero-dependency
|
|
7
|
+
* `@opentelemetry/api` (proxied requests emit `introspection-proxy-call`
|
|
8
|
+
* spans that no-op unless the host process registers a tracer provider — no
|
|
9
|
+
* OTel SDK or provider-SDK dependencies), so it can be used standalone (e.g.
|
|
10
|
+
* alongside the `introspection-pi` instrumentation wrapper) without pulling
|
|
11
|
+
* in the full `introspection-node` surface.
|
|
10
12
|
*/
|
|
11
13
|
export {
|
|
12
14
|
getProxyDispatcher,
|
|
@@ -15,3 +17,5 @@ export {
|
|
|
15
17
|
resolveForwardProxyUrl,
|
|
16
18
|
} from "./proxy.js";
|
|
17
19
|
export type { ProxyFetchOptions } from "./proxy.js";
|
|
20
|
+
export { PROXY_CALL_SPAN_NAME, PROXY_TRACER_NAME } from "./tracing.js";
|
|
21
|
+
export type { ProxyMode } from "./tracing.js";
|
package/src/proxy.ts
CHANGED
|
@@ -22,11 +22,23 @@ import {
|
|
|
22
22
|
fetch as undiciFetch,
|
|
23
23
|
type Dispatcher,
|
|
24
24
|
} from "undici";
|
|
25
|
+
import {
|
|
26
|
+
matchesNoProxy,
|
|
27
|
+
parseNoProxyEntries,
|
|
28
|
+
tracedProxyCall,
|
|
29
|
+
} from "./tracing.js";
|
|
25
30
|
|
|
26
31
|
export interface ProxyFetchOptions {
|
|
27
32
|
egressProxyUrl?: string;
|
|
28
33
|
egressProxyHosts?: string;
|
|
29
34
|
forwardProxyUrl?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Emit an `introspection-proxy-call` OTel span per proxied request
|
|
37
|
+
* (default true). Spans no-op unless the host process registered a tracer
|
|
38
|
+
* provider. Direct requests (no proxy, or `NO_PROXY` hosts) never get a
|
|
39
|
+
* span regardless of this flag.
|
|
40
|
+
*/
|
|
41
|
+
tracing?: boolean;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
function resolveEgressUrl(options: ProxyFetchOptions): string | undefined {
|
|
@@ -127,8 +139,14 @@ export function createProxyFetch(
|
|
|
127
139
|
|
|
128
140
|
if (!egress && !forward) return base;
|
|
129
141
|
|
|
142
|
+
const tracing = options.tracing ?? true;
|
|
143
|
+
// Snapshot NO_PROXY once, like EnvHttpProxyAgent does at construction. Used
|
|
144
|
+
// only to decide span emission — undici owns the actual routing.
|
|
145
|
+
const noProxyEntries = parseNoProxyEntries(process.env);
|
|
146
|
+
|
|
130
147
|
return (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
|
|
131
|
-
const
|
|
148
|
+
const url = new URL(toUrlString(input));
|
|
149
|
+
const hostname = url.hostname.toLowerCase();
|
|
132
150
|
|
|
133
151
|
const useEgress =
|
|
134
152
|
!!egress && egressHosts.size > 0 && egressHosts.has(hostname);
|
|
@@ -161,10 +179,31 @@ export function createProxyFetch(
|
|
|
161
179
|
target = downgradeToHttp(target);
|
|
162
180
|
}
|
|
163
181
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
182
|
+
const execute = () =>
|
|
183
|
+
undiciFetch(
|
|
184
|
+
target as unknown as Parameters<typeof undiciFetch>[0],
|
|
185
|
+
opts as unknown as Parameters<typeof undiciFetch>[1],
|
|
186
|
+
) as unknown as Promise<Response>;
|
|
187
|
+
|
|
188
|
+
// A forward-dispatched request to a NO_PROXY host goes direct inside
|
|
189
|
+
// EnvHttpProxyAgent — no proxy hop, so no proxy span (in-cluster clients
|
|
190
|
+
// trace those calls themselves as `introspection-api-call`).
|
|
191
|
+
const viaProxy =
|
|
192
|
+
useEgress || !matchesNoProxy(hostname, url.port, noProxyEntries);
|
|
193
|
+
if (!tracing || !viaProxy) return execute();
|
|
194
|
+
|
|
195
|
+
const method = (
|
|
196
|
+
init?.method ??
|
|
197
|
+
(typeof Request !== "undefined" && input instanceof Request
|
|
198
|
+
? input.method
|
|
199
|
+
: "GET")
|
|
200
|
+
).toUpperCase();
|
|
201
|
+
return tracedProxyCall(
|
|
202
|
+
useEgress ? "egress" : "forward",
|
|
203
|
+
method,
|
|
204
|
+
url,
|
|
205
|
+
execute,
|
|
206
|
+
);
|
|
168
207
|
};
|
|
169
208
|
}
|
|
170
209
|
|
package/src/tracing.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry span instrumentation for proxied requests.
|
|
3
|
+
*
|
|
4
|
+
* Emits one `introspection-proxy-call` CLIENT span per request that is
|
|
5
|
+
* actually routed through a proxy (egress credential-injection or forward
|
|
6
|
+
* CONNECT). Requests that go direct — no proxy configured, or the host is
|
|
7
|
+
* excluded via `NO_PROXY` — deliberately get no span: in-cluster callers
|
|
8
|
+
* (`NO_PROXY` covers the DP API) already trace those calls at the client
|
|
9
|
+
* layer, so proxy spans and client-layer spans stay mutually exclusive.
|
|
10
|
+
*
|
|
11
|
+
* Depends only on `@opentelemetry/api`: without a registered tracer provider
|
|
12
|
+
* every span here is a no-op, so the package stays safe to load in bare Node
|
|
13
|
+
* processes (e.g. the sandbox `NODE_OPTIONS` preload).
|
|
14
|
+
*
|
|
15
|
+
* Attributes are intentionally lean — transport shape only (method, host,
|
|
16
|
+
* port, query-stripped URL, proxy mode, status). Tenant/task identity is
|
|
17
|
+
* inferred server-side from the request's JWT, or stamped globally by the
|
|
18
|
+
* host process's span processors, never duplicated here. Query strings are
|
|
19
|
+
* stripped because they can carry capability tokens (presigned URLs,
|
|
20
|
+
* share ids).
|
|
21
|
+
*/
|
|
22
|
+
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
23
|
+
|
|
24
|
+
export const PROXY_CALL_SPAN_NAME = "introspection-proxy-call";
|
|
25
|
+
export const PROXY_TRACER_NAME = "@introspection-sdk/introspection-proxy";
|
|
26
|
+
|
|
27
|
+
export type ProxyMode = "egress" | "forward";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parse `NO_PROXY`/`no_proxy` into normalized entries. Mirrors undici's
|
|
31
|
+
* `EnvHttpProxyAgent` semantics closely enough to decide span emission —
|
|
32
|
+
* undici still owns the actual routing decision.
|
|
33
|
+
*/
|
|
34
|
+
export function parseNoProxyEntries(env: NodeJS.ProcessEnv): string[] {
|
|
35
|
+
const raw = env.NO_PROXY ?? env.no_proxy ?? "";
|
|
36
|
+
return raw
|
|
37
|
+
.split(",")
|
|
38
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Whether `hostname[:port]` matches a `NO_PROXY` entry (i.e. goes direct). */
|
|
43
|
+
export function matchesNoProxy(
|
|
44
|
+
hostname: string,
|
|
45
|
+
port: string,
|
|
46
|
+
entries: string[],
|
|
47
|
+
): boolean {
|
|
48
|
+
for (const raw of entries) {
|
|
49
|
+
if (raw === "*") return true;
|
|
50
|
+
let entry = raw;
|
|
51
|
+
let entryPort = "";
|
|
52
|
+
const colon = entry.lastIndexOf(":");
|
|
53
|
+
if (colon !== -1 && !entry.slice(colon).includes("]")) {
|
|
54
|
+
entryPort = entry.slice(colon + 1);
|
|
55
|
+
entry = entry.slice(0, colon);
|
|
56
|
+
}
|
|
57
|
+
if (entryPort && entryPort !== port) continue;
|
|
58
|
+
if (entry.startsWith(".")) entry = entry.slice(1);
|
|
59
|
+
if (hostname === entry || hostname.endsWith(`.${entry}`)) return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Run `execute` inside an `introspection-proxy-call` CLIENT span. */
|
|
65
|
+
export function tracedProxyCall(
|
|
66
|
+
mode: ProxyMode,
|
|
67
|
+
method: string,
|
|
68
|
+
url: URL,
|
|
69
|
+
execute: () => Promise<Response>,
|
|
70
|
+
): Promise<Response> {
|
|
71
|
+
const tracer = trace.getTracer(PROXY_TRACER_NAME);
|
|
72
|
+
const port = Number(url.port) || (url.protocol === "https:" ? 443 : 80);
|
|
73
|
+
return tracer.startActiveSpan(
|
|
74
|
+
PROXY_CALL_SPAN_NAME,
|
|
75
|
+
{
|
|
76
|
+
kind: SpanKind.CLIENT,
|
|
77
|
+
attributes: {
|
|
78
|
+
"http.request.method": method,
|
|
79
|
+
"server.address": url.hostname,
|
|
80
|
+
"server.port": port,
|
|
81
|
+
"url.full": url.origin + url.pathname,
|
|
82
|
+
"url.path": url.pathname,
|
|
83
|
+
"introspection.proxy.mode": mode,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
async (span) => {
|
|
87
|
+
try {
|
|
88
|
+
const response = await execute();
|
|
89
|
+
span.setAttribute("http.response.status_code", response.status);
|
|
90
|
+
if (response.status >= 400) {
|
|
91
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
92
|
+
}
|
|
93
|
+
return response;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
span.recordException(err instanceof Error ? err : String(err));
|
|
96
|
+
span.setStatus({
|
|
97
|
+
code: SpanStatusCode.ERROR,
|
|
98
|
+
message: err instanceof Error ? err.message : String(err),
|
|
99
|
+
});
|
|
100
|
+
throw err;
|
|
101
|
+
} finally {
|
|
102
|
+
span.end();
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
);
|
|
106
|
+
}
|