fix: preserve lastEventId in SSE path and add proxy heartbeat (#1041)

* fix: preserve lastEventId in SSE path and add proxy heartbeat

- Extract event.id from SSE stream events in event-pipeline.ts so that
  reconnects carry the correct Last-Event-ID header for gapless replay.
- Emit :heartbeat comment every 20s in the direct SSE proxy to keep
  the UI heartbeat watchdog from aborting idle connections.

* fix: handle SSE metadata through SDK callback

* Guard SSE proxy heartbeats

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Jinwoo An (안진우)
2026-04-27 14:16:44 +03:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent 43c92babc3
commit 6470d9d205
3 changed files with 85 additions and 2 deletions
+7
View File
@@ -340,6 +340,12 @@ export function createEventPipeline(input: EventPipelineInput) {
const events = await sdk.global.event({
signal,
...(lastEventId && lastEventId.length > 0 ? { headers: { "Last-Event-ID": lastEventId } } : {}),
onSseEvent: (event: { id?: unknown }) => {
resetHeartbeat()
if (typeof event.id === "string" && event.id.length > 0) {
lastEventId = event.id
}
},
onSseError: (error: unknown) => {
if (isAbortError(error)) return
if (streamErrorLogged) return
@@ -356,6 +362,7 @@ export function createEventPipeline(input: EventPipelineInput) {
for await (const event of events.stream) {
resetHeartbeat()
streamErrorLogged = false
const payload = resolveEventPayload((event as { payload?: Event }).payload ?? event)
if (!payload) {
continue