{"id":18051402,"url":"https://github.com/insidewhy/rxjs-websockets","last_synced_at":"2025-10-25T04:15:07.993Z","repository":{"id":39001349,"uuid":"81986805","full_name":"insidewhy/rxjs-websockets","owner":"insidewhy","description":"A very flexible and simple websocket library for rxjs","archived":false,"fork":false,"pushed_at":"2025-10-17T19:41:24.000Z","size":312,"stargazers_count":269,"open_issues_count":18,"forks_count":36,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-10-18T21:41:07.210Z","etag":null,"topics":["ngrx-effects","observables","redux-observable","rxjs","websocket","websockets"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/insidewhy.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-02-14T20:39:26.000Z","updated_at":"2025-09-05T15:23:40.000Z","dependencies_parsed_at":"2023-01-31T06:01:24.013Z","dependency_job_id":"9b0a6868-7bd3-478a-ab8f-677575d102a2","html_url":"https://github.com/insidewhy/rxjs-websockets","commit_stats":{"total_commits":220,"total_committers":15,"mean_commits":"14.666666666666666","dds":0.4,"last_synced_commit":"857aa0faa22403bee2e489b5b2dfa80a3d3e72cc"},"previous_names":["ohjames/angular2-websocket-service","ohjames/rxjs-websockets"],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/insidewhy/rxjs-websockets","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/insidewhy%2Frxjs-websockets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/insidewhy%2Frxjs-websockets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/insidewhy%2Frxjs-websockets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/insidewhy%2Frxjs-websockets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/insidewhy","download_url":"https://codeload.github.com/insidewhy/rxjs-websockets/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/insidewhy%2Frxjs-websockets/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280902782,"owners_count":26410856,"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-10-25T02:00:06.499Z","response_time":81,"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":["ngrx-effects","observables","redux-observable","rxjs","websocket","websockets"],"created_at":"2024-10-30T22:47:09.364Z","updated_at":"2025-10-25T04:15:07.965Z","avatar_url":"https://github.com/insidewhy.png","language":"TypeScript","funding_links":[],"categories":["Libraries \u0026 Utilities","TypeScript"],"sub_categories":["Framework-Agnostic"],"readme":"# rxjs-websockets\n\n[![build status](https://circleci.com/gh/insidewhy/rxjs-websockets.png?style=shield)](https://circleci.com/gh/insidewhy/rxjs-websockets)\n[![Known Vulnerabilities](https://snyk.io/test/github/insidewhy/rxjs-websockets/badge.svg)](https://snyk.io/test/github/insidewhy/rxjs-websockets)\n[![Renovate](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com)\n\nAn rxjs websocket library with a simple and flexible implementation. Supports the browser and node.js.\n\n## Comparisons to other rxjs websocket libraries:\n\n- [observable-socket](https://github.com/killtheliterate/observable-socket)\n  - observable-socket provides an input subject for the user, rxjs-websockets allows the user to supply the input stream as a parameter to allow the user to select an observable with semantics appropriate for their own use case ([queueing-subject](https://github.com/insidewhy/queueing-subject) can be used to achieve the same semantics as observable-socket).\n  - With observable-socket the WebSocket object must be used and managed by the user, rxjs-websocket manages the WebSocket(s) for the user lazily according to subscriptions to the messages observable.\n  - With observable-socket the WebSocket object must be observed using plain old events to detect the connection status, rxjs-websockets presents the connection status through observables.\n- [rxjs built-in websocket subject](https://github.com/ReactiveX/rxjs/blob/next/src/observable/dom/webSocket.ts)\n  - Implemented as a Subject so lacks the flexibility that rxjs-websockets and observable-socket provide.\n  - Does not provide any ability to monitor the web socket connection state.\n\n## Installation\n\n```bash\nnpm install -S rxjs-websockets\n# or\nyarn add rxjs-websockets\n```\n\nFor rxjs 6 support, rxjs-websockets 8 is needed.\n\n```bash\nnpm install -S rxjs-websockets@8\n# or\nyarn add rxjs-websockets@8\n```\n\n## Changelog\n\n[Changelog here](changelog.md)\n\n## Simple usage\n\n```typescript\nimport { QueueingSubject } from 'queueing-subject'\nimport { Subscription } from 'rxjs'\nimport { share, switchMap } from 'rxjs/operators'\nimport makeWebSocketObservable, {\n  GetWebSocketResponses,\n  // WebSocketPayload = string | ArrayBuffer | Blob\n  WebSocketPayload,\n  normalClosureMessage,\n} from 'rxjs-websockets'\n\n// this subject queues as necessary to ensure every message is delivered\nconst input$ = new QueueingSubject\u003cstring\u003e()\n\n// queue up a request to be sent when the websocket connects\ninput$.next('some data')\n\n// create the websocket observable, does *not* open the websocket connection\nconst socket$ = makeWebSocketObservable('ws://localhost/websocket-path')\n\nconst messages$: Observable\u003cWebSocketPayload\u003e = socket$.pipe(\n  // the observable produces a value once the websocket has been opened\n  switchMap((getResponses: GetWebSocketResponses) =\u003e {\n    console.log('websocket opened')\n    return getResponses(input$)\n  }),\n  share(),\n)\n\nconst messagesSubscription: Subscription = messages.subscribe({\n  next: (message: string) =\u003e {\n    console.log('received message:', message)\n    // respond to server\n    input$.next('i got your message')\n  },\n  error: (error: Error) =\u003e {\n    const { message } = error\n    if (message === normalClosureMessage) {\n      console.log('server closed the websocket connection normally')\n    } else {\n      console.log('socket was disconnected due to error:', message)\n    }\n  },\n  complete: () =\u003e {\n    // The clean termination only happens in response to the last\n    // subscription to the observable being unsubscribed, any\n    // other closure is considered an error.\n    console.log('the connection was closed in response to the user')\n  },\n})\n\nfunction closeWebsocket() {\n  // this also caused the websocket connection to be closed\n  messagesSubscription.unsubscribe()\n}\n\nsetTimeout(closeWebsocket, 2000)\n```\n\nThe observable returned by `makeWebSocketObservable` is cold, this means the websocket connection is attempted lazily as subscriptions are made to it. Advanced users of this library will find it important to understand the distinction between [hot and cold observables](https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html), for most it will be sufficient to use the [share operator](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-share) as shown in the example above. The `share` operator ensures at most one websocket connection is attempted regardless of the number of subscriptions to the observable while ensuring the socket is closed when the last subscription is unsubscribed. When only one subscription is made the operator has no effect.\n\nBy default the websocket supports binary messages so the payload type is `string | ArrayBuffer | Blob`, when you only need `string` messages the generic parameter to `makeWebSocketObservable` can be used:\n\n```typescript\nconst socket$ = makeWebSocketObservable\u003cstring\u003e('ws://localhost/websocket-path')\nconst input$ = new QueueingSubject\u003cstring\u003e()\n\nconst messages$: Observable\u003cstring\u003e = socket$.pipe(\n  switchMap((getResponses: GetWebSocketResponses\u003cstring\u003e) =\u003e getResponses(input$)),\n  share(),\n)\n```\n\n## Reconnecting on unexpected connection closures\n\nThis can be done with the built-in rxjs operator `retryWhen`:\n\n```typescript\nimport { Subject } from 'rxjs'\nimport { switchMap, retryWhen } from 'rxjs/operators'\nimport makeWebSocketObservable from 'rxjs-websockets'\n\nconst input$ = new Subject\u003cstring\u003e()\n\nconst socket$ = makeWebSocketObservable('ws://localhost/websocket-path')\n\nconst messages$ = socket$.pipe(\n  switchMap((getResponses) =\u003e getResponses(input$)),\n  retryWhen((errors) =\u003e errors.pipe(delay(1000))),\n)\n```\n\n## Alternate WebSocket implementations\n\nA custom websocket factory function can be supplied that takes a URL and returns an object that is compatible with WebSocket:\n\n```typescript\nimport makeWebSocketObservable, { WebSocketOptions } from 'rxjs-websockets'\n\nconst options: WebSocketOptions = {\n  // this is used to create the websocket compatible object,\n  // the default is shown here\n  makeWebSocket: (url: string, protocols?: string | string[]) =\u003e new WebSocket(url, protocols),\n\n  // optional argument, passed to `makeWebSocket`\n  // protocols: '...',\n}\n\nconst socket$ = makeWebSocketObservable('ws://127.0.0.1:4201/ws', options)\n```\n\n## JSON messages and responses\n\nThis example shows how to use the `map` operator to handle JSON encoding of outgoing messages and parsing of responses:\n\n```typescript\nimport { Observable } from 'rxjs'\nimport makeWebSocketObservable, { WebSocketOptions, GetWebSocketResponses } from 'rxjs-websockets'\n\nfunction makeJsonWebSocketObservable(\n  url: string,\n  options?: WebSocketOptions,\n): Observable\u003cunknown\u003e {\n  const socket$ = makeWebSocketObservable\u003cstring\u003e(url, options)\n  return socket$.pipe(\n    map(\n      (getResponses: GetWebSocketResponses\u003cstring\u003e) =\u003e (input$: Observable\u003cobject\u003e) =\u003e\n        getResponses(input$.pipe(map((request) =\u003e JSON.stringify(request)))).pipe(\n          map((response) =\u003e JSON.parse(response)),\n        ),\n    ),\n  )\n}\n```\n\nThe function above can be used identically to `makeWebSocketObservable` only the requests/responses will be transparently encoded/decoded.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finsidewhy%2Frxjs-websockets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finsidewhy%2Frxjs-websockets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finsidewhy%2Frxjs-websockets/lists"}