{"id":14989434,"url":"https://github.com/andywer/http-event-stream","last_synced_at":"2025-06-23T01:09:07.740Z","repository":{"id":37706383,"uuid":"148980948","full_name":"andywer/http-event-stream","owner":"andywer","description":"📡 Modern spec-compliant Server Sent Events stream implementation.","archived":false,"fork":false,"pushed_at":"2023-01-05T14:15:55.000Z","size":799,"stargazers_count":19,"open_issues_count":7,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-13T01:11:15.636Z","etag":null,"topics":["events","expressjs","http","koajs","nodejs","rest","server-sent-events","sse","stream"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andywer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-16T09:27:40.000Z","updated_at":"2023-07-06T11:37:49.000Z","dependencies_parsed_at":"2023-02-04T05:55:12.125Z","dependency_job_id":null,"html_url":"https://github.com/andywer/http-event-stream","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/andywer/http-event-stream","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fhttp-event-stream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fhttp-event-stream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fhttp-event-stream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fhttp-event-stream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andywer","download_url":"https://codeload.github.com/andywer/http-event-stream/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andywer%2Fhttp-event-stream/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259924815,"owners_count":22932806,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["events","expressjs","http","koajs","nodejs","rest","server-sent-events","sse","stream"],"created_at":"2024-09-24T14:18:21.992Z","updated_at":"2025-06-23T01:09:02.720Z","avatar_url":"https://github.com/andywer.png","language":"TypeScript","readme":"# http-event-stream [![Build Status](https://travis-ci.org/andywer/http-event-stream.svg?branch=master)](https://travis-ci.org/andywer/http-event-stream) [![NPM Version](https://img.shields.io/npm/v/http-event-stream.svg)](https://www.npmjs.com/package/http-event-stream)\n\nStream real-time events over plain HTTP using [Server Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) in node.js.\n\nFocusing on spec-compliant Server Sent Event streams, we not only stream events, but also replay past events on demand. Event replaying allows clients to disconnect and reconnect to a stream without missing any data.\n\n📡\u0026nbsp;\u0026nbsp;**Server-sent events via plain HTTP**\u003cbr /\u003e\n💡\u0026nbsp;\u0026nbsp;**Stream as a REST endpoint route**\u003cbr /\u003e\n☁️\u0026nbsp;\u0026nbsp;**Immutable state allows cleaner code**\u003cbr /\u003e\n🗺️\u0026nbsp;\u0026nbsp;**Framework-agnostic - works with Express, Koa \u0026 others**\u003cbr /\u003e\n🛡️\u0026nbsp;\u0026nbsp;**No more \"Failed to upgrade websocket connection\"**\u003cbr /\u003e\n\n---\n\n## Installation\n\n```sh\nnpm install http-event-stream\n# or\nyarn add http-event-stream\n```\n\n\n## Usage\n\n### Using [Express.js](https://expressjs.com/)\n\n```js\nconst express = require(\"express\")\n\nconst app = express()\n\n// Example event stream: Stream the current time\napp.get(\"/time-stream\", (req, res) =\u003e {\n  // Find the implementation below\n  streamSampleEvents(req, res)\n})\n\napp.listen(3000)\n```\n\n### Using [Koa.js](https://koajs.com/)\n\n```js\nconst Koa = require(\"koa\")\nconst Router = require(\"koa-router\")\n\nconst app = new Koa()\nconst router = new Router()\n\n// Example event stream: Stream the current time\nrouter.get(\"/time-stream\", (context) =\u003e {\n  // Find the implementation below\n  streamSampleEvents(context.req, context.res)\n\n  // Koa quirk: Don't close the request/stream after handling the route!\n  context.respond = false\n})\n\napp\n  .use(router.routes())\n  .use(router.allowedMethods())\n  .listen(3000)\n```\n\n### Sample stream implementation\n\n```js\nconst { streamEvents } = require(\"http-event-stream\")\nconst events = require(\"./some-event-emitter\")\n\nfunction streamSampleEvents (req, res) {\n  const fetchEventsSince = async (lastEventId) =\u003e {\n    return [ /* all events since event with ID `lastEventId` would go here */ ]\n  }\n  return streamEvents(req, res, {\n    async fetch (lastEventId) {\n      // This method is mandatory to replay missed events after a re-connect\n      return fetchEventsSince(lastEventId)\n    },\n    stream (stream) {\n      const listener = () =\u003e {\n        stream.sendEvent({\n          event: \"time\",\n          data: JSON.stringify({\n            now: new Date().toISOString()\n          })\n        })\n      }\n\n      // Subscribe to some sample event emitter\n      events.addEventListener(\"data\", listener)\n\n      // Return an unsubscribe function, so the stream can be terminated properly\n      const unsubscribe = () =\u003e events.removeEventListener(\"data\", listener)\n      return unsubscribe\n    }\n  })\n}\n```\n\nA server-sent event sent via `stream.sendEvent()` or returned from `fetch()` has to have the following shape:\n\n```ts\ninterface ServerSentEvent {\n  data: string | string[]\n  event?: string,\n  id?: string\n  retry?: number\n}\n```\n\nBesides `stream.sendEvent(event: ServerSentEvent)` there is also `stream.sendComment(comment: string)` and `stream.close()`.\n\nSee [Using server-sent events - Fields](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Fields).\n\n\n## API\n\nSee [dist/index.d.ts](./dist/index.d.ts).\n\n\n## Differences to WebSockets\n\nBrief summary:\n\n- Automatic reconnecting out of the box\n- Unidirectional data flow\n- HTTP/2 multiplexing out of the box\n- No `Connection: Upgrade` - no special reverse proxy config\n\nWhat do we use websockets for? Usually for streaming events from the server to client in realtime.\n\nServer Sent Events (SSE) only do this one job, but do it really well. It's a simple protocol, using a normal HTTP connection, only streaming data from the server to the client.\n\nYou can pass parameters and headers from the client to the server when opening the stream, but the actual stream is read-only for the client.\n\nIt might sound like a strong limitation first, but actually it's a pretty clean approach: It makes the stream stateless and allows cool things like [combining multiple streams into one](https://github.com/Netflix/Turbine) which you could not easily do with a duplex stream.\n\n\n## Authentication\n\nSince it's all just plain HTTP, we can use headers like we always do. Go ahead and use your favorite auth middleware that you use for the other REST endpoints.\n\n\n## Client\n\nMake sure to include a polyfill in your web page code, since [not all major browsers provide native support for SSE](https://caniuse.com/#search=server%20sent%20events).\n\nTry [`event-source-polyfill`](https://www.npmjs.com/package/event-source-polyfill).\n\nTo connect to SSE streams from node.js, use the [`eventsource` package](https://www.npmjs.com/package/eventsource).\n\n\n## Further reading\n\n- [Smashing Magazine - Using SSE Instead Of WebSockets For Unidirectional Data Flow Over HTTP/2](https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/)\n- [streamdata.io - Why we chose server-sent events SSE vs Websockets for our streaming API](https://streamdata.io/blog/push-sse-vs-websockets/)\n- [codeburst.io - Polling vs SSE vs WebSocket— How to choose the right one](https://codeburst.io/polling-vs-sse-vs-websocket-how-to-choose-the-right-one-1859e4e13bd9)\n\n\n## License\n\nMIT\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandywer%2Fhttp-event-stream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandywer%2Fhttp-event-stream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandywer%2Fhttp-event-stream/lists"}