diff --git a/.changeset/clear-stream-timeout.md b/.changeset/clear-stream-timeout.md new file mode 100644 index 0000000000..cf9d792756 --- /dev/null +++ b/.changeset/clear-stream-timeout.md @@ -0,0 +1,5 @@ +--- +"react-router": patch +--- + +fix: clear timeout when turbo-stream encoding completes diff --git a/contributors.yml b/contributors.yml index 0966b71f78..daa45d0f08 100644 --- a/contributors.yml +++ b/contributors.yml @@ -277,6 +277,7 @@ - maximevtush - maxpou - mcansh +- mcollina - MeatSim - MenouerBetty - Methuselah96 diff --git a/packages/react-router/lib/server-runtime/single-fetch.ts b/packages/react-router/lib/server-runtime/single-fetch.ts index 9785c5176e..71e469b5fd 100644 --- a/packages/react-router/lib/server-runtime/single-fetch.ts +++ b/packages/react-router/lib/server-runtime/single-fetch.ts @@ -385,10 +385,14 @@ export function encodeViaTurboStream( () => controller.abort(new Error("Server Timeout")), typeof streamTimeout === "number" ? streamTimeout : 4950, ); - requestSignal.addEventListener("abort", () => clearTimeout(timeoutId)); + + let clearStreamTimeout = () => clearTimeout(timeoutId); + + requestSignal.addEventListener("abort", clearStreamTimeout); return encode(data, { signal: controller.signal, + onComplete: clearStreamTimeout, plugins: [ (value) => { // Even though we sanitized errors on context.errors prior to responding, diff --git a/packages/react-router/vendor/turbo-stream-v2/turbo-stream.ts b/packages/react-router/vendor/turbo-stream-v2/turbo-stream.ts index 9c6d8529e1..660072aa42 100644 --- a/packages/react-router/vendor/turbo-stream-v2/turbo-stream.ts +++ b/packages/react-router/vendor/turbo-stream-v2/turbo-stream.ts @@ -138,9 +138,10 @@ export function encode( plugins?: EncodePlugin[]; postPlugins?: EncodePlugin[]; signal?: AbortSignal; + onComplete?: () => void; }, ) { - const { plugins, postPlugins, signal } = options ?? {}; + const { plugins, postPlugins, signal, onComplete } = options ?? {}; const encoder: ThisEncode = { deferred: {}, @@ -274,6 +275,7 @@ export function encode( } await Promise.all(Object.values(encoder.deferred)); + onComplete?.(); controller.close(); }, });