{"id":20006818,"url":"https://github.com/nextorigin/sseries-of-tubes","last_synced_at":"2025-08-13T07:15:38.104Z","repository":{"id":57368870,"uuid":"64236559","full_name":"nextorigin/sseries-of-tubes","owner":"nextorigin","description":"Takes Express/Connect routes and creates stream.Writable endpoints for Server Sent Events","archived":false,"fork":false,"pushed_at":"2020-05-23T12:09:41.000Z","size":76,"stargazers_count":7,"open_issues_count":10,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-09T06:42:08.683Z","etag":null,"topics":["eventemitter","express-middleware","expressjs","keep-alive","nodejs-streams","server-sent-events","sse","stream-processing","streams","streams2","streams3"],"latest_commit_sha":null,"homepage":null,"language":"CoffeeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nextorigin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-26T16:21:25.000Z","updated_at":"2019-03-04T17:48:45.000Z","dependencies_parsed_at":"2022-09-15T15:24:54.315Z","dependency_job_id":null,"html_url":"https://github.com/nextorigin/sseries-of-tubes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nextorigin/sseries-of-tubes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nextorigin%2Fsseries-of-tubes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nextorigin%2Fsseries-of-tubes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nextorigin%2Fsseries-of-tubes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nextorigin%2Fsseries-of-tubes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nextorigin","download_url":"https://codeload.github.com/nextorigin/sseries-of-tubes/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nextorigin%2Fsseries-of-tubes/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270202642,"owners_count":24544379,"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","status":"online","status_checked_at":"2025-08-13T02:00:09.904Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["eventemitter","express-middleware","expressjs","keep-alive","nodejs-streams","server-sent-events","sse","stream-processing","streams","streams2","streams3"],"created_at":"2024-11-13T06:13:46.741Z","updated_at":"2025-08-13T07:15:38.065Z","avatar_url":"https://github.com/nextorigin.png","language":"CoffeeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sseries-of-tubes\n\n[![Build Status][ci-master]][travis-ci]\n[![Coverage Status][coverage-master]][coveralls]\n[![Dependency Status][dependency]][david]\n[![devDependency Status][dev-dependency]][david]\n[![Downloads][downloads]][npm]\n[![Greenkeeper badge][greenkeeper-enabled]][greenkeeper]\n\nTakes Express/Connect routes and creates stream.Writable endpoints for Server Sent Events.\n\n[![NPM][npm-stats]][npm]\n\n# Introduction\n\nSSEriesOfTubes attaches to an http.Server and efficiently manages each endpoint for Server Sent Events by creating a writeable `StringTube` Stream that is piped to every http.Response.  `StringTube` is a utf8 String Stream subclassed from Through2.\n\nAdditionally, SSEriesOfTubes can wrap a standard Express/Connect route controller (a `function` that takes arguments `(req, res, next)`), poll that controller for data, and push that data to the SSE stream.\n\nThis way, any API can easily support REST/polling and Server Sent Events with the same route controller.\n\nSSEriesOfTubes is an EventEmitter based on [chrisdickinson/sse-stream](https://github.com/chrisdickinson/sse-stream), so it handles SSE headers, keep-alive messaging, and emits events around the connection and polling lifecycle.\n\n# Installation\n```sh\nnpm install --save sseries-of-tubes\n```\n\n# Usage\n\n## Example\n\n```coffee\n# on server\nhttp           = require \"http\"\nexpress        = require \"express\"\nSSEriesOfTubes = require \"sseries-of-tubes\"\n\nserver         = new http.Server\napp            = express()\nsseriesOfTubes = new SSEriesOfTubes server\n\nsendHello = (req, res, next) -\u003e\n    res.json hello: \"world\"\n\n# Sends {\"hello\": \"world\"} every 3s to every client connected to /sse/hello\napp.get \"/sse/hello\", sseriesOfTubes.plumb sendHello, 3\n\n...\n\n# on client\nsource = new EventSource \"/sse/hello\"\n# log {\"hello\": \"world\"} as received every 3s\nsource.onmessage = (data) -\u003e console.log data\n\n```\n\n## Interface\n\n#### SSEriesOfTubes.StringTube\n\nPointer to class StringTube, a [Through2](https://github.com/rvagg/through2) Readable/Writable stream.\n\n#### SSEriesOfTubes::constructor(server, keepAliveInterval)\n```coffee\nnew SSEriesOfTubes http.Server server, int keepAliveInterval\n```\nreturns sseriesOfTubes instance\n\nCreates a new SSEriesOfTubes instance that reacts to http.Server \"listening\" and \"close\" events.\n\n#### sseriesOfTubes.plumb(fn, interval)\n```coffee\nsseriesOfTubes.plumb Function route, int interval\n```\nreturns Function route\n\nCreates a new StringTube source which polls a route to write to all clients for an endpoint.\n\n#### sseriesOfTubes.plumb(fn, interval, event)\n```coffee\nsseriesOfTubes.plumb Function route, int interval, String event\n```\nreturns Function route\n\nCreates a new StringTube source which polls a route to write to all clients for an endpoint, and will send the event `event` (in EventSource syntax) before sending data.\n\n#### sseriesOfTubes.plumb()\n```coffee\nsseriesOfTubes.plumb()\n```\nreturns Function route\n\nCreates a new StringTube source which writes to all clients for an endpoint.\n\n#### sseriesOfTubes.source(url)\n```coffee\nsseriesOfTubes.source String url\n```\nreturns StringTube source\n\nRetrieves the StringTube source for an endpoint.\n\n#### sseriesOfTubes.combine(router, paths...)\n```coffee\nsseriesOfTubes.combine express.Router router, String paths...\n```\nreturns Function route\n\nCreates a new StringTube source by combining existing StringTube sources referenced by their `path`.  This way different combinations of streams can be provided without duplicating pollers.  Requires a `router` conforming to the express.Router interface for method `handle`.\n\n#### sseriesOfTubes.multiplex(router, param = \"streams\")\n```coffee\nsseriesOfTubes.multiplex express.Router router, String param\n```\nreturns Function route\n\nCreates new StringTube sources by dynamically combining existing StringTube sources, referenced by their `path` in an comma-separated list provided by the client in the query or body as parameter `param`.  This method is similar to `combine`, but works with paths that have route parameters.  Requires a `router` conforming to the express.Router interface for method `handle`.\n\n#### sseriesOfTubes.destroy()\n```coffee\nsseriesOfTubes.destroy()\n```\nEnds all SSE client connections and destroys all clients.\n\n## Events\n\n#### connection\n```coffee\nsseriesOfTubes.on \"connection\", (client) -\u003e\n```\nOn client connection, calls bound function with an instance of Client.\n\n#### poll\n```coffee\nsseriesOfTubes.on \"poll\", (url) -\u003e\n```\nOn route start poll, calls bound function with the url endpoint.\n\n#### plumb\n```coffee\nsseriesOfTubes.on \"plumb\", (url) -\u003e\n```\nOn route start plumb (creates StringTube source), calls bound function with the url endpoint.\n\n#### stop\n```coffee\nsseriesOfTubes.on \"stop\", (url) -\u003e\n```\nOn last client disconnect, calls bound function with the url endpoint.\n\n# License\n\nMIT\n\n  [ci-master]: https://img.shields.io/travis/nextorigin/sseries-of-tubes/master.svg?style=flat-square\n  [travis-ci]: https://travis-ci.org/nextorigin/sseries-of-tubes\n  [coverage-master]: https://img.shields.io/coveralls/nextorigin/sseries-of-tubes/master.svg?style=flat-square\n  [coveralls]: https://coveralls.io/r/nextorigin/sseries-of-tubes\n  [dependency]: https://img.shields.io/david/nextorigin/sseries-of-tubes.svg?style=flat-square\n  [david]: https://david-dm.org/nextorigin/sseries-of-tubes\n  [dev-dependency]: https://img.shields.io/david/dev/nextorigin/sseries-of-tubes.svg?style=flat-square\n  [david-dev]: https://david-dm.org/nextorigin/sseries-of-tubes#info=devDependencies\n  [downloads]: https://img.shields.io/npm/dm/sseries-of-tubes.svg?style=flat-square\n  [npm]: https://www.npmjs.org/package/sseries-of-tubes\n  [npm-stats]: https://nodei.co/npm/sseries-of-tubes.png?downloads=true\u0026downloadRank=true\u0026stars=true\n  [greenkeeper-enabled]: https://badges.greenkeeper.io/nextorigin/spine-awaitajax.svg\n  [greenkeeper]: https://greenkeeper.io/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnextorigin%2Fsseries-of-tubes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnextorigin%2Fsseries-of-tubes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnextorigin%2Fsseries-of-tubes/lists"}