{"id":26773152,"url":"https://github.com/nichitaa/rxjs-ws","last_synced_at":"2025-03-29T01:36:17.961Z","repository":{"id":183936545,"uuid":"671030735","full_name":"nichitaa/rxjs-ws","owner":"nichitaa","description":"WebSocket library to simply integrate with RxJS","archived":false,"fork":false,"pushed_at":"2024-09-06T06:56:26.000Z","size":89,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-10T19:42:38.378Z","etag":null,"topics":["observables","rxjs","streams","websocket"],"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/nichitaa.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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}},"created_at":"2023-07-26T11:36:42.000Z","updated_at":"2024-09-06T06:56:30.000Z","dependencies_parsed_at":"2024-01-21T13:29:46.037Z","dependency_job_id":"abc16459-b629-40b2-b3e9-3ec500e3d425","html_url":"https://github.com/nichitaa/rxjs-ws","commit_stats":null,"previous_names":["nichitaa/ws-rxjs","nichitaa/rxjs-ws"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichitaa%2Frxjs-ws","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichitaa%2Frxjs-ws/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichitaa%2Frxjs-ws/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichitaa%2Frxjs-ws/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nichitaa","download_url":"https://codeload.github.com/nichitaa/rxjs-ws/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246126670,"owners_count":20727594,"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":["observables","rxjs","streams","websocket"],"created_at":"2025-03-29T01:36:17.471Z","updated_at":"2025-03-29T01:36:17.944Z","avatar_url":"https://github.com/nichitaa.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rxjs-ws\n\nWebSocket library to simply integrate with RxJS.\n\n\u003e Inspired by: [rxjs-websockets](https://github.com/insidewhy/rxjs-websockets). It is an extension of it, that covers most of WebSocket manipulation and provides flexible utilities/streams to work with WebSocket events.\n\n### Features 🎯\n\n- Manage WebSocket connection / provides real time connection status\n- Manage reconnection / retries (via rxjs operators) / easy API to conditionally reconnect\n- Custom serialization / deserialization\n- ✨ `getStreamHandler` - Powerful utility to create stream handlers from WebSocket events\n\n\nFor example on application side you have WS events `events/posts` \u0026 `events/users`. You can create handlers for each of them, for example:\n```ts\nconst postsHandler = handler.getStreamHandler\u003cPostEvent, Post, PostRequest, PostError\u003e({ default: [] })\nconst usersHandler = handler.getStreamHandler\u003cUserEvent, User, UserRequest, UserError\u003e({ default: undefined, awaitReadyStatusBeforeNextRequest: false })\n```\n\n### Getting Started 🎉\n#### Peer Dependencies \n\n* `rxjs`: `^7.x`,\n\n### Installation\n\n```bash\nnpm install @nichitaa/rxjs-ws\n```\n\n### Create `WebSocketConnector`\n\n```ts\nconst connector = new WebSocketConnector({\n  url: 'wss://...',\n});\n```\n\nDefault WebSocket instance is `window.WebSocket` \n\nParams:\n- `url`, `protocols` - [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)\n- `createWebSocketInstance` - create custom WebSocket instance (for example socket.io)\n- `serializer` - provide custom serializer function (defaults to `JSON.stringify`)\n- `deserializer` - provide custom deserializer function (defaults to `JSON.parse`)\n\n### Manage WebSocket connection\n\nWith optionally `retryConfig`\n```ts\nconnector.connect({ \n  retryConfig: { \n    count: 10, \n    delay: of(true).pipe(delay(1000)),\n    onSuccess: () =\u003e {\n      console.log('successfully retried websocket connection')\n    }\n  } \n});\n```\n\nParams:\n- `count`, `delay` - [RxJS `RetryConfig` docs](https://rxjs.dev/api/index/interface/RetryConfig)\n- `onSuccess` - callback called when retry was successfully\n\nDisconnect.\n\n```ts\nconnector.disconnect();\n```\n\nForce trigger reconnection, might be usefully on stale connections.\n\n```ts\nconnector.forceReconnect(\"optional custom message\");\n// OR\nconnector.forceReconnect();\n```\n\nSubscribe to status changes.\n\n```ts\nimport { CONN_STATUS } from '@nichitaa/rxjs-ws';\n\nconnector.status$.subscribe((status) =\u003e {\n  if (CONN_STATUS.connected) {\n    console.log('just connected')\n  }\n})\n```\n\n`status$` is stream with possible values (`CONN_STATUS`)\n\n- `uninitialized` - connection not yet initialized\n- `connected` - connection successfully established\n- `reconnecting` - reconnection is in progress\n- `disconnected` - dropped socket connection (not active)\n\nSend events (aka requests).\n\n```ts\ntype Request = {\n  payload: string;\n  streamId: number\n}\n\nconn.send\u003cRequest\u003e({ payload: '...', streamId: 1 });\n```\n\nReceive incoming messages.\n\n```ts\n// create a custom stream that filteres events for a specific method\nconst users$ = connector\n  .messages\u003c{ method: string; data: string }\u003e()\n  .pipe(filter((event) =\u003e event.method === 'v1/users/events'));\n\n// subscribe to users events\nusers$.subscribe((event) =\u003e {\n  console.log('users just received: ', event);\n});\n```\n\n\n✨ Utility to create streams - `getStreamHandler`\n\n```ts\n// create a custom stream that filteres events for a specific method\nimport { STREAM_STATUS } from '@nichitaa/rxjs-ws';\n\nconst usersHandler = connector.getStreamHandler\u003cWSEvent, User, UserRequest, UserError\u003e({\n  default: [],\n})\n\nconst scanUsers = (request) = (source$) =\u003e {\n  return source$.pipe(\n    // filter only users types of events\n    filter(event =\u003e event.method ===  request.method), // e.g.: request.method === 'v1/users'\n    // throw error if so that handler can catch it\n    tap((event) =\u003e {\n      if (isError(event)) throw x\n    }),\n    // for example accumulate them\n    scan(\n      (acc, event) =\u003e {\n        if (event.isLastMessage) acc.snapshotEnd = true;\n        acc.events.push(event.user);\n        return acc;\n      },\n      { snapshotEnd: false, events: [] },\n    ),\n    filter((x) =\u003e x.snapshotEnd),\n    map((x) =\u003e x.events),\n  );\n};\n\n// send a request\nusersHandler.send({\n  request: { method: 'v1.users' },\n  transformResponse: scanUsers,\n});\n\nusersHandler.$.subscribe(({ response, request, status, error }) =\u003e {\n  // react to stream emissions\n  \n  if (status === STREAM_STATUS.loading) {\n    // loading\n  }\n  if (status === STREAM_STATUS.ready \u0026\u0026 error === undefined) {\n    const userNames = response.map(x =\u003e x.username);\n  }\n  if (status === STREAM_STATUS.ready \u0026\u0026 error !== undefined) {\n    console.error(error);\n  }\n})\n```\n\nArguments of the `getStreamHandler` function:\n\n- `default` - default `response` (defaults to `undefined`)\n- `transformRequests` - custom RxJS operator that can change the requests that are processed/send to WebSocket (defaults to [`identity`](https://rxjs.dev/api/index/function/identity))\n- `resetResponseOnNextRequest` - reset `response` back to `default` for the next request (`handler.send({request: {...}})`) (defaults to `true`)\n- `resetErrorOnNextRequest` - similar to `resetResponseOnNextRequest`, but resets `error` field (defaults to `true`)\n- `awaitReadyStatusBeforeNextRequest` - allows to process next request without waiting for at least one `ready` status emission from current processed request\n\nBecause `handler.send()` can be called in any order at any time, it is important to process them sequentially, `awaitReadyStatusBeforeNextRequest` allows to \ndrop the execution (waiting for response) for current request and continue with execution of the new request, for example:\n\n- with `awaitReadyStatusBeforeNextRequest: false`:\n  - ```ts\n    const handler = connector.getStreamHandler({\n      awaitReadyStatusBeforeNextRequest: false\n    })\n    handler.send({request: 1});\n    handler.send({request: 2});\n    handler.send({request: 3});\n    ```\n    In the above example `handler.$` will emit:\n    1. `{status: 'uninitialized', response: undefined}`\n    2. `{status: 'loading', request: 1, response: undefined}`\n    3. `{status: 'loading', request: 2, response: undefined}`\n    4. `{status: 'loading', request: 3, response: undefined}`\n    5. `{status: 'ready', request: 3, response: undefined}` When response for 3rd request will arrive, and all previous request will be correctly send\n\n- with `awaitReadyStatusBeforeNextRequest: true`:\n  - ```ts\n    const handler = connector.getStreamHandler({})\n    handler.send({request: 1});\n    handler.send({request: 2});\n    ```\n  In the above example `handler.$` will emit:\n    1. `{status: 'uninitialized', response: undefined}`\n    2. `{status: 'loading', request: 1, response: undefined}`\n    3. `{status: 'ready', request: 1, response: ... }`\n    4. `{status: 'loading', request: 2, response: undefined}`\n    5. `{status: 'ready', request: 2, response: ...}` All requests are send in order and each next request is started only after current has at least one emission with status `ready`\n    \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnichitaa%2Frxjs-ws","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnichitaa%2Frxjs-ws","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnichitaa%2Frxjs-ws/lists"}