Canceling the webhook SSE response does not reliably release its registered client or heartbeat timer.
At current main (76100aa), app/api/webhook/route.ts uses cancel(controller) and reads controller._keepAlive. The Web Streams cancel callback receives the cancellation reason; the controller is supplied to start.
Reproduced locally with the real route and broadcaster, native Node Web Streams, and controlled timers:
await response.body.cancel() rejects with Cannot read properties of undefined (reading '_keepAlive').
- Canceling with a string or Error leaves the original controller registered and its timer scheduled.
- A failed heartbeat clears its timer but leaves the controller registered until a later broadcast removes it.
Expected: cancellation immediately removes that connection and clears its heartbeat without affecting other clients.
I plan a focused fix that retains the controller and timer in the GET handler's closure and shares cleanup between cancellation and heartbeat failure. Regression tests will cover cancellation reasons, two independent clients, replay, broadcasts, and heartbeat failure. This was reproduced offline; no Ring credentials or device were used.
Reference: https://streams.spec.whatwg.org/#underlying-source-api
Canceling the webhook SSE response does not reliably release its registered client or heartbeat timer.
At current main (
76100aa),app/api/webhook/route.tsusescancel(controller)and readscontroller._keepAlive. The Web Streamscancelcallback receives the cancellation reason; the controller is supplied tostart.Reproduced locally with the real route and broadcaster, native Node Web Streams, and controlled timers:
await response.body.cancel()rejects withCannot read properties of undefined (reading '_keepAlive').Expected: cancellation immediately removes that connection and clears its heartbeat without affecting other clients.
I plan a focused fix that retains the controller and timer in the GET handler's closure and shares cleanup between cancellation and heartbeat failure. Regression tests will cover cancellation reasons, two independent clients, replay, broadcasts, and heartbeat failure. This was reproduced offline; no Ring credentials or device were used.
Reference: https://streams.spec.whatwg.org/#underlying-source-api