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

protostream

v0.1.1

Published

Emits protobuf messages from a stream, as they are encountered.

Downloads

8

Readme

ProtoStream

Protocol Buffers have no default framing for use in a streaming protocol, such as TCP.

ProtoStream is a Stream Transform. Its input is a stream of fragments of wrapped protobuf messages. Its outputs are discrete Protocol Buffer messages, which can be decoded by the library of your choice.

Theory

In Protocol Buffers, the serialisation of a one wrapper message with N repeated child messages is identical to the serialisation of the concatenated serialisation of N wrapper messages with one child message each.

From the test suite:

var bufA = Wrapper.serialize({wrapped:[people.fred,people.wilma,people.barney]});
var bufB = Buffer.concat([Wrapper.serialize({wrapped:[people.fred]}),
                          Wrapper.serialize({wrapped:[people.wilma]}),
                          Wrapper.serialize({wrapped:[people.barney]})]);
assert.deepEqual(bufA, bufB);

This allows us to represent a stream as a wrapper message with repeating elements, yet send indiviual message into the stream by wrapping and sending them one at a time.

This has the benefit that a the full content of a stream can be decoded as a single message of type "Wrapper". This is really good for compatibility with tools that can decode protobuf messages, such as Wireshark.

The .proto file used, includes the Wrapper message, and a Person message from Google's examples.

test.proto:

package test;

message Wrapper {
  repeated Person wrapped = 42; // large number (>15) to test multibyte field key
}

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

See The Protocol Buffers documentation for more information on the encoding format.

Implementation

ProtoStream is a NodeJS module which uses a state machine to emit the individual child messages, one by one, as bytes are received.

These child messages can then be decoded separately, by the Protobuf library of your choice.

From the test suite:

var protostream = ps.createProtoStream();

// collect each received child message as a separate buffer, in an array (rxd)
var rxd = [];
protostream.on('data', function(data) {
  rxd.push(data);
});

// make a buffer containing two (wrapped) protobuf messages
protostream.write(Buffer.concat([Wrapper.serialize({wrapped:[people.fred]}),
                                 Wrapper.serialize({wrapped:[people.wilma]})]));

// check that they have been split on the right boundary
assert.deepEqual(Person.parse(rxd[0]), people.fred);
assert.deepEqual(Person.parse(rxd[1]), people.wilma);

// check that the ProtoStream stream transform continues to work
protostream.write(Wrapper.serialize({wrapped:[people.barney]}));
assert.deepEqual(Person.parse(rxd[2]), people.barney);

To Do

  • The state machine operates on single bytes, as needed by the WAIT_KEY and WAIT_LEN states. The WAIT_BYTES state would be capable of processing whole chunks, without the function-call-per-byte overhead, if the state machine were modified.