From 8e1043ab06dd6f8961cf2aa78deb6ee6dbd89868 Mon Sep 17 00:00:00 2001 From: Daniel Nowak <13685818+lowlyocean@users.noreply.github.com> Date: Mon, 14 Sep 2026 08:22:39 -0400 Subject: [PATCH] Fix timeout reset upon progress notification --- packages/core-internal/src/shared/protocol.ts | 1 + .../test/shared/protocol.test.ts | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/core-internal/src/shared/protocol.ts b/packages/core-internal/src/shared/protocol.ts index 637be389aa..073935ef4a 100644 --- a/packages/core-internal/src/shared/protocol.ts +++ b/packages/core-internal/src/shared/protocol.ts @@ -765,6 +765,7 @@ export abstract class Protocol { } clearTimeout(info.timeoutId); + info.startTime = Date.now(); info.timeoutId = setTimeout(info.onTimeout, info.timeout); return true; } diff --git a/packages/core-internal/test/shared/protocol.test.ts b/packages/core-internal/test/shared/protocol.test.ts index 2fb0f64813..abfcde5a97 100644 --- a/packages/core-internal/test/shared/protocol.test.ts +++ b/packages/core-internal/test/shared/protocol.test.ts @@ -458,7 +458,7 @@ describe('protocol tests', () => { onprogress: onProgressMock }); - // First progress notification should work + // First progress notification should work and reset the timeout window vi.advanceTimersByTime(80); if (transport.onmessage) { transport.onmessage({ @@ -476,7 +476,9 @@ describe('protocol tests', () => { progress: 50, total: 100 }); - vi.advanceTimersByTime(80); + + // Second progress at 101ms later still within maxTotalTimeout (150ms window) + vi.advanceTimersByTime(101); if (transport.onmessage) { transport.onmessage({ jsonrpc: '2.0', @@ -488,8 +490,23 @@ describe('protocol tests', () => { } }); } + await Promise.resolve(); + + // Third progress at 151ms after the second — exceeds maxTotalTimeout + vi.advanceTimersByTime(151); + if (transport.onmessage) { + transport.onmessage({ + jsonrpc: '2.0', + method: 'notifications/progress', + params: { + progressToken: 0, + progress: 90, + total: 100 + } + }); + } await expect(requestPromise).rejects.toThrow('Maximum total timeout exceeded'); - expect(onProgressMock).toHaveBeenCalledTimes(1); + expect(onProgressMock).toHaveBeenCalledTimes(2); }); test('should timeout if no progress received within timeout period', async () => {