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

@footgun/network

v0.5.1

Published

A node.js library for low latency, realtime networking over UDP.

Readme

@footgun/network

A node.js library for low latency, realtime networking over UDP.

Features:

  • low latency message delivery
  • does not leak memory
  • unreliable-unordered channels
  • reliable-ordered channels
  • per-endpoint Round Trip Time (RTT) estimation
  • send/receive transfer speed estimations
  • data oriented design
  • has unit and soak tests
  • minimal (~1k lines of code)
  • pure es module

Usage

How to set up a run loop, send/receive messages

import * as Network from '@footgun/network'
import dgram        from 'dgram'


async function main () {
    const socket = dgram.createSocket('udp4')

    // listen for data, local:   address     port
    await bind(socket,          '0.0.0.0',   3000)

    // create endpoint, remote:             address   port
    const endpoint = Network.create(socket, '0.0.0.0', 3000)

    // unreliable channels are great for high volume eventually consistent data like player positions, etc.
    Network.addChannel(endpoint, Network.CHANNEL_UNRELIABLE)

    // reliable channels are useful for lower volume events that need guaranteed, in order delivery
    // e.g., I'm entering a vehicle, I'm shooting a missile, etc.
    Network.addChannel(endpoint, Network.CHANNEL_RELIABLE)


    // listen for new data on the UDP socket
    socket.on('message', function (message, rinfo) {
        Network.readPacket(endpoint, message) // process all received data through the endpoint
    })

    // the channels ids are based on the order they were added to the endpoint.
    // so for example above we first called Network.addChannel(...) with CHANNEL_UNRELIABLE so it's channelid is 0
    const unreliableChannelId = 0
    const reliableChannelId = 1

    // define a structure that will hold messages read from the network
    const messages = new Array(2048)
    for (let i=0; i < messages.length; i++) {
        messages[i] = {
            len: 0,
            msg: new Uint8Array(1024),
        }
    }


    const gameLoop = function () {

        // send one message over unreliable channel
        const [ x, y ] = [ 100, 106 ]
        const playerPosMsg = new Uint8Array([ x, y ]) // a simple 2 byte message to send
        Network.sendMessage(endpoint, unreliableChannelId, playerPosMsg, playerPosMsg.byteLength)

        // send one message over reliable channel
        const enterVehicleMsg = new Uint8Array([ 23, 106, 255, 0, 24, 14, 91 ]) 
        Network.sendMessage(endpoint, reliableChannelId, enterVehicleMsg, enterVehicleMsg.byteLength)


        // receive messages over the unreliable channel (each message is a Uint8Array)
        let msgCount = Network.readMessages(endpoint, unreliableChannelId, messages)

        // process each message received over the uneliable channel
        for (let i=0; i < msgCount; i++) {
            const um = messages[i]  // um.msg is the data, um.len is how many bytes are in it
        }


        // also an array of messages, but the reliable channels will ensure the order is
        // maintained, so if packets are dropped or arrive out of order you can still have
        // confidence you'll see a consistent ordered message stream here that matches what
        // the sending side put in.
        msgCount = Network.readMessages(endpoint, reliableChannelId, messages)

        // process each message received over the reliable channel
        for (let i=0; i < msgCount; i++) {
            const um = messages[i]  // um.msg is the data, um.len is how many bytes are in it
        }


        // package all queued messages into packets and send them over the underlying UDP socket
        Network.transmitPackets(endpoint)

        // stats:

        // network round trip in milliseconds
        //console.log('RTT:', endpoint.RTT)

        // upload rate in bytes/second
        //console.log('upload:', endpoint.bandwidth.sendSpeed)

        // download rate in bytes/second
        //console.log('download:', endpoint.bandwidth.recvSpeed)

        setTimeout(gameLoop, 1)
    }

    gameLoop() // start running the game
}


main()


async function bind (socket, listenAddress, listenPort) {
    return new Promise(function (resolve, reject) {
        socket.bind(listenPort, listenAddress, function (er) {
            if (er)
                return reject(er)

            const address = socket.address()
            console.log(`Server listening at ${address.address}:${address.port}.`)
            resolve()
        })
    })
}

References

  • https://gafferongames.com/post/reliability_ordering_and_congestion_avoidance_over_udp
  • https://github.com/mas-bandwidth/yojimbo
  • https://github.com/padenot/ringbuf.js