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

wss-rpc2

v1.0.10

Published

WebSocket Server and Client implementation of the JSON RPC-2 spec

Downloads

11

Readme

wss-rpc2

WebSocket Server and Client implementation of the JSON RPC2 spec.
Powered by ws.

npm NPM Coverage Status

Basic functionality, according to the spec:

  • Method call: client -> server (request/response)
  • Notifications: client -> server (notification)

Extended functionality:

  • Events: server -> client (to all / to some / to a single client)
  • Reconnect and keep alive
  • Stateful client connection
  • The client works in both node and browser

Quick start

Installation:

npm i wss-rpc2

Backend / Server:

import { RPCServer, RPCEvent } from 'wss-rpc2'

const server = new RPCServer({ port: 3000 })

server.registerMethod('multiply', (params) => {
  return params[0] * params[1]
})

Frontend / Client:

import { RPCClient } from 'wss-rpc2'

const client = new RPCClient('ws://localhost:3000')
const result = await client.call('multiply', [3, 5])

See more examples.

RPCServer API

new RPCServer(options: IRPCServerOptions)

Parameters:

  • options: IRPCServerOptions<State = any> extends ServerOptions
    • wss?: ws.WebSocketServer - existing WebSocketServer (ws) instance
    • keepAlive?: number - ping clients every N ms (default: 300000 // 5 min)
    • stateFactory?: () => State - initial state factory of the connected client
    • ...ServerOptions (see ws library)

RPCServer.registerMethod(name: string, method: IRPCMethod): void

Parameters:

  • name: string - name of the RPC method
  • method: IRPCMethod - RPC method function, see types

RPCServer.callMethod(name: string, params: IRPCParams): Promise<any>

Call a method explicitly

Parameters:

  • name: string - name of the RPC method
  • params: IRPCParams - params of the RPC method

RPCServer.getConnections(): RPCConnection[]

Returns active connection instances.


RPCServer.close(): Promise

Closes all active client's connections and stops the server.


RPCServer.on(eventName: string, listener: Function, once?: boolean): Function

Subscribe a listener to the event. Returns unsubscribe function.

RPCServer Events:

  • listening (params: empty) - on server start
  • connect (params: RPCConnection) - on client connect
  • disconnect (params: RPCConnection) - on client disconnect
  • request (params: RPCRequest) - on after request received
  • response (params: RPCResponse) - on before response sent
  • error (params: Error | unknown) - on server error
  • close (params: empty) - on server stop

RPCClient API

new RPCClient(address: string, options?: IRPCClientOptions)

Parameters:

  • address: string - URL of the RPCServer
  • options: IRPCClientOptions
    • autoConnect?: boolean - if false, then use client.connect() (default: true)
    • reconnectIntervals?: number[] - reconnect intervals sequence. Example: [1000, 1500, 2000] will wait between reconnect: 1000ms, 1500ms, 2000ms, ..., 2000ms, until reconnectLimit is reached (default: [1000] - every 1000 ms)
    • reconnectLimit?: number - 0 - unlimited, -1 - disabled (default: 1000)
    • requestTimeout?: number - request timeout (default: 10000)

RPCClient.state: 'init' | 'connecting' | 'connected' | 'stopped'

Client connection state:

  • init - before connect() has been called
  • connecting - connection or reconnection is in process
  • connected - active connection state
  • stopped - if disconnect() has been called or reconnectLimit is reached

RPCClient.connected: Promise<void>

Connection promise. However, it is not necessary to wait for a connection, because requests will be queued up until the connection is established.

const client = new RPCClient()
await client.connected
// connected!

RPCClient.connect(): Promise<void>

Manual connect, if autoConnect = false

const client = new RPCClient({ autoConnect: false })
await client.connect()
// connected!

RPCClient.disconnect(): Promise<void>

Disconnects and stops a reconnect-observer.


RPCClient.call(method: string, params?: IRPCParams): Promise<RPCResponse>

Calls the method and waits for a response.


RPCClient.notify(method: string, params?: IRPCParams): void

Notifies the server without waiting for a response.


RPCClient.on(eventName: string, listener: Function, once?: boolean): Function

Subscribe a listener to the event. Returns unsubscribe function.

RPCClient Events:

  • connect (params: empty) - on connect
  • disconnect (params: empty) - on disconnect
  • error (params: Error | unknown) - on error
  • request (params: IRPCRequestObject) - on before request sent
  • response (params: IRPCResponseObject) - on response received
  • event (params: RPCEvent) - on server event received

RPCConnection <State = unknown> API

id: string

Connection identifier


ws: WebSocket

Browser WebSocket object (isomorphic-ws is used for the node client)


state?: State

Domain state of the connection, if defined by IRPCServerOptions.stateFactory (and State generic for TS).


lastActivity: number = 0

Last client's activity timestamp


RPCConnection.emit (event: RPCEvent, cb?: (e: Error) => void)

Emit an event to the client. Example:

const event = new RPCEvent({ event: 'hello', params: {} })
server.getConnections().forEach(connection => {
  connection.emit(event, e => console.error(e))
})

Types

interface IRPCServerOptions extends ws.ServerOptions {
  wss?: WebSocketServer
  keepAlive?: number
  stateFactory?: () => State
}
interface IRPCClientOptions {
  autoConnect?: boolean
  reconnectIntervals?: number[]
  reconnectLimit?: number
  requestTimeout?: number
}
type IRPCParams = { [key: string]: unknown } | unknown[]
type IRPCMethod<Req extends IRPCParams = any, Res = any, State = any>
        = (params: Req, connection: RPCConnection<State>) => Res
interface IRPCRequestObject {
  jsonrpc: '2.0'
  id?: string | number
  method: string
  params?: IRPCParams
}
interface IRPCResponseObject {
  jsonrpc: '2.0'
  id: string | number | null
  result?: any
  error?: IRPCError
}
interface IRPCError {
  code: number
  message: string
  data?: unknown
}

Typescript

Typescript support provides several useful features for typing request, responses and connection state.

import { RPCServer } from 'wss-rpc2'

const server = new RPCServer<IAppUserState>({
  stateFactory: () => ({ authorized: false })
})

server.registerMethod<IRpcLogin['request'], IRpcLogin['response']>('login', async (params, connection) => {
  const user = await auth(params)
  if (user) {
    connection.state.authorized = true
    connection.state.email = user.email
    connection.state.id = user.id
  }
  return user
})

interface IAppUserState {
  authorized: boolean
  email?: string
  id?: string
}

interface IRpcLogin {
  request: {
    login: string
    password: string
  }
  response: {
    user?: {
      id: string
      email: string
    }
  }
}
import { RPCClient } from 'wss-rpc2'

const client = new RPCClient(url)
const { error, result } = await client.call<{ user: IUser | null }>('login', { email, password })
console.log(result?.user?.id)

Examples

To be done
Also see tests