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 🙏

© 2025 – Pkg Stats / Ryan Hefner

playsocketjs

v2.6.3

Published

WebSocket wrapper for creating simple multiplayer systems with ease.

Readme

PlaySocket Client

A reactive, optimistic WebSocket library that simplifies game & app development by abstracting away complex sync logic.

Why use PlaySocket?

PlaySocket eliminates the traditional complexity of collaborative experiences:

  • Streamlined architecture: No additional backend code is required, but server-authoritative behavior supported
  • State synchronization: Built-in storage system keeps the full state synchronized across all clients, always conflict-free and in order
  • Resilient & secure connections: Automatic reconnection handling & strict rate-limiting
  • Lightweight: Uses WebSockets for efficient, predictable, reliable communication and has little dependencies

Installation

npm install playsocketjs

Usage examples

Note that in production, you should always try...catch promises, such as socket.init() – they can reject!

Initializing the client:

import PlaySocket from 'playsocketjs';

// Create a new instance
const socket = new PlaySocket('unique-client-id', { // You can pass no ID to let the server pick one
    endpoint: 'wss://example.com/socket'
});

// Set up event handlers (optional)
socket.onEvent('status', status => console.log('Status:', status));
socket.onEvent('error', status => console.log('Error:', status));

const clientId = await socket.init(); // Initialize the socket

Creating a room:

// Create a new room
const roomId = await socket.createRoom();

// Optionally, with initial storage
const roomId = await socket.createRoom({
  players: ["this-player"],
  latestPlayer: null,
});

Joining a room:

await socket.joinRoom('room-id'); // Join an existing room

Leaving a room:

socket.destroy(); // To leave the room, destroy the instance

Using the storage update event for reactivity:

const reactiveVariable = useState(); // Or $state(), reactive(), depending on your framework
socket.onEvent('storageUpdated', storage => (reactiveVariable = storage)); // Assign on update

Interfacing with the synchronized storage (examples):

const currentState = socket.getStorage; // Synchronous, local access
socket.updateStorage('players', 'array-add-unique', { username: 'Player4', level: 2 }); // Special method to enable conflict-free additions for arrays
socket.updateStorage('latestPlayer', 'set', 'Player4'); // Regular synced storage update

Sending traditional requests to the server:

socket.sendRequest('chosen-request-name', { fact: "You can build server-authoritative logic using this!" })

API reference

Constructor

Creates a new PlaySocket instance with a specified ID and configuration options. The ID can be set to null to let the server pick a unique one.

new PlaySocket(id?: string, options: PlaySocketOptions)

Configuration options

| Option | Type | Default | Description | |--------|------|---------|-------------| | endpoint | string | none - set this! | WebSocket server endpoint (e.g., 'wss://example.com/socket') | | customData | object | {} | Arbitrary data to pass to the "clientRegistered" server event (optional) | | debug | boolean | false | Set to true to enable extra logging |

Methods

| Method | Parameters | Return type | Description | |--------|------------|-------------|-------------| | init() | - | Promise<string> | Initialize the WebSocket connection – Returns Promise which resolves with the client's ID | | createRoom() | initialStorage?: object, size?: number | Promise<string> | Create a new room and become host – Returns Promise which resolves with the room ID. The room participant maximum is 100 | | joinRoom() | roomId: string | Promise<void> | Join an existing room | | destroy() | - | void | Use this to leave a room and close the connection | | updateStorage() | key: string, type: 'set' \| 'array-add' \| 'array-add-unique' \| 'array-remove-matching' \| 'array-update-matching', value: any, updateValue?: any | void | Update a key in the shared storage (max. 100 keys). Array operation types allow for conflict-free simultaneous array updates. For '-matching' operations, value becomes the value to match, and updateValue the replacement | | sendRequest() | name: string, data?: any | void | Send requests to the server with optional custom data (handle these in the requestReceived server event) | | onEvent() | event: string, callback: Function | void | Register an event callback |

Event types

| Event | Callback parameter | Description | |-------|-------------------|-------------| | status | status: string | Connection status updates | | error | error: string | Error events | | instanceDestroyed | - | Destruction event - triggered by manual .destroy() method invocation or by fatal errors and disconnects | | storageUpdated | storage: object | Storage state changes | | hostMigrated | roomId: string | Host changes | | clientConnected | clientId: string | New client connected to the room | | clientDisconnected | clientId: string, roomId?: string | Client disconnected from the room |

Properties (Read-only)

| Property | Type | Description | |----------|------|-------------| | id | string | Client's unique identifier on the WebSocket server | | isHost | boolean | If this user is currently assigned the host role | | connectionCount | number | Number of active client connections in room (without yourself) | | getStorage | object | Retrieve storage object |

 

PlaySocket Server

PlaySocket includes a server implementation that can be set up in seconds.

Installation

To use the server component, you'll need to install playsocketjs and the ws package:

npm install playsocketjs ws

Usage examples

Here are usage examples for a standalone server and an Express.js application.

Standalone server

import PlaySocketServer from 'playsocketjs/server'; // Both ES Module & CommonJS Module syntax is supported

const server = new PlaySocketServer(); // Create and start the server (default path is /)

// Gracefully disconnect all clients and close the server (optional)
function shutdown() {
    server.stop();
    process.exit(0);
}

// Handle both SIGINT (Ctrl+C) and SIGTERM (Docker stop)
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);

Together with Express.js (or other Backend frameworks)

const express = require('express');
const http = require('http');
const PlaySocketServer = require('playsocketjs/server');

const app = express();
const httpServer = http.createServer(app);

// Create PlaySocket server with your HTTP server
const playSocketServer = new PlaySocketServer({
  server: httpServer,
  path: '/socket'
});

// Start the server
httpServer.listen(3000, () => {
  console.log('Server running on port 3000');
});

// Gracefully disconnect all clients and close the server (recommended)
function shutdown() {
    server.stop();
    process.exit(0);
}

// Handle both SIGINT (Ctrl+C) and SIGTERM (Docker stop)
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);

API reference

Constructor

Creates a new PlaySocket Server instance with configuration options.

new PlaySocket(options: PlaySocketServerOptions)

Configuration options

| Option | Type | Default | Description | |--------|------|---------|-------------| | port | number | 3000 | Port to listen on (used only if no server provided) | | path | string | '/' | WebSocket endpoint path | | server | http.Server | - | Existing http server (optional) | | rateLimit | number | 20 | Adjust the messages/second rate limit | | debug | boolean | false | Set to true to enable extra logging |

Methods

| Method | Parameters | Return type | Description | |--------|------------|-------------|-------------| | stop() | - | void | Closes all active client connections, the websocket server and the underlying http server if it's standalone | | kick() | clientId: string, reason?: string | void | Kick a client by their clientID – this will close their connection and set an error message | | onEvent() | event: string, callback: Function | void | Register a server-side event callback | | getRoomStorage() | roomId: string | object | Get a snapshot of the current room storage | | updateRoomStorage() | roomId: string, key: string, type: 'set' \| 'array-add' \| 'array-add-unique' \| 'array-remove-matching' \| 'array-update-matching', value: any, updateValue?: any | void | Update a key in the shared room storage from the server | | createRoom() | initialStorage?: object, size?: number, host?: string | object | Create a room (returns object containing room ID and state) – Rooms created with a non-player host like "server" (default) will not be deleted when the last participant leaves | | destroyRoom() | roomId: string | void | Destroy a room & kick all participants |

Event types

| Event | Callback parameters | Description | Return for action | |-------|-------------------|-------------|--------------| | clientRegistered | clientId: string, customData: object | Client registered with the server | - | | clientRegistrationRequested | clientId: string, customData: object | Client requests to register | Return false or rejection reason string to block | | clientDisconnected | clientId: string | Client disconnected from the server | - | | clientJoinedRoom | clientId: string, roomId: string | Client joined a room (clients can only leave by disconnecting) | - | | clientJoinRequested | clientId: string, roomId: string | Client requests to join a room | Return false or rejection reason string to block | | roomCreated | roomId: string | Client created a room | - | | roomDestroyed | roomId: string | Room was destroyed (happens when all participants leave) | - | | roomCreationRequested | {clientId: string, initialStorage: object} | Room creation requested by client | Return object to override initial storage, false to deny | | storageUpdated | {clientId: string, roomId: string, update: object, storage: object} | Room storage property updated | - | | storageUpdateRequested | {clientId: string, roomId: string, update: object, storage: object} | Room storage property update requested by client | Return false to block the update | | requestReceived | {clientId: string, roomId?: string, requestName: string, data?: any} | Request from client was received by the server | - |

Properties (Read-only)

| Property | Type | Description | |----------|------|-------------| | getRooms | object | Retrieve the rooms object |

License

MIT