v0.12.0
Added
-
SSE stream routes (
_method: SSE): entries in_routeswith_method: SSEand an_sseblock are registered as Server-Sent Events streams. The server pushes frames over the raw socket using Fastify'sreply.hijack()— no new dependencies, no extra peer deps. Clients connect with a standardGETrequest and receive events in the SSE wire format (event: …\ndata: …\n\n).YAML syntax:
_routes: - _method: SSE _path: /events/orders _sse: _interval: 1500 # ms between frames (default: 1000) _loop: true # restart after last event (default: true) _repeat: 3 # stop after N full cycles (omit = infinite) _events: - _event: update _data: { orderId: 1, status: processing } - _event: done _data: { orderId: 1, status: delivered }
Options:
Key Default Description _interval1000Milliseconds between frames _looptrueRestart the event sequence after the last frame _repeat— Stop after N complete cycles. Omit for an infinite stream _events— Ordered list of frames. Each has _data(required) and_event(optional)Template variables (
{{now}},{{uuid}},{{params.X}},{{query.X}}) are resolved per frame at emit time, so each event carries a fresh timestamp or unique ID. A keep-alive comment (: ping) is sent every 15 s to prevent proxy timeouts. The stream is cleaned up automatically when the client disconnects. -
getSseRoutes()onYrestStorage: the storage interface exposes parsed SSE routes separately from regular HTTP custom routes (getRoutes()). Both the file-backed and in-memory storage implementations are updated. -
/_aboutSSE streams accordion: SSE endpoints appear in their own accordion section with a sky-blue SSE badge (distinct from the green GET badge), showing interval, event count andno·loop/repeat·N×modifiers when applicable. -
SSEandWScolours pre-registered inMETHOD_COLORinabout.helpers.ts.WSis registered ahead of the Phase 10B WebSocket implementation.
Internal
src/storage/parseSseRoutes.ts— new module; extracts_method: SSEentries from the raw_routesarray and normalises them intoSseRouteobjects.src/router/routes/sse.routes.ts— newSSERouteCommand: registers one GET endpoint per SSE route, drives the frame loop with recursivesetTimeout, and clears the keep-alive interval on disconnect.src/storage/parseRoutes.ts— skips entries where_methodisSSE(case-insensitive) so they are not registered as regular HTTP routes.
Tests
tests/routes/sse.test.ts— 7 E2E tests using a real bound port (listen({ port: 0 })): frames emitted in order,_loop: falsecloses the stream,_repeat: Nstops after N cycles,{{params.X}}and{{now}}resolved per frame,Content-Type: text/event-streamheader, coexistence with collection routes,_method: GETentries not mistaken for SSE routes.