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

nanocobs

v0.4.2

Published

Consistent Overhead Byte Stuffing. The nanocobs C implementation, compiled to WebAssembly.

Readme

nanocobs

Consistent Overhead Byte Stuffing. The nanocobs C implementation, compiled to WebAssembly.

npm install nanocobs

No install script -- installing never runs a compiler and cannot fail to build. Where the package carries a prebuilt native addon for your platform it uses that; everywhere else it falls back to WebAssembly, which is ~2 KB with zero imports, inlined as base64: no file to load, no fs, no fetch, no bundler plugin, no async init.

Framing

import { encode, decode } from 'nanocobs';

const frame = encode(payload);   // Uint8Array, trailing 0x00 delimiter included
const back = decode(frame);      // Uint8Array

decode is cobs_decode: it stops at the first delimiter and ignores anything after it, so a buffer holding more than one frame yields the first.

Reading a stream

decodeFrames is the shape a socket loop wants. It copies the buffer into wasm memory once and walks it there, so it stays linear however many frames the buffer holds:

import { decodeFrames } from 'nanocobs';

let carry = new Uint8Array(0);
socket.on('data', (chunk) => {
  const buf = concat(carry, chunk);
  const { frames, consumed } = decodeFrames(buf);
  for (const f of frames) handle(f);
  carry = buf.subarray(consumed);   // an incomplete trailing frame, if there was one
});

consumed stops short of a partial frame at the end, so the carry is exactly what the next read has to complete.

decodeFirst(buf) is the one-frame form, returning { payload, consumed }. Prefer decodeFrames for a whole buffer: decodeFirst copies all of what it is handed, so a decodeFirst(buf.subarray(i)) loop costs O(n²) in the frame count.

Caller-owned buffers

import { encodeInto, decodeInto, encodeMax, decodeMax } from 'nanocobs';

const frame = new Uint8Array(encodeMax(payload.length));
const n = encodeInto(payload, frame);              // bytes written

const out = new Uint8Array(decodeMax(n));
const m = decodeInto(frame.subarray(0, n), out);   // bytes written

tryEncodeInto and tryDecodeInto are the same calls without exceptions: they return the byte count, or a negative cobs_ret_t (-1 BAD_ARG, -2 BAD_PAYLOAD, -3 EXHAUSTED).

Errors

Failures throw a CobsError carrying the C's own return code, unchanged:

import { CobsError } from 'nanocobs';

try { decode(buf); }
catch (e) {
  if (CobsError.isCobsError(e)) e.code;   // 'BAD_ARG' | 'BAD_PAYLOAD' | 'EXHAUSTED'
}

isCobsError is a brand check rather than instanceof, so it survives duplicate copies of the package and cross-realm boundaries.

Isolation

Every entry point above shares one wasm instance. createCodec() returns one with its own linear memory, to reclaim what a large payload pinned or to isolate a worker:

import { createCodec } from 'nanocobs';

const codec = createCodec();
codec.encode(payload);
codec.memoryBytes;    // linear memory held; grows on demand, never shrinks

Backends

Both backends are the same cobs.c, and they are held to identical behaviour -- the same bytes, the same error codes -- by a conformance suite that runs every case through each. Which one you get is a performance question, not a behavioural one.

| | | |---|---| | Node, with a prebuild for your platform | native addon | | Node, anywhere else | wasm | | Browsers, bundlers, Deno, Workers | wasm |

Prebuilds ship for macOS (one universal binary covering Intel and Apple Silicon), Linux x64/arm64/armv7 (glibc and musl each) and ppc64, and Windows x64 and arm64. node-gyp-build picks one when the module is first imported, not at install time, so npm ci --ignore-scripts still gets the native backend. It is the package's only dependency and has none of its own.

import { backend } from 'nanocobs';
console.log(backend);   // 'native' | 'wasm'

Log that at startup. A missing prebuild falls back silently and looks exactly like the native path, so this is the only thing that tells you which you are running.

NANOCOBS_BACKEND=wasm forces the portable path without a code change. NANOCOBS_BACKEND=native turns a missing prebuild into a startup error instead of a quiet fallback -- useful in an environment where you are relying on native throughput. import 'nanocobs/wasm' always resolves to wasm.

On a platform with no prebuild you can build the addon yourself; the sources ship in the tarball:

npm install nanocobs --ignore-scripts
cd node_modules/nanocobs && npx node-gyp rebuild && \
  mkdir -p prebuilds/$(node -p 'process.platform+"-"+process.arch') && \
  cp build/Release/nanocobs.node prebuilds/$(node -p 'process.platform+"-"+process.arch')/

License

Unlicense OR 0BSD