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

ros2-cdr

v0.1.0

Published

CDR encode/decode against ros2msg definition text, for the rosbridge Foxglove-protocol server

Readme

ros2-cdr

CDR encode/decode against a structured ROS 2 type definition for Node.js — the client-side counterpart to the rosbridge server.

That server never decodes a ROS message: it relays opaque CDR byte payloads, leaving encode/decode to the client. ros2-cdr is that client piece: give it the structured type definition the server emits and the bytes, and it hands back structured values — and builds the bytes back for client-publish, service calls, and action goals.

The codec walks a pre-parsed field tree (a TypeDefinition) rather than re-parsing .msg text on the client: the server already parsed the IDL with rosidl, so it advertises the structure directly. Each channel/service/action is advertised with schemaEncoding: "ros2typedef" and its schema field set to the TypeDefinition object (from parse_schema.read_*_type_definition) — so a client reads channel.schema and hands it straight to MessageCodec. (This replaces the ros2msg text schema; the bridge no longer targets Foxglove Studio.) A text adapter is still available if you have ros2msg text from elsewhere — see From ros2msg text.

Zero runtime dependencies. No ROS install, no code generation. Written in TypeScript; ships compiled JS + type declarations.

Install

npm install ros2-cdr

Usage

import { MessageCodec, type TypeDefinition } from "ros2-cdr";

// `typeDefinition` is what the bridge emits for a channel (see below).
const codec = new MessageCodec(typeDefinition);

const value = codec.decode(cdrBytes); // -> nested object
const payload = codec.encode(value);  // -> Uint8Array of CDR bytes

Build the MessageCodec once per type and reuse it. Module-level decode(typeDefinition, data) / encode(typeDefinition, value) helpers exist for one-offs.

The type definition

A TypeDefinition is a root type name plus a flat map of every (transitively referenced) message type to its ordered fields — exactly the JSON parse_schema.read_*_type_definition produces:

{
  "rootType": "geometry_msgs/PointStamped",
  "types": {
    "geometry_msgs/PointStamped": [
      { "name": "header", "type": "std_msgs/Header",  "isArray": false, "arrayLength": null },
      { "name": "point",  "type": "geometry_msgs/Point", "isArray": false, "arrayLength": null }
    ],
    "geometry_msgs/Point": [
      { "name": "x", "type": "float64", "isArray": false, "arrayLength": null },
      { "name": "y", "type": "float64", "isArray": false, "arrayLength": null },
      { "name": "z", "type": "float64", "isArray": false, "arrayLength": null }
    ]
    // ... std_msgs/Header, builtin_interfaces/Time, ...
  }
}

Each field's type is a normalized primitive name (float64, uint8, string, …) or a pkg/Type reference; arrayLength is a number for a fixed-size array or null for a dynamic/bounded sequence. builtin_interfaces/Time and Duration always resolve even if omitted from types.

From ros2msg text

If all you have is the Foxglove-style concatenated ros2msg schema string (schemaEncoding: "ros2msg"), build a codec from it directly:

const codec = MessageCodec.fromRos2msgText(definitionText, "geometry_msgs/PoseStamped");

This parses the text into a TypeDefinition and is otherwise identical. parseRos2msgText(text, rootType) is also exported if you want the structure.

Value mapping

| ROS 2 type | JavaScript value | | -------------------------------- | ------------------------------------------------- | | bool | boolean | | 8/16/32-bit integers | number | | int64 / uint64 | bigint | | float32 / float64 | number | | string / wstring | string | | T[N] (fixed) / T[] (dynamic) | Array | | uint8[] / byte[] | Uint8Array (encode also accepts number[]) | | nested message | object |

Encoding requires every field to be present (no defaults are filled in); decoding returns every field.

What it implements

  • Classic CDR v1 encapsulation (the ROS 2 wire format): 4-byte header, little- or big-endian, with alignment measured from the byte after the header.
  • All ROS primitive types, string/wstring, fixed and dynamic/bounded arrays, and arbitrarily nested messages.
  • A structured TypeDefinition as the codec's native input, with a ros2msg definition-text adapter (MSG: pkg/Type blocks, Header / pkg/msg/Type shorthands, same-package bare references; constants and default values skipped). builtin_interfaces/Time and Duration always resolve.

Layout

src/cdr.ts          CdrReader / CdrWriter — CDR primitives, strings, alignment.
src/definition.ts   TypeDefinition/FieldDefinition types + parseRos2msgText adapter.
src/codec.ts        MessageCodec — walk a TypeDefinition over the CDR primitives.
test/               node:test suite: alignment, hand-computed byte vectors, round-trips.

Produced on the server by srv/parse_schema.py's read_msg_type_definition / read_srv_type_definition / read_action_type_definition.

Develop

npm install
npm test          # runs the TypeScript sources directly via Node's type stripping
npm run build     # emits dist/ (JS + .d.ts) via tsc

Requires Node.js >= 20 (the test runner uses native TypeScript type stripping; Node >= 22.6 for that, or run against the compiled dist/).

Limitations

  • Targets CDR v1 (the classic FastRTPS/CycloneDDS ROS 2 wire format), not XCDR2.
  • wstring is treated as UTF-16 code units (matching Foxglove Studio) and is the least exercised path.
  • Comment/constant stripping is line-based, so a # or = inside a string default value could be misparsed — defaults don't affect the wire format, so this only matters if you inspect the parsed schema.

License

Apache-2.0. See LICENSE.