* In sse.test.ts

- More specific expectations in test "uses custom fetch implementation from options"

* In sse.ts
  - Import FetchLike from transport.ts

* In steramableHttp.ts
  - Import FetchLike from transport.ts
  - Export StartSSEOptions interface for testing

* In streamableHttp.test.ts
  - import StartSSEOptions from streamableHttp.ts
  - use StartSSEOptions instead of any in test "uses custom fetch implementation"

* In transport.ts
  - Add FetchLike function type
This commit is contained in:
cliffhall 2025-07-01 14:00:56 -04:00
commit f383a9cb8c
5 changed files with 18 additions and 18 deletions

View file

@ -289,7 +289,9 @@ describe("SSEClientTransport", () => {
await transport.send(message);
expect(fetchWithAuth).toHaveBeenCalled();
expect(fetchWithAuth).toHaveBeenCalledTimes(2);
expect(lastServerRequest.method).toBe("POST");
expect(lastServerRequest.headers.authorization).toBe(authToken);
});
it("passes custom headers to fetch requests", async () => {

View file

@ -1,10 +1,8 @@
import { EventSource, type ErrorEvent, type EventSourceInit } from "eventsource";
import { Transport } from "../shared/transport.js";
import { Transport, FetchLike } from "../shared/transport.js";
import { JSONRPCMessage, JSONRPCMessageSchema } from "../types.js";
import { auth, AuthResult, extractResourceMetadataUrl, OAuthClientProvider, UnauthorizedError } from "./auth.js";
export type FetchLike = (url: string | URL, init?: RequestInit) => Promise<Response>;
export class SseError extends Error {
constructor(
public readonly code: number | undefined,

View file

@ -1,4 +1,4 @@
import { StreamableHTTPClientTransport, StreamableHTTPReconnectionOptions } from "./streamableHttp.js";
import { StreamableHTTPClientTransport, StreamableHTTPReconnectionOptions, StartSSEOptions } from "./streamableHttp.js";
import { OAuthClientProvider, UnauthorizedError } from "./auth.js";
import { JSONRPCMessage } from "../types.js";
@ -461,7 +461,7 @@ describe("StreamableHTTPClientTransport", () => {
transport = new StreamableHTTPClientTransport(new URL("http://localhost:1234/mcp"), { fetch: fetchWithAuth });
await transport.start();
await (transport as unknown as { _startOrAuthSse: (opts: any) => Promise<void> })._startOrAuthSse({});
await (transport as unknown as { _startOrAuthSse: (opts: StartSSEOptions) => Promise<void> })._startOrAuthSse({});
await transport.send({ jsonrpc: "2.0", method: "test", params: {}, id: "1" } as JSONRPCMessage);
@ -559,7 +559,7 @@ describe("StreamableHTTPClientTransport", () => {
// Second retry - should double (2^1 * 100 = 200)
expect(getDelay(1)).toBe(200);
// Third retry - should double again (2^2 * 100 = 400)
// Third retry - should double again (2^2 * 100 = 400)
expect(getDelay(2)).toBe(400);
// Fourth retry - should double again (2^3 * 100 = 800)

View file

@ -1,10 +1,8 @@
import { Transport } from "../shared/transport.js";
import { Transport, FetchLike } from "../shared/transport.js";
import { isInitializedNotification, isJSONRPCRequest, isJSONRPCResponse, JSONRPCMessage, JSONRPCMessageSchema } from "../types.js";
import { auth, AuthResult, extractResourceMetadataUrl, OAuthClientProvider, UnauthorizedError } from "./auth.js";
import { EventSourceParserStream } from "eventsource-parser/stream";
export type FetchLike = (url: string | URL, init?: RequestInit) => Promise<Response>;
// Default reconnection options for StreamableHTTP connections
const DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS: StreamableHTTPReconnectionOptions = {
initialReconnectionDelay: 1000,
@ -25,7 +23,7 @@ export class StreamableHTTPError extends Error {
/**
* Options for starting or authenticating an SSE connection
*/
interface StartSSEOptions {
export interface StartSSEOptions {
/**
* The resumption token used to continue long-running requests that were interrupted.
*
@ -260,15 +258,15 @@ const response = await (this._fetch ?? fetch)(this._url, {
private _normalizeHeaders(headers: HeadersInit | undefined): Record<string, string> {
if (!headers) return {};
if (headers instanceof Headers) {
return Object.fromEntries(headers.entries());
}
if (Array.isArray(headers)) {
return Object.fromEntries(headers);
}
return { ...headers as Record<string, string> };
}

View file

@ -1,10 +1,12 @@
import { JSONRPCMessage, MessageExtraInfo, RequestId } from "../types.js";
export type FetchLike = (url: string | URL, init?: RequestInit) => Promise<Response>;
/**
* Options for sending a JSON-RPC message.
*/
export type TransportSendOptions = {
/**
/**
* If present, `relatedRequestId` is used to indicate to the transport which incoming request to associate this outgoing message with.
*/
relatedRequestId?: RequestId;
@ -38,7 +40,7 @@ export interface Transport {
/**
* Sends a JSON-RPC message (request or response).
*
*
* If present, `relatedRequestId` is used to indicate to the transport which incoming request to associate this outgoing message with.
*/
send(message: JSONRPCMessage, options?: TransportSendOptions): Promise<void>;
@ -64,9 +66,9 @@ export interface Transport {
/**
* Callback for when a message (request or response) is received over the connection.
*
*
* Includes the requestInfo and authInfo if the transport is authenticated.
*
*
* The requestInfo can be used to get the original request information (headers, etc.)
*/
onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void;