CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-protobufjs

Protocol Buffers for JavaScript with TypeScript support, providing pure JavaScript implementation for serializing and deserializing structured data using Google's Protocol Buffer format.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

binary-io.mddocs/

Binary I/O Operations

Low-level binary reading and writing operations for custom serialization needs, performance optimization, and direct protobuf wire format manipulation.

Capabilities

Writer Class

Binary writer for encoding protobuf wire format data with buffering and type-specific encoding methods.

class Writer {
  /**
   * Current length of written data
   */
  len: number;
  
  /**
   * Operation head (internal)
   */
  head: Operation;
  
  /**
   * Operation tail (internal)
   */
  tail: Operation;
  
  /**
   * State stack for nested operations
   */
  states: State[];
  
  /**
   * Creates a new writer instance
   * @returns Writer instance
   */
  static create(): Writer;
  
  /**
   * Writes unsigned 32-bit integer
   * @param value - Value to write (0 to 4294967295)
   * @returns This writer
   */
  uint32(value: number): Writer;
  
  /**
   * Writes signed 32-bit integer
   * @param value - Value to write (-2147483648 to 2147483647)
   * @returns This writer
   */
  int32(value: number): Writer;
  
  /**
   * Writes signed zigzag-encoded 32-bit integer
   * @param value - Value to write
   * @returns This writer
   */
  sint32(value: number): Writer;
  
  /**
   * Writes unsigned 64-bit integer
   * @param value - Value as number or Long
   * @returns This writer
   */
  uint64(value: number | Long | string): Writer;
  
  /**
   * Writes signed 64-bit integer
   * @param value - Value as number or Long
   * @returns This writer
   */
  int64(value: number | Long | string): Writer;
  
  /**
   * Writes signed zigzag-encoded 64-bit integer
   * @param value - Value as number or Long
   * @returns This writer
   */
  sint64(value: number | Long | string): Writer;
  
  /**
   * Writes fixed 32-bit unsigned integer (little endian)
   * @param value - Value to write
   * @returns This writer
   */
  fixed32(value: number): Writer;
  
  /**
   * Writes fixed 32-bit signed integer (little endian)
   * @param value - Value to write
   * @returns This writer
   */
  sfixed32(value: number): Writer;
  
  /**
   * Writes fixed 64-bit unsigned integer (little endian)
   * @param value - Value as number or Long
   * @returns This writer
   */
  fixed64(value: number | Long | string): Writer;
  
  /**
   * Writes fixed 64-bit signed integer (little endian)
   * @param value - Value as number or Long
   * @returns This writer
   */
  sfixed64(value: number | Long | string): Writer;
  
  /**
   * Writes 32-bit float (IEEE 754)
   * @param value - Float value
   * @returns This writer
   */
  float(value: number): Writer;
  
  /**
   * Writes 64-bit double (IEEE 754)
   * @param value - Double value
   * @returns This writer
   */
  double(value: number): Writer;
  
  /**
   * Writes boolean value
   * @param value - Boolean value
   * @returns This writer
   */
  bool(value: boolean): Writer;
  
  /**
   * Writes string value (UTF-8 encoded)
   * @param value - String value
   * @returns This writer
   */
  string(value: string): Writer;
  
  /**
   * Writes byte array
   * @param value - Byte array
   * @returns This writer
   */
  bytes(value: Uint8Array | string): Writer;
  
  /**
   * Writes protobuf tag (field number and wire type)
   * @param id - Field id
   * @param wireType - Wire type
   * @returns This writer
   */
  tag(id: number, wireType: number): Writer;
  
  /**
   * Forks this writer (creates nested length-delimited context)
   * @returns Forked writer
   */
  fork(): Writer;
  
  /**
   * Resets writer to initial state
   * @returns This writer
   */
  reset(): Writer;
  
  /**
   * Finishes length-delimited context
   * @returns This writer
   */
  ldelim(): Writer;
  
  /**
   * Finishes writing and returns buffer
   * @returns Encoded binary data
   */
  finish(): Uint8Array;
}

Usage Examples:

const protobuf = require("protobufjs");

// Basic writer usage
const writer = protobuf.Writer.create();
writer.tag(1, 2)        // Field 1, length-delimited
      .string("hello")   // String value
      .tag(2, 0)         // Field 2, varint
      .uint32(42);       // Integer value

const buffer = writer.finish();
console.log("Encoded bytes:", Array.from(buffer));

// Length-delimited message writing
const writer2 = protobuf.Writer.create();
writer2.tag(1, 2);      // Field 1, length-delimited

const fork = writer2.fork();  // Start nested message
fork.tag(1, 2).string("nested");
fork.tag(2, 0).uint32(123);
writer2.ldelim();       // Finish nested message

const nestedBuffer = writer2.finish();

BufferWriter Class

Node.js-specific writer that outputs Node.js Buffer instead of Uint8Array.

class BufferWriter extends Writer {
  /**
   * Finishes writing and returns Node.js Buffer
   * @returns Encoded binary data as Buffer
   */
  finish(): Buffer;
}

Usage Examples:

// Node.js specific buffer writing
const writer = new protobuf.BufferWriter();
writer.tag(1, 2).string("test");
const buffer = writer.finish();
console.log("Buffer type:", buffer instanceof Buffer); // true

Reader Class

Binary reader for decoding protobuf wire format data with position tracking and type-specific decoding methods.

class Reader {
  /**
   * Source buffer
   */
  buf: Uint8Array;
  
  /**
   * Current reading position
   */
  pos: number;
  
  /**
   * Buffer length
   */
  len: number;
  
  /**
   * Creates reader from buffer
   * @param buffer - Buffer to read from
   * @returns Reader instance
   */
  static create(buffer: Uint8Array): Reader;
  
  /**
   * Reads unsigned 32-bit integer
   * @returns Decoded value
   */
  uint32(): number;
  
  /**
   * Reads signed 32-bit integer
   * @returns Decoded value
   */
  int32(): number;
  
  /**
   * Reads signed zigzag-decoded 32-bit integer
   * @returns Decoded value
   */
  sint32(): number;
  
  /**
   * Reads unsigned 64-bit integer
   * @returns Decoded value as Long
   */
  uint64(): Long;
  
  /**
   * Reads signed 64-bit integer
   * @returns Decoded value as Long
   */
  int64(): Long;
  
  /**
   * Reads signed zigzag-decoded 64-bit integer
   * @returns Decoded value as Long
   */
  sint64(): Long;
  
  /**
   * Reads fixed 32-bit unsigned integer (little endian)
   * @returns Decoded value
   */
  fixed32(): number;
  
  /**
   * Reads fixed 32-bit signed integer (little endian)
   * @returns Decoded value
   */
  sfixed32(): number;
  
  /**
   * Reads fixed 64-bit unsigned integer (little endian)
   * @returns Decoded value as Long
   */
  fixed64(): Long;
  
  /**
   * Reads fixed 64-bit signed integer (little endian)
   * @returns Decoded value as Long
   */
  sfixed64(): Long;
  
  /**
   * Reads 32-bit float (IEEE 754)
   * @returns Decoded float value
   */
  float(): number;
  
  /**
   * Reads 64-bit double (IEEE 754)
   * @returns Decoded double value
   */
  double(): number;
  
  /**
   * Reads boolean value
   * @returns Decoded boolean
   */
  bool(): boolean;
  
  /**
   * Reads string value (UTF-8 decoded)
   * @returns Decoded string
   */
  string(): string;
  
  /**
   * Reads byte array
   * @returns Decoded bytes
   */
  bytes(): Uint8Array;
  
  /**
   * Reads protobuf tag
   * @returns Object with id and wireType properties
   */
  tag(): { id: number; wireType: number };
  
  /**
   * Skips specified number of bytes
   * @param length - Number of bytes to skip
   * @returns This reader
   */
  skip(length: number): Reader;
  
  /**
   * Skips value of specified wire type
   * @param wireType - Wire type to skip
   * @returns This reader
   */
  skipType(wireType: number): Reader;
}

Usage Examples:

// Basic reader usage
const reader = protobuf.Reader.create(buffer);

while (reader.pos < reader.len) {
    const tag = reader.tag();
    console.log(`Field ${tag.id}, wireType ${tag.wireType}`);
    
    switch (tag.wireType) {
        case 0: // varint
            const value = reader.uint32();
            console.log("Varint value:", value);
            break;
        case 2: // length-delimited  
            const bytes = reader.bytes();
            console.log("Bytes length:", bytes.length);
            break;
        default:
            reader.skipType(tag.wireType);
    }
}

// Manual message decoding
function decodeMessage(buffer) {
    const reader = protobuf.Reader.create(buffer);
    const message = {};
    
    while (reader.pos < reader.len) {
        const tag = reader.tag();
        
        switch (tag.id) {
            case 1:
                message.name = reader.string();
                break;
            case 2:
                message.id = reader.uint32();
                break;
            default:
                reader.skipType(tag.wireType);
        }
    }
    
    return message;
}

BufferReader Class

Node.js-specific reader for reading from Node.js Buffer objects.

class BufferReader extends Reader {
  /**
   * Source buffer as Node.js Buffer
   */
  buf: Buffer;
  
  /**
   * Creates reader from Node.js Buffer
   * @param buffer - Buffer to read from
   * @returns BufferReader instance
   */
  static create(buffer: Buffer): BufferReader;
}

Wire Type Constants

Protobuf wire type constants for low-level operations.

namespace WireType {
  const Varint: 0;          // int32, int64, uint32, uint64, sint32, sint64, bool, enum
  const Fixed64: 1;         // fixed64, sfixed64, double
  const LengthDelimited: 2; // string, bytes, embedded messages, packed repeated fields
  const StartGroup: 3;      // deprecated
  const EndGroup: 4;        // deprecated  
  const Fixed32: 5;         // fixed32, sfixed32, float
}

Usage Examples:

// Using wire type constants
const writer = protobuf.Writer.create();

// Write string field (field 1)
writer.tag(1, protobuf.util.WireType.LengthDelimited);
writer.string("hello world");

// Write integer field (field 2)  
writer.tag(2, protobuf.util.WireType.Varint);
writer.uint32(42);

// Write float field (field 3)
writer.tag(3, protobuf.util.WireType.Fixed32);
writer.float(3.14);

Advanced Operations

Advanced binary I/O operations for complex use cases.

class Writer {
  /**
   * Writes raw buffer data
   * @param buffer - Raw buffer to write
   * @returns This writer
   */
  raw(buffer: Uint8Array): Writer;
  
  /**
   * Gets current operation state
   * @returns Current state object
   */
  state(): State;
  
  /**
   * Pushes new state onto stack
   * @param state - State to push
   * @returns This writer
   */
  push(state: State): Writer;
  
  /**
   * Pops state from stack
   * @returns Popped state
   */
  pop(): State;
}

class Reader {
  /**
   * Creates sub-reader for specified length
   * @param length - Length of sub-buffer
   * @returns New reader for sub-buffer
   */
  slice(length: number): Reader;
  
  /**
   * Reads remaining bytes
   * @returns All remaining bytes
   */
  remaining(): Uint8Array;
}

Usage Examples:

// Advanced writer operations
const writer = protobuf.Writer.create();

// Write custom data format
const customData = new Uint8Array([0x01, 0x02, 0x03]);
writer.tag(1, 2);                    // Length-delimited
writer.uint32(customData.length);    // Length prefix
writer.raw(customData);              // Raw data

// Complex nested structures
const fork1 = writer.fork();
fork1.tag(1, 2).string("level1");

const fork2 = fork1.fork();
fork2.tag(1, 2).string("level2");
fork1.ldelim();  // Close level2

writer.ldelim();  // Close level1

// Advanced reader operations
const reader = protobuf.Reader.create(buffer);
const tag = reader.tag();

if (tag.wireType === 2) {  // Length-delimited
    const length = reader.uint32();
    const subReader = reader.slice(length);
    
    // Process sub-message with dedicated reader
    while (subReader.pos < subReader.len) {
        const subTag = subReader.tag();
        // Process sub-fields...
    }
}

Types

interface Operation {
  fn: Function;
  len: number;
  next: Operation | null;
}

interface State {
  head: Operation;
  tail: Operation; 
  len: number;
}

interface Long {
  low: number;
  high: number;
  unsigned: boolean;
  toNumber(): number;
  toString(): string;
}

namespace util {
  namespace WireType {
    const Varint: 0;
    const Fixed64: 1;
    const LengthDelimited: 2;
    const StartGroup: 3;
    const EndGroup: 4;
    const Fixed32: 5;
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-protobufjs

docs

binary-io.md

cli-tools.md

code-generation.md

index.md

proto-loading.md

reflection.md

rpc-services.md

serialization.md

tile.json