Skip to content

Commit 9a8bf5b

Browse files
fix(client): feature-detect AbortSignal.any (Node >=20 floor includes 20.0–20.2)
AbortSignal.any landed in Node 20.3; the package engines floor is >=20. Feature-detect and fall back to a small manual combinator (a controller that aborts on the first of the two inputs, propagating reason). The native path stays the default. Engines is intentionally NOT bumped.
1 parent 254616d commit 9a8bf5b

1 file changed

Lines changed: 23 additions & 2 deletions

File tree

packages/client/src/client/streamableHttp.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,27 @@ export type StreamableHTTPClientTransportOptions = {
173173
protocolVersion?: string;
174174
};
175175

176+
/**
177+
* `AbortSignal.any` with a manual fallback. `AbortSignal.any` landed in
178+
* Node 20.3; this package's `engines` floor is `>=20`, so 20.0–20.2 must be
179+
* served by the fallback combinator (a controller that aborts on the first
180+
* of `a` or `b`). The native path is preferred because it propagates the
181+
* originating signal's `reason` and participates in GC the way the spec
182+
* defines.
183+
*/
184+
function anySignal(a: AbortSignal, b: AbortSignal): AbortSignal {
185+
if (typeof AbortSignal.any === 'function') {
186+
return AbortSignal.any([a, b]);
187+
}
188+
const controller = new AbortController();
189+
if (a.aborted) return (controller.abort(a.reason), controller.signal);
190+
if (b.aborted) return (controller.abort(b.reason), controller.signal);
191+
const forward = (source: AbortSignal) => () => controller.abort(source.reason);
192+
a.addEventListener('abort', forward(a), { once: true });
193+
b.addEventListener('abort', forward(b), { once: true });
194+
return controller.signal;
195+
}
196+
176197
/**
177198
* Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
178199
* It will connect to a server using HTTP `POST` for sending messages and HTTP `GET` with Server-Sent Events
@@ -592,11 +613,11 @@ export class StreamableHTTPClientTransport implements Transport {
592613
// Per-request abort: when the caller supplies a request-scoped
593614
// signal (the `subscriptions/listen` driver), aborting it cancels
594615
// this POST and its SSE response stream without closing the
595-
// transport. AbortSignal.any is the standard combinator.
616+
// transport.
596617
const transportSignal = this._abortController?.signal;
597618
const signal =
598619
options?.requestSignal !== undefined && transportSignal !== undefined
599-
? AbortSignal.any([transportSignal, options.requestSignal])
620+
? anySignal(transportSignal, options.requestSignal)
600621
: (options?.requestSignal ?? transportSignal);
601622
const init = {
602623
...this._requestInit,

0 commit comments

Comments
 (0)