npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

redux-ws-middleware

v1.0.8

Published

This package makes web socket management much easier with redux

Downloads

711

Readme

Redux WebSocket Middleware

This package makes web socket management much easier with redux. The package is built over the WebSocket constructor from browser API.


Examples


Structure


Installation

# using npm
npm install redux-ws-middleware

# using yarn
yarn add redux-ws-middleware

Options

| Name | Required | Type | Default | | ---------------------------------------------- | -------- | --------------------------------------------------- | ----------- | | url | Yes | string | - | | actionTypes | Yes | Array<string OR RegExp> | - | | completedActionTypes | Yes | Array<string> | - | | onMessage | Yes | (res: Res, dispatch: Dispatch<AnyAction>) => void | - | | autoConnect | No | boolean | true | | protocols | No | string OR string[] | - | | shouldReconnect | No | ((event: CloseEvent) => boolean) OR boolean | true | | reconnectionIntervals | No | number OR number[] | 1000 | | shouldOpen | No | ((req: Req) => boolean) OR boolean | false | | shouldClose | No | ((res: DRes) => boolean) OR boolean | false | | serialize | No | (req: Req) => SReq | - | | deserialize | No | (res: Res) => DRes | - | | debug | No | boolean | - |


url

Required*

Type: string

Url for the WebSocket constructor.

url: 'ws://localhost:3000'
url: 'wss://example.com'

actionTypes

Required*

Type: [RegExp | string, RegExp | string, RegExp | string]

WARNING: Sequence is important!

Types that you are able to manage the socket with. You can have socket dispatching any of them.

The first element should be the SEND action type. Second - CONNECT type. Third - DISCONNECT type.

IMPORTANT: Do not use /g at the end of RegExp!

actionTypes: ['SEND', 'CONNECT', 'DISCONNECT']
actionTypes: [new RegExp(/_REQUEST$/), 'CONNECT', 'DISCONNECT']

If you don't need these: CONNECT, DISCONNECT so just don't send them.

actionTypes: ['SEND', 'CONNECT']
actionTypes: ['SEND']
actionTypes: [new RegExp(/_REQUEST$/)]

completedActionTypes

Required*

Type: [string, string]

WARNING: Sequence is important!

Types that you receive back on actions.

completedActionTypes: ['CONNECTED', 'DISCONNECTED']

onMessage

Required*

Type: (res: Res, dispatch: Dispatch<AnyAction>) => void

The callback gets called with deserialized data already, if you put deserialize function into options, or with a normal data if you don't. And with a dispatch so you can manage your store.

*(this is just an example of the onMessage handler)

onMessage: (data, dispatch) => {
  switch (data.method) {
    case 'posts':
      if (data.error) {
        dispatch(postsActions.getPostsRejected(data.error));
      } else {
        dispatch(postsActions.getPostsFulfilled(data.result));
      }
      break;
      
    ...
      
    default:
      break;
  }
}

autoConnect

Type: boolean - (true by default)

When true you don't need to send anything else to connect it. When false you need to dispatch the connect action with a type actionTypes[1].

autoConnect: false

debug

Type: boolean

When true the package shows additional logs.

debug: ture

protocols

Type: string | string[]

Protocols for the WebSocket constructor.

protocols: 'some protocol'
protocols: ['some protocol']

shouldReconnect

Type: ((event: CloseEvent) => boolean) | boolean - (true by default)

When true the socket tries to reconnect if event.code !== 1005. When predicate is passed you are able to decide if the socket needs to be reconnected.

shouldReconnect: false

reconnectionInterval

Type: number | number[] - (1000 by default)

In milliseconds. When array each new connection uses the next number from the array for a timeout to avoid DDOSing a server.

reconnectionInterval: 1000

When reconnection count reaches the last array element it uses it each the next time. When the socket connects back the next reconnection loop will start from the 0 index.

reconnectionInterval: [0, 1000, 2000, 3000, 4000, 5000, 10000]

shouldOpen

Type: ((req: Req) => boolean) | boolean - (false by default) Req is a template of the generic MiddlewareOptions type

When true the socket opens on any send action if connection is closed`. When predicate is passed you are able to decide if socket needs to be open.

shouldOpen: true

When predicate is passed you are able to decide when socket needs to be open.

shouldOpen: (req: SomeReq) => req.method === 'load_session'

shouldClose

Type: ((res: DRes) => boolean) | boolean - (false by default)

DRes is a templates of the generic MiddlewareOptions type

When true the socket closes connection after each response from the server. When predicate is passed you are able to decide when the socket needs to be closed.

shouldClose: true
shouldClose: (res: SomeDeserializedRes) => res.method === 'logout'

serialize

Type: (req: Req) => SReq

Req and SReq are templates of the generic MiddlewareOptions type

The format function gets called to prepare the data to get submitted to the server. For example, camelCase to snake_case conversion.

serialize: req => {
  return {
    ...req,
    time: Date.now()
  }
}

deserialize

Type: (res: Res) => DRes

Res and DRes are templates of the generic MiddlewareOptions type

The format function gets called to prepare the message to get submitted to the onMessage callback. For example, snake_case to camelCase conversion.

deserialize: res => {
  return res.data
}

Usage

Connecting

const SOCKET_SEND = 'SCOKET_SEND';
const SOCKET_CONNECT = 'SOCKET_CONNECT';
const SOCKET_DISCONNECT = 'SOCKET_DISCONNECT';

const otpions = {
  ...
  actionTypes: [SOCKET_SEND, SOCKET_CONNECT, SOCKET_DISCONNECT],
  ...
};

const connectAction = () => ({ type: SOCKET_CONNECT });

dispatch(connectAction());

Disconnecting

import { CloseAction } from 'redux-ws-middleware';

const SOCKET_SEND = 'SCOKET_SEND';
const SOCKET_CONNECT = 'SOCKET_CONNECT';
const SOCKET_DISCONNECT = 'SOCKET_DISCONNECT';

const otpions = {
  ...
  actionTypes: [SOCKET_SEND, SOCKET_CONNECT, SOCKET_DISCONNECT],
  ...
};

const disconnectAction = (code?: number): CloseAction<typeof SOCKET_DISCONNECT> => ({
  type: SOCKET_DISCONNECT,
  payload: { code }
});

OR

dispatch(disconnectAction(1000));

The disconnectAction can return:

{
  type: SOCKET_DISCONNECT,
  code
}
{
  type: SOCKET_DISCONNECT,
  payload: { code }
}
{
  type: SOCKET_DISCONNECT,
  data: { code }
}

(all these are supported by CloseAction<typeof SOCKET_DISCONNECT> type)

Sending data

The data can be sent in payload OR in data key.

import { SendAction } from 'redux-ws-middleware';

const GET_POSTS = 'GET_POSTS_REQUEST';

const otpions = {
  ...
  actionTypes: [new RegExp(/_REQUEST$/)],
  ...
}

const getPostsAction = (offset: number, limit: number): SendAction<typeof GET_POSTS> => ({
  type: GET_POSTS,
  payload: { offset, limit }
});

dispatch(getPostsAction(0, 20));

The getPostsAction can return:

{
  type: GET_POSTS,
  payload: { code }
}
{
  type: GET_POSTS,
  data: { code }
}

(all these are supported by SendAction<typeof GET_POSTS> type)


MiddlewareOptions declaration

import { createSocketMiddleware, MiddlewareOptions } from 'redux-ws-middleware';

type ScoketReq = {
  method: string
  data: Record<string, unknown>
};

type SocketRes = {
  [method: string]: Record<string, unknown>
};

type ScoketSerializedReq = {
  [method: string]: Record<string, unknown>
};

type SocketDeserializedRes = Record<string, unknown>;

const options: MiddlewareOptions<ScoketReq, SocketRes, ScoketSerializedReq, SocketDeserializedRes> = {
  url: 'ws://localhost:3000',
  actionTypes: ['SEND', 'CONNECT', 'DISCONNECT'],
  completedActionTypes: ['CONNECTED', 'DISCONNECTED'],

  // serialize: (req: ScoketReq) => ScoketSerializedReq
  serialize: ({ method, data }) => ({ [method]: data }),

  // deserialize: (res: SocketRes) => SocketDeserializedRes
  deserialize: (res: SocketRes) => res[Object.keys(res)[0]]
};

const socketMiddleware = createSocketMiddleware(options);

Passing own types to MiddlewareOptions type

MiddlewareOptions is a generic type.

MiddlewareOptions<Req, Res, SReq = Req, DRes = Res>

Req - type of the socket request (required).

Res - type of the socket response (required).

SReq (default is Req) - type of serialized socket request which will be sent to the API (not required). This type should be returned from the MiddlewareOptions.serialize function.

DRes (default is Res) - type of deserialized socket response which is reachable by using hooks as data (not required). This type should be returned from the MiddlewareOptions.deserialize function.