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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@spacelys/sockets

v0.2.0

Published

![Version](https://storage.googleapis.com/spacelys/sockets/outputs/latest/badges/version.svg) ![Coverage](https://storage.googleapis.com/spacelys/sockets/outputs/latest/badges/coverage.svg) ## Basic Overview

Readme

SpacelySocket

Version Coverage

Basic Overview

Manage your clients and websocket server with the use of Spaces. These Spaces make it easy to organize clients and events in a compartmentalized manner.

Installation and Usage

npm install @spacelys/sockets --save

Spaces

Spaces are how we compartmentalized our websocket server. All messages are processed by the same server. We segment our server via Spaces to handle logical groupings of events. You might have a game server where you have a mainSpace, lobbySpace, gameSpace. The mainSpace could be responsible for general events like private messages. The lobbySpace would be responsible to group players together before starting the game. The gameSpace would then be responsible for handling events that happen in the game as to not clutter the lobbySpace with server game logic.


Setting up a Simple Space Server

import * as Spacely from '@spacelys/sockets'

const serverSpace = Spacely.listen<any>(4321);

serverSpace.onJoin((from: Spacely.Client) => {
    // do something when a client joines
});

serverSpace.onMessage((from: Spacely.Client, message: any) => {
    // do something when client sends a message
});

serverSpace.onLeave((from: Spacely.Client) => {
    // handle a client disconnecting from the space
});

Sub Spaces

You will create your main Space when starting up your server. You can then create sub Spaces from any Spaces to handle different type of clients and events.

interface LobbyState { messages: Array<string> };

const serverSpace = Spacely.listen<any>(4321);
const lobbySpace = serverSpace.createSpace<LobbyState>(
    "mainLobby",
    (): LobbyState => ({ messages: [] })
);

serverSpace.onJoin((from: Spacely.Client) => {
    if (from.getUID() !== "dont-let-this-guy-in") {
        lobbySpace.addClient(from);
    }
});

lobbySpace.onJoin((from: Spacely.Client) => {
    from.reply("Welcome! Glad you arent that guy we dont like");
});

Space State

Each space is assigned its own state object to manage. The type of the state is defined when you create a new Space. Any sub Space is automatically given the same state type as its parent but with its own copy to manage.

interface MyStateObject = { valuesGiven: Array<number> };
const serverSpace = Spacely.listen<MyStateObject>(
    4321, // port to listen on
    () => ({ valuesGiven: [] }) // when supplied, this will create the initial state of your Space
);

serverSpace.onJoin((from: Spacely.Client) => {
    const {valuesGiven} = serverSpace.getState();
    const lastValue = valuesGiven.length > 0 ? valuesGiven.slice(-1)[0] : -1;
    const value = Math.random() * 100;
    from.reply(`You were assigned ${value} points!, last person got ${lastValue}`);
    valuesGiven.push(value);
    serverSpace.setState({
        valuesGiven
    });
});

Responding to Client

Outside of the reply method which we will go more into depth on in the Client section of this readme, we can also broadcast to all or some connected clients.

const serverSpace = Spacely.listen<any>(4321);

setTimeout(() => {
    serverSpace.broadcast("server is shutting down!") // server is shutting down in 4 hours
}, 1000 * 60 * 60 * 4);

serverSpace.onMessage((from: Spacely.Client, message: any) => {
    from.reply('message received');
    // broadcast to all the connected users, except the one that actually sent the message, what that user wrote
    serverSpace.broadcast(`A user wrote ${message}`, [from]);
});

Clients

Connected clients will only receive messages from the Spaces they are connected to.


UUID

When a client joins the server they will get assigned a unique id. This id will be the same regardless of what space they are on. However if the client disconnected from the server and rejoins, a new id will be generated.

...
lobbySpace.onMessage((from: Spacely.Client, message: any) => {
    const lobbyState = lobbySpace.getState();
    if (message.type === "chat" ) {
        const id = from.getUID();
        lobbyState[id].messages.push(message.payload);
    }
});
gameSpace.onMessage((from: Spacely.Client, message: any) => {
    const gameState = lobbySpace.getState();
    if (message.type === "move" ) {
        const id = from.getUID();
        gameState[id].pos = message.newPosition;
    }
});

Replying

We can send a message directly to a client by using the reply method. Internally all communication is actually handled by this reply method.

luckyNumber = ...;
gameSpace.onMessage((from: Spacely.Client, message: any) => {
    if (message === luckyNumber) {
        from.reply("you got it!");
    } else {
        from.reply("try again");
    }
});

Disconnecting

mainSpace.onMessage((from: Spacely.Client, message: any) => {
    if (message === "exit-server") {
        // Removes from ALL spaces and terminates their websocket connection
        //(onLeave gets called for all the Spaces they were in)
        from.disconnect();
    }
});

gameSpace.onMessage((from: Spacely.Client, message: any) => {
    if (message === "leave-game") {
        // Removes client from gameSpace, their websocket connection is still 
        // active on the server (onLeave gets called for gameSpace)
        gameSpace.removeClient(from);
    }
});

gameSpace.onLeave((from: Spacely.Client) => {
    gameSpace.broadcast(`${from.getUID()} has left`);
});

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure the changes in the Pull Request pass the cloud build checks setup. Merges to master will automatically publish NPM package. Ensure that the version number is correct before merging your PR into master as that is the version number the package will be published with.

License

MIT