Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clients/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ function App() {
fetchRequestLogState?.destroy();
stderrLogState?.destroy();

const { environment } = createWebEnvironment(
const { environment, logger } = createWebEnvironment(
getAuthToken(),
redirectUrlProvider,
onBeforeOAuthRedirect,
Expand Down Expand Up @@ -1221,6 +1221,7 @@ function App() {
// reads the current log.
const nextFetchLog = new FetchRequestLogState(client, {
sessionStorage: sessionStorageAdapter,
logger,
...(sessionId && { sessionId }),
});
fetchLogRef.current = nextFetchLog;
Expand Down
12 changes: 12 additions & 0 deletions clients/web/src/test/core/mcp/state/fetchRequestLogState.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, it, expect, beforeEach, vi } from "vitest";
import type pino from "pino";
import type { FetchRequestEntry } from "@inspector/core/mcp/types";
import { FetchRequestLogState } from "@inspector/core/mcp/state/fetchRequestLogState";
import { FakeInspectorClient } from "@inspector/core/mcp/__tests__/fakeInspectorClient";
Expand Down Expand Up @@ -121,6 +122,9 @@ describe("FetchRequestLogState", () => {
});

it("ignores fetchRequestBodyUpdate for unknown ids", () => {
const logger = { debug: vi.fn() } as unknown as pino.Logger;
state.destroy();
state = new FetchRequestLogState(client, { logger });
client.dispatchTypedEvent("fetchRequest", entry("a"));
let changes = 0;
state.addEventListener("fetchRequestsChange", () => changes++);
Expand All @@ -129,6 +133,14 @@ describe("FetchRequestLogState", () => {
responseBody: "x",
});
expect(changes).toBe(0);
expect(logger.debug).toHaveBeenCalledWith(
{
id: "nonexistent",
storedFetchRequestCount: 1,
maxFetchRequests: 1000,
},
"Dropped fetch request body update because request entry is no longer in log",
);
});

it("does NOT clear on connect or disconnect", () => {
Expand Down
22 changes: 18 additions & 4 deletions core/mcp/state/fetchRequestLogState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/

import type { InspectorClientProtocol } from "../inspectorClientProtocol.js";
import type pino from "pino";
import type { FetchRequestEntry } from "../types.js";
import type {
InspectorClientStorage,
Expand All @@ -24,6 +25,7 @@ import {
TypedEventTarget,
type TypedEventGeneric,
} from "../typedEventTarget.js";
import { silentLogger } from "../../logging/logger.js";

export interface FetchRequestLogStateEventMap {
fetchRequest: FetchRequestEntry;
Expand All @@ -44,20 +46,24 @@ export interface FetchRequestLogStateOptions {
sessionStorage?: InspectorClientStorage;
/** Session ID for load/save; required for sessionStorage to have effect. */
sessionId?: string;
/** Logger used for diagnostic events that do not affect UI state. */
logger?: pino.Logger;
}

export class FetchRequestLogState extends TypedEventTarget<FetchRequestLogStateEventMap> {
private fetchRequests: FetchRequestEntry[] = [];
private client: InspectorClientProtocol | null = null;
private unsubscribe: (() => void) | null = null;
private readonly maxFetchRequests: number;
private readonly logger: pino.Logger;

constructor(
client: InspectorClientProtocol,
options: FetchRequestLogStateOptions = {},
) {
super();
this.maxFetchRequests = options.maxFetchRequests ?? 1000;
this.logger = options.logger ?? silentLogger;
this.client = client;

const onFetchRequest = (
Expand Down Expand Up @@ -87,7 +93,17 @@ export class FetchRequestLogState extends TypedEventTarget<FetchRequestLogStateE
): void => {
const { id, responseBody } = event.detail;
const idx = this.fetchRequests.findIndex((e) => e.id === id);
if (idx === -1) return;
if (idx === -1) {
this.logger.debug(
{
id,
storedFetchRequestCount: this.fetchRequests.length,
maxFetchRequests: this.maxFetchRequests,
},
"Dropped fetch request body update because request entry is no longer in log",
);
return;
}
this.fetchRequests[idx] = {
...this.fetchRequests[idx]!,
responseBody,
Expand Down Expand Up @@ -192,9 +208,7 @@ export class FetchRequestLogState extends TypedEventTarget<FetchRequestLogStateE
if (restored.length === 0) return;
const merged = [...restored, ...this.fetchRequests];
this.fetchRequests =
this.maxFetchRequests > 0
? merged.slice(-this.maxFetchRequests)
: merged;
this.maxFetchRequests > 0 ? merged.slice(-this.maxFetchRequests) : merged;
this.dispatchTypedEvent("fetchRequestsChange", this.getFetchRequests());
}

Expand Down