mrkeyoor.com_
Wed 23 Sept 02:51 UTC
npmUtilsupdated 22 Sept 2026

byte-counter review

byte-counter 0.1.0 is the first release of a pass-through byte meter for JavaScript streams. Its default export is a Web TransformStream, while `byte-counter/node` supplies a Node Transform for `pipeline()` and classic `.pipe()` chains. Both expose a read-only `count` and forward each chunk unchanged. A separate `byteLength()` helper counts UTF-8 bytes in strings and reads the byte length of typed binary data. Our package check found no dependencies, bundled declarations, working import and require paths, and a 0.3 KB gzipped browser bundle.

Verdict

byte-counter 0.1.0 installed as one 1 MB package in 0.5 seconds, added no dependencies or audit findings, and produced a 0.3 KB gzipped browser bundle in our sandbox. Install it for passive byte totals across Web or Node streams; use a progress or limiting transform when the count must trigger behavior.

We installed it

Lab card: what happened when we installed byte-counterScreenshot of byte-counter documentation
Install✓ · 0.5s1 package on disk · 1 MB
ImportESM import works · require() works · ESM package with exports map
Browser0.3 KBgzipped (0.5 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does byte-counter install cleanly?

Yes. In a fresh container with an empty cache, npm install byte-counter finished in 0.5s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does byte-counter add to a browser bundle?

0.3 KB gzipped (0.5 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does byte-counter work with both ESM and CommonJS?

Yes. Both import 'byte-counter' and require('byte-counter') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does byte-counter include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

byte-counter or progress-stream: which should you use?

progress-stream: Choose it for Node streams that need percentage, speed, runtime, and ETA events. byte-counter 0.1.0 installed as one 1 MB package in 0.5 seconds, added no dependencies or audit findings, and produced a 0.3 KB gzipped browser bundle in our sandbox.

When should you not use byte-counter?

Your production runtime is below Node 20. Version 0.1.0 declares node >=20, and the package does not publish a legacy build.

API stability3/5Version 0.1.0 exposes a narrow surface: one Web stream class, one Node subpath, a read-only count, and `byteLength()`. The exports map prevents accidental internal imports, and the TypeScript declarations mirror those entry points. This is also the package's first published version, so there is no release history showing how names, accepted inputs, or the Node 20 requirement behave across upgrades.
Docs4/5The README puts Web Streams and Node streams in separate examples, names the `/node` import, lists the binary inputs accepted by `byteLength()`, and shows that an emoji occupies more bytes than its visible character count suggests. It does not explain reset behavior, oversized-input enforcement, fetch decompression versus Content-Length, or when a writer can stall without a reader, leaving those operational edges to stream documentation.
Maintenance3/5GitHub reports an unarchived repository, 36 stars, no open issues or pull requests, and a last push on October 29, 2025. npm still lists 0.1.0 as the only release. The implementation has no dependencies and little code to age, but one release provides limited evidence about compatibility fixes or how quickly the maintainer will respond when Web Streams and Node change.
Ecosystem3/5The npm downloads endpoint counted 3,706,344 installs in the latest completed week. Standard TransformStream and Node Transform interfaces let it join fetch bodies, file streams, HTTP requests, and `pipeline()` without an adapter. The package has no plugins, formatting layer, rate calculation, or policy hooks, so broader transfer tooling still requires code around the counter or a different module.

Use it if

  • You already have a Web Streams pipeline and need the exact number of bytes that crossed one stage.
  • A Node file, HTTP body, or archive pipeline needs passive byte accounting without changing its chunks.
  • You want the same small package for Web TransformStream code and Node Transform code through separate entry points.
  • A UTF-8 string or ArrayBuffer view needs an exact byte count without starting a stream.
Skip it if

Setup reality

We installed byte-counter 0.1.0 in a fresh Node 22 Bookworm sandbox. npm finished in 0.5 seconds, and the result was one package using 1 MB on disk. The package itself was 36 KB unpacked, declared no direct or peer dependencies, and produced no npm audit findings. It includes TypeScript declarations, uses ESM with an exports map, and both require() and ESM import worked in our checks.

There are no credentials or config files. Pick the entry point by stream API: byte-counter creates a Web TransformStream, while byte-counter/node creates a Node Transform. The Node engine floor is 20. Passing the Web version to stream.pipeline() or calling .pipeThrough() on the Node version gives you the wrong interface even though both classes perform the same count-and-forward job.

The count begins at 0 and changes as chunks pass through. Wait for pipeTo() or pipeline() to finish before treating it as the final total. The library does not compare against Content-Length, emit progress events, calculate speed, or reject a threshold. With fetch, Content-Length may describe encoded transfer bytes while the response body exposes decoded data, so the two numbers are not always meant to match.

Our browser build succeeded at 0.5 KB minified and 0.3 KB gzipped. That makes the default Web Streams entry cheap to ship, but browser support still depends on TransformStream. A JavaScript number holds the total, so this is ordinary transfer accounting rather than bigint metering beyond the safe-integer range.

Patterns

Count UTF-8 bytes in a string measure-utf8-text

import {byteLength} from 'byte-counter';

console.log(byteLength('Hello 👋'));
// 10

`byteLength()` measures UTF-8 bytes. JavaScript string length and visible character count answer different questions.

Count a typed array measure-binary-view

import {byteLength} from 'byte-counter';

const payload = new Uint8Array([0, 127, 128, 255]);
console.log(byteLength(payload));
// 4

The helper also accepts ArrayBuffer, SharedArrayBuffer, Buffer, DataView, and other ArrayBuffer views.

Meter a fetch response count-fetch-response

import ByteCounterStream from 'byte-counter';

const response = await fetch(url);
if (!response.ok || !response.body) throw new Error(`HTTP ${response.status}`);

const counter = new ByteCounterStream();
await response.body.pipeThrough(counter).pipeTo(destination);
console.log(counter.count);

Read the final value after `pipeTo()` resolves. A response body can be null, so check it before starting the chain.

Check a declared response size compare-content-length

const expected = Number(response.headers.get('content-length'));
const counter = new ByteCounterStream();
await response.body.pipeThrough(counter).pipeTo(destination);

if (Number.isFinite(expected) && expected !== counter.count) {
  console.warn({expected, received: counter.count});
}

A compressed HTTP response can declare encoded bytes while fetch yields decoded bytes. Treat a mismatch as something to investigate, not automatic proof of truncation.

Write directly through a Web counter write-web-stream

const counter = new ByteCounterStream();
const drained = counter.readable.pipeTo(new WritableStream({write() {}}));
const writer = counter.writable.getWriter();

await writer.write(new TextEncoder().encode('alpha'));
await writer.write(new TextEncoder().encode('beta'));
await writer.close();
await drained;
console.log(counter.count);

Keep the readable side draining. Writes can wait on backpressure when nothing consumes the output.

Count a Node file copy copy-node-file

import fs from 'node:fs';
import {pipeline} from 'node:stream/promises';
import ByteCounterStream from 'byte-counter/node';

const counter = new ByteCounterStream();
await pipeline(
  fs.createReadStream('source.bin'),
  counter,
  fs.createWriteStream('copy.bin'),
);
console.log(counter.count);

The `/node` subpath supplies the Transform accepted by `pipeline()`. The default export uses Web Streams.

Count a Node readable without saving it discard-node-output

import {Writable} from 'node:stream';
import {pipeline} from 'node:stream/promises';
import ByteCounterStream from 'byte-counter/node';

const counter = new ByteCounterStream();
const sink = new Writable({write(_chunk, _encoding, done) { done(); }});
await pipeline(source, counter, sink);
console.log(counter.count);

A Transform needs a consumer. `pipeline()` also carries source and sink errors back to the caller.

Meter an outgoing request body count-http-upload

const counter = new ByteCounterStream();
await pipeline(
  fs.createReadStream('archive.tar'),
  counter,
  request,
);
console.log(`body bytes: ${counter.count}`);

This total covers body chunks sent into the request stream. It excludes HTTP headers and transport framing.

Sample a running Node count sample-progress

const counter = new ByteCounterStream();
const timer = setInterval(() => console.log(counter.count), 1000);

try {
  await pipeline(source, counter, destination);
} finally {
  clearInterval(timer);
}

Version 0.1.0 emits no progress callback. Sampling supplies a byte total, while rate and ETA calculations remain application code.

Fail after a byte ceiling enforce-size-limit

import {Transform} from 'node:stream';

const limit = new Transform({
  transform(chunk, _encoding, done) {
    if (counter.count > 10 * 1024 * 1024) return done(new Error('Body too large'));
    done(null, chunk);
  },
});
await pipeline(source, counter, limit, destination);

The counter never aborts by itself. Put a rejecting stage after it so that stage sees the updated total for the current chunk.

Create one counter per transfer separate-transfer-counts

async function copyAndCount(source, destination) {
  const counter = new ByteCounterStream();
  await pipeline(source, counter, destination);
  return counter.count;
}

There is no reset method, and a closed stream is not reusable. A new instance keeps totals independent.

Load the package from CommonJS require-package

const ByteCounterStream = require('byte-counter');

const counter = new ByteCounterStream();

`require()` worked in our Node 22 package check even though the package declares `type: module`. Test this path on the exact older Node release you support.

Alternatives

PackageRegistryPick it when
progress-streamnpmChoose it for Node streams that need percentage, speed, runtime, and ETA events.
stream-meternpmChoose it when a Node stream must fail after a configured byte limit.
byte-lengthnpmChoose it when you only count a string or Buffer and have no stream pipeline.
pretty-bytesnpmChoose it to format a known byte value for people rather than measure streamed chunks.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.