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

strop

v0.1.3

Published

A modern TypeScript stream operations library

Readme

Strop

A modern, type-safe TypeScript stream library inspired by Highland.js, featuring lazy evaluation, error handling via Result types, and powerful stream composition.

Features

  • Type-safe: Full TypeScript support with strict typing
  • Result-based error handling: No exceptions, explicit error handling with Result types
  • Lazy evaluation: Streams only compute values when consumed
  • Composable: Rich set of operators for transforming and combining streams
  • Memory efficient: Handles large datasets without loading everything into memory
  • Promise & async/await ready: Works seamlessly with modern async patterns
  • Zero dependencies: Lightweight and self-contained

Installation

npm install strop
# or
yarn add strop
# or
pnpm add strop

Quick Start

import { Stream } from 'strop';

// Create a stream from an array
const numbers = Stream.fromArray([1, 2, 3, 4, 5]);

// Transform and consume
const result = await numbers
  .map(x => x * 2)
  .filter(x => x > 5)
  .toArray();

if (result.ok) {
  console.log(result.value); // [6, 8, 10]
}

Core Concepts

Streams

Streams are lazy, composable sequences of values that can be transformed and consumed. They support:

  • Transformation: map, filter, flatMap, scan
  • Selection: take, drop, where, compact
  • Grouping: batch values into groups, group by property or function
  • Rate Limiting: throttle to control flow rate
  • Combination: concat, merge, flatten
  • Consumption: toArray, toPromise, each, reduce

Result Types

Instead of throwing exceptions, all stream operations return Result<T, E> types:

type Result<T, E> =
  | { ok: true; value: T }
  | { ok: false; error: E };

This makes error handling explicit and type-safe.

Examples

Map and Filter

import { Stream } from 'strop';

const result = await Stream.fromArray([1, 2, 3, 4, 5])
  .map(x => x * 2)
  .filter(x => x > 5)
  .toArray();

// { ok: true, value: [6, 8, 10] }

Error Handling

import { Stream } from 'strop';

const result = await Stream.fromArray([1, 2, 3])
  .map(x => {
    if (x === 2) throw new Error('Invalid value');
    return x * 2;
  })
  .errors((error, push) => {
    console.error('Caught error:', error);
    push({ type: 'value', value: 0 }); // Recover with default
  })
  .toArray();

// { ok: true, value: [2, 0, 6] }

Async Operations

import { Stream } from 'strop';

const fetchUsers = async (id: number) => {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
};

await Stream.fromArray([1, 2, 3])
  .flatMap(id => Stream.fromPromise(fetchUsers(id)))
  .each(user => console.log(user));

Batching

import { Stream } from 'strop';

const result = await Stream.fromArray([1, 2, 3, 4, 5, 6, 7])
  .batch(3)
  .toArray();

// { ok: true, value: [[1, 2, 3], [4, 5, 6], [7]] }

Grouping

import { Stream } from 'strop';

// Group by property
const data = [
  { type: 'fruit', name: 'apple' },
  { type: 'veggie', name: 'carrot' },
  { type: 'fruit', name: 'banana' }
];

const result = await Stream.fromArray(data).group('type').toArray();
// { ok: true, value: [{
//   fruit: [{ type: 'fruit', name: 'apple' }, { type: 'fruit', name: 'banana' }],
//   veggie: [{ type: 'veggie', name: 'carrot' }]
// }]}

// Group by function
const numbers = [1, 2, 3, 4, 5, 6];
const grouped = await Stream.fromArray(numbers)
  .group(n => n % 2 === 0 ? 'even' : 'odd')
  .toArray();
// { ok: true, value: [{ odd: [1, 3, 5], even: [2, 4, 6] }]}

Pipeline Composition

import { Stream, pipeline } from 'strop';

const transform = pipeline<number, number>(
  s => s.map(x => x * 2),
  s => s.filter(x => x > 5),
  s => s.take(3)
);

const result = await transform(Stream.fromArray([1, 2, 3, 4, 5])).toArray();
// { ok: true, value: [6, 8, 10] }

Rate Limiting

import { Stream } from 'strop';

// Allow max 2 values per 100ms window
const throttled = Stream.fromArray([1, 2, 3, 4, 5])
  .throttle(2, 100);

// First 2 values pass immediately, rest are delayed
// Values are not dropped - backpressure builds up
const result = await throttled.toArray();
// { ok: true, value: [1, 2, 3, 4, 5] }
// Takes ~200ms to complete as values 3-5 are delayed

Node.js Callback Wrapping

import { wrapCallback } from 'strop';
import fs from 'fs';

const readFile = wrapCallback(fs.readFile);
const content = await readFile('package.json', 'utf8').toPromise();

if (content.ok) {
  console.log(content.value);
}

Documentation

API Overview

Static Constructors

  • Stream.fromArray(array) - Create stream from array
  • Stream.fromPromise(promise) - Create stream from promise
  • Stream.fromAsyncIterable(iterable) - Create stream from async iterable
  • Stream.fromGenerator(generator) - Create stream from generator function
  • Stream.fromNodeStream(stream) - Create stream from Node.js readable stream
  • Stream.of(value) - Create stream with single value
  • Stream.empty() - Create empty stream
  • Stream.fromError(error) - Create stream that emits an error

Transformations

  • .map(fn) - Transform each value
  • .filter(fn) - Keep values matching predicate
  • .flatMap(fn) - Map and flatten nested streams
  • .take(n) - Take first n values
  • .drop(n) - Skip first n values
  • .batch(n) - Group values into batches
  • .scan(initial, fn) - Accumulate with intermediate values
  • .pluck(key) - Extract property from objects
  • .where(props) - Filter by property values
  • .compact() - Remove falsy values
  • .group(keyOrFn) - Group values by property or function
  • .throttle(maxValues, timeWindowMs) - Limit rate of values

Combination

  • .concat(other) - Append another stream
  • .flatten() - Flatten nested streams
  • .merge() - Merge multiple streams
  • .series() - Process streams sequentially
  • .parallel(n) - Process streams with concurrency limit

Consumption

  • .toArray() - Collect all values into array
  • .toPromise() - Get single value as promise
  • .each(fn) - Iterate over each value
  • .reduce(initial, fn) - Reduce to single value

Error Handling

  • .errors(handler) - Handle and recover from errors

Utilities

  • .through(transform) - Pipe through transform function

Development

# Install dependencies
yarn install

# Run tests
yarn test

# Build
yarn build

# Type check
yarn typecheck

License

MIT

Contributing

Contributions are welcome! Please read our contributing guidelines and submit PRs.