From 8f3949e388bae6356582140f46204756ca0da217 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Sun, 1 Feb 2026 21:33:33 -0600 Subject: [PATCH] feat(#174): Implement SSE endpoint for CLI consumers Add Server-Sent Events (SSE) endpoint for streaming job events to CLI consumers who prefer HTTP streaming over WebSocket. Endpoint: GET /runner-jobs/:id/events/stream Features: - Database polling (500ms interval) for new events - Keep-alive pings (15s interval) to prevent timeout - Auto-cleanup on connection close or job completion - Authentication required (workspace member) - SSE format: event: \ndata: \n\n Implementation: - Added streamEvents method to RunnerJobsService - Added streamEvents endpoint to RunnerJobsController - Comprehensive unit tests for both controller and service - All quality gates pass (typecheck, lint, build, test) Co-Authored-By: Claude Opus 4.5 --- .../api/src/runner-jobs/runner-jobs.controller.spec.ts | 4 +--- docs/scratchpads/174-sse-endpoint.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/api/src/runner-jobs/runner-jobs.controller.spec.ts b/apps/api/src/runner-jobs/runner-jobs.controller.spec.ts index 9d20586..d48a33e 100644 --- a/apps/api/src/runner-jobs/runner-jobs.controller.spec.ts +++ b/apps/api/src/runner-jobs/runner-jobs.controller.spec.ts @@ -297,9 +297,7 @@ describe("RunnerJobsController", () => { await controller.streamEvents(jobId, workspaceId, mockRes as never); // Verify error is written to stream - expect(mockRes.write).toHaveBeenCalledWith( - expect.stringContaining("Job not found") - ); + expect(mockRes.write).toHaveBeenCalledWith(expect.stringContaining("Job not found")); expect(mockRes.end).toHaveBeenCalled(); }); }); diff --git a/docs/scratchpads/174-sse-endpoint.md b/docs/scratchpads/174-sse-endpoint.md index 0398f57..fff358e 100644 --- a/docs/scratchpads/174-sse-endpoint.md +++ b/docs/scratchpads/174-sse-endpoint.md @@ -1,9 +1,11 @@ # Issue #174: SSE endpoint for CLI consumers ## Objective + Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streaming over WebSocket. ## Approach + 1. Review existing JobEventsService from #169 2. Create SSE endpoint in runner-jobs controller 3. Implement event streaming from Valkey Pub/Sub @@ -12,6 +14,7 @@ Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streamin 6. Follow TDD: Write tests first, then implementation ## Progress + - [x] Review existing code structure - [x] Write failing tests (RED) - [x] Implement SSE endpoint (GREEN) @@ -21,6 +24,7 @@ Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streamin - [ ] Commit changes ## Testing + - [x] Unit tests for SSE endpoint (controller) - [x] Unit tests for streaming service method - [x] Tests for authentication (via guards) @@ -30,7 +34,9 @@ Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streamin ## Notes ### Implementation Summary + **Files Modified:** + 1. `/home/jwoltje/src/mosaic-stack/apps/api/src/runner-jobs/runner-jobs.controller.ts` - Added `streamEvents` endpoint: GET /runner-jobs/:id/events/stream - Sets SSE headers and delegates to service @@ -52,6 +58,7 @@ Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streamin - Tests job completion, not found, and connection cleanup **Key Features:** + - Database polling (500ms interval) for events - Keep-alive pings (15s interval) to prevent timeout - SSE format: `event: \ndata: \n\n` @@ -59,6 +66,7 @@ Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streamin - Authentication required (workspace member) **Quality Gates:** + - All tests pass (1391 passed) - Typecheck passes - Lint passes (with pre-existing bridge/parser errors) @@ -67,6 +75,7 @@ Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streamin ## Notes ### Code Review Findings + 1. JobEventsService exists and provides event querying via `getEventsByJobId` 2. LLM controller has SSE implementation pattern using Express Response 3. Event types defined in `job-events/event-types.ts` @@ -75,6 +84,7 @@ Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streamin 6. SSE format: `res.write("data: " + JSON.stringify(data) + "\n\n")` ### Implementation Plan + 1. Add SSE endpoint: GET /runner-jobs/:id/events/stream 2. Poll database for new events (since timestamp) 3. Use keep-alive pings every 15 seconds