SPB Git forge

spb/polyllm

Public
15commits 1branches 0releases
2.2 MBsize
maindefault branch
13 days agolast push
TypeScript 97.4% SQL 1% JavaScript 0.9% CSS 0.6%
1.8 KB · 58 lines typescript
Raw Blame History
1/**2 * Minimal SSE writer for Route Handlers. Each event is one JSON object per `data:` line.3 * Heartbeats keep ngrok / proxies from closing idle connections during long reasoning.4 */5export function sseResponse(run: (emit: (event: unknown) => void, signal: AbortSignal) => Promise<void>, opts: { requestId?: string; heartbeatMs?: number } = {}): Response {6  const encoder = new TextEncoder();7  const abort = new AbortController();8  let closed = false;9  const stream = new ReadableStream<Uint8Array>({10    start(controller) {11      const emit = (event: unknown) => {12        if (closed) return;13        try {14          controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`));15        } catch {16          closed = true;17        }18      };19      const hb = setInterval(() => {20        if (closed) return;21        try {22          controller.enqueue(encoder.encode(`: ping\n\n`));23        } catch {24          closed = true;25        }26      }, opts.heartbeatMs ?? 15_000);27      run(emit, abort.signal)28        .catch((e) => {29          emit({ type: "error", error: { code: "INTERNAL_ERROR", message: (e as Error)?.message ?? "Internal error", retryable: false } });30        })31        .finally(() => {32          clearInterval(hb);33          if (!closed) {34            closed = true;35            try {36              controller.close();37            } catch {38              /* already closed */39            }40          }41        });42    },43    cancel() {44      closed = true;45      abort.abort();46    },47  });48  return new Response(stream, {49    headers: {50      "Content-Type": "text/event-stream; charset=utf-8",51      "Cache-Control": "no-cache, no-transform",52      Connection: "keep-alive",53      "X-Accel-Buffering": "no",54      ...(opts.requestId ? { "X-Request-Id": opts.requestId } : {}),55    },56  });57}58