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

binary-packet

v1.0.11

Published

Lightweight and hyper-fast, zero-dependencies, TypeScript-first, schema-based binary packets serialization and deserialization library

Downloads

66

Readme

binary-packet

Lightweight and hyper-fast, zero-dependencies, TypeScript-first, schema-based binary packets serialization and deserialization library.
Originally made to be used for an ultrafast WebSockets communication with user-defined type-safe messages between client and server, with the smallest bytes usage possible.

Supports serializing into and deserializing from DataViews, ArrayBuffers and Buffers (NodeJS/Bun only).
To achieve the maximum performance is it always advised to use node Buffer(s) when available.

Installation

Node:
npm install binary-packet

Bun:
bun add binary-packet

Features & Specification

Define the structure of the packets through unique Packet IDs and "schema" objects.
This "schema" object is simply called Definition and defines the shape of a packet: specifically its fields and their types.

Fields / Data types

Currently, these kinds of fields are supported: | Type | Description | Values | Size (bytes) | |------|-------------|--------------|--------------| | Field.UNSIGNED_INT_8 | 8 bits unsigned integer | 0 - 255 | 1 | | Field.UNSIGNED_INT_16 | 16 bits unsigned integer | 0 - 65535 | 2 | | Field.UNSIGNED_INT_32 | 32 bits unsigned integer | 0 - 4294967295 | 4 | | Field.INT_8 | 8 bits signed integer | -128 - 127 | 1 | | Field.INT_16 | 16 bits signed integer | -32768 - 32767 | 2 | | Field.INT_32 | 32 bits signed integer | -2147483648 - 2147483647 | 4 | | Field.FLOAT_32 | 32 bits IEEE754 floating-point | | 4 | | Field.FLOAT_64 | 64 bits IEEE754 floating-point | | 8 | | BinaryPacket | BinaryPacket "subpacket" | BinaryPacket | size(BinaryPacket) | | FieldString | ASCII or single octet utf-8 chars string | Up to 65536 chars | 2 + length | | FieldArray | Dynamically-sized array of one of the types above | Up to 256 elements | 1 + length * size(Element) | | FieldFixedArray | Statically-sized array of one of the types above | Any pre-defined numbers of elements | length * size(Element) | | FieldBitFlags | Boolean flags packed into a single 8 bits integer | Up to 8 boolean flags | 1 | | FieldOptional | Optional BinaryPacket "subpacket" | BinaryPacket | undefined | 1 + size(BinaryPacket) |

As shown, both arrays and nested objects ("subpackets") are supported.
Note: FieldFixedArray is much more memory efficient and performant than FieldArray, but require a pre-defined length.

Pattern matching

The library exposes an easy way to "pattern match" packets of a yet-unknown-type in a type-safe manner through a visitor pattern.
For an example, search for "pattern matching" in the examples below.

Usage Examples

Example: (incomplete) definition of a simplistic board game

import { BinaryPacket, Field, FieldArray } from 'binary-packet'

// Suppose we have a game board where each cell is a square and is one unit big.
// A cell can be then defined by its X and Y coordinates.
// For simplicity, let's say there cannot be more than 256 cells, so we can use 8 bits for each coordinate.
const Cell = {
  x: Field.UNSIGNED_INT_8,
  y: Field.UNSIGNED_INT_8
}

// When done with the cell definition we can create its BinaryPacket writer/reader.
// NOTE: each BinaryPacket needs an unique ID, for identification purposes and error checking.
const CellPacket = BinaryPacket.define(0, Cell)

// Let's now make the definition of the whole game board.
// You can also specify arrays of both "primitive" fields and other BinaryPackets.
const Board = {
  numPlayers: Field.UNSIGNED_INT_8,
  otherStuff: Field.INT_32,
  cells: FieldArray(CellPacket)
}

// When done with the board definition we can create its BinaryPacket writer/reader.
// NOTE: each BinaryPacket needs an unique ID, for identification purposes and error checking.
const BoardPacket = BinaryPacket.define(1, Board)

//////////////////
// WRITING SIDE //
//////////////////
const buffer = BoardPacket.writeNodeBuffer({
  numPlayers: 1,
  otherStuff: 69420,
  cells: [
    { x: 0, y: 0 },
    { x: 1, y: 1 }
  ]
})

// ...
// sendTheBufferOverTheNetwork(buffer)
// ...

//////////////////
// READING SIDE //
//////////////////
import assert from 'assert'

// ...
// const buffer = receiveTheBufferFromTheNetwork()
// ...

const board = BoardPacket.readNodeBuffer(buffer)

assert(board.numPlayers === 1)
assert(board.otherStuff === 69420)
assert(board.cells.length === 2)
assert(board.cells[0].x === 0)
assert(board.cells[0].y === 0)
assert(board.cells[1].x === 1)
assert(board.cells[1].y === 1)

Example: pattern matching

import assert from 'assert/strict'
import { BinaryPacket, Field } from 'binary-packet'

// Packet A definition
const A = BinaryPacket.define(1)

// Packet B definition: This is the kind of packets that we care about in this example!
const B = BinaryPacket.define(2, { data: Field.UNSIGNED_INT_8 })

// Packet C definition
const C = BinaryPacket.define(3)

// Assume the following packet comes from the network or, for some other reason, is a buffer we do not know anything about.
const buffer = B.writeNodeBuffer({ data: 255 })

BinaryPacket.visitNodeBuffer(
  buffer,

  A.visitor(() => assert(false, 'Erroneously accepted visitor A')),

  B.visitor(packet => {
    // Do something with the packet
    assert.equal(packet.data, 255)
    console.log('Accepted visitor B:', packet)
  }),

  C.visitor(() => assert(false, 'Erroneously accepted visitor C'))
)

Benchmarks & Alternatives

Benchmarks are not always meant to be taken seriously.
Most of the times the results of a benchmark do not actually show the full capabilities of each library.
So, take these "performance" comparisons with a grain of salt; or, even better, do your own benchmarks with the actual data you need to serialize/deserialize.

This library has been benchmarked against the following alternatives:

  • msgpackr - A very popular, fast and battle-tested library. Currently offers more features than binary-packet, but it always appears to be slower and is also less type-safe.
  • restructure - An older, popular schema-based library, has some extra features like LazyArrays, but it is much slower than both binary-packet and msgpackr. And, sadly, easily crashes with complex structures.

The benchmarks are executed on three different kinds of packets:

  • EmptyPacket: basically an empty javascript object.
  • SimplePacket: objects with just primitive fields, statically-sized arrays and a string.
  • ComplexPacket: objects with primitives, statically-sized arrays, dynamically-sized arrays, bitflags, a string, an array of strings and other nested objects/arrays.

You can see and run the benchmarks yourself if you:

Disclaimer

This library is still very new, thus not "battle-tested" in production enough, or may still have missing important features.
If you plan on serializing highly sensitive data or need to guarantee no crashes, use an alternative like msgpackr until this library becomes 100% production-ready.

Contribute

Would like to have more complex, but still hyper-fast and memory efficient, features?
Contribute on GitHub yourself or, alternatively, buy me a coffee!