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

@rodbe/fn-utils

v1.13.0

Published

RBX npm Library

Readme

@rodbe/fn-utils

A collection of TypeScript utility functions for functional programming, async handling, array/object manipulation, and HTTP fetching.

Installation

npm install @rodbe/fn-utils
# or
pnpm add @rodbe/fn-utils

API Reference


Array

purge

Removes all falsy values (null, undefined, NaN, '') from an array.

import { purge } from '@rodbe/fn-utils';

purge([1, null, 'hello', undefined, '', NaN, 2]);
// → [1, 'hello', 2]

purge([null, undefined]);
// → []

unique

Returns a new array with duplicate values removed.

import { unique } from '@rodbe/fn-utils';

unique([1, 2, 2, 3, 1]);
// → [1, 2, 3]

unique(['a', 'b', 'a', 'c']);
// → ['a', 'b', 'c']

Async

to

Wraps a Promise into a [error, result] tuple — no more try/catch blocks. Returns [null, result] on success and [error, null] on failure.

Optionally accepts a customErrorObj to extend the error with extra properties.

import { to } from '@rodbe/fn-utils';

// Basic usage
const [err, user] = await to(fetchUser(1));
if (err) {
  console.error('Failed to fetch user:', err);
} else {
  console.log(user);
}

// With custom error properties
const [err, data] = await to(fetchData(), { context: 'dashboard', retryable: true });
if (err) {
  console.log(err.context);    // 'dashboard'
  console.log(err.retryable);  // true
}

Type:

type ToAwaited<Res, Err = Error> = [Err, null] | [null, Res];

Functional Programming

pipe

Composes functions left-to-right. The output of each function is passed as input to the next.

import { pipe } from '@rodbe/fn-utils';

const add1 = (x: number) => x + 1;
const double = (x: number) => x * 2;
const toString = (x: number) => `Value: ${x}`;

const transform = pipe(add1, double, toString);
transform(3);
// → 'Value: 8'  (3+1=4, 4*2=8, 'Value: 8')

compose

Composes functions right-to-left. The output of each function is passed as input to the previous.

import { compose } from '@rodbe/fn-utils';

const add1 = (x: number) => x + 1;
const double = (x: number) => x * 2;
const toString = (x: number) => `Value: ${x}`;

const transform = compose(toString, double, add1);
transform(3);
// → 'Value: 8'  (add1 → double → toString)

Object

getProp

Curried accessor for deeply nested object properties using dot notation.

import { getProp } from '@rodbe/fn-utils';

const user = { profile: { name: 'Alice', address: { city: 'NYC' } } };

getProp('profile.name')(user);
// → 'Alice'

getProp<string>('profile.address.city')(user);
// → 'NYC'

// Works great as a mapper
const users = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 },
];
users.map(getProp('name'));
// → ['Alice', 'Bob']

fuzzySearch

Filters an array of objects by matching a search string against a given key (supports dot notation). Each word in searchText is matched independently (AND logic).

import { fuzzySearch } from '@rodbe/fn-utils';

const users = [
  { name: 'Alice Smith', role: 'admin' },
  { name: 'Bob Johnson', role: 'user' },
  { name: 'Alice Brown', role: 'user' },
];

fuzzySearch({ items: users, key: 'name', searchText: 'alice' });
// → [{ name: 'Alice Smith', ... }, { name: 'Alice Brown', ... }]

// Multi-word: all words must match
fuzzySearch({ items: users, key: 'name', searchText: 'alice smith' });
// → [{ name: 'Alice Smith', ... }]

// Nested key via dot notation
const products = [{ meta: { title: 'Laptop Pro' } }, { meta: { title: 'Mouse' } }];
fuzzySearch({ items: products, key: 'meta.title', searchText: 'laptop' });
// → [{ meta: { title: 'Laptop Pro' } }]

Predicates

hasValue

Returns true if the value is not null, undefined, NaN, or ''.

import { hasValue } from '@rodbe/fn-utils';

hasValue('hello');    // → true
hasValue(0);          // → true
hasValue(false);      // → true

hasValue(null);       // → false
hasValue(undefined);  // → false
hasValue(NaN);        // → false
hasValue('');         // → false

isObject

Returns true if the value is a plain object {}.

import { isObject } from '@rodbe/fn-utils';

isObject({ a: 1 });     // → true
isObject({});           // → true

isObject([1, 2]);       // → false
isObject(null);         // → false
isObject('string');     // → false
isObject(new Date());   // → false

isEmptyObj

Returns true if the value is not a plain object or if it is an object with no own keys.

import { isEmptyObj } from '@rodbe/fn-utils';

isEmptyObj({});          // → true
isEmptyObj(null);        // → true
isEmptyObj([]);          // → true

isEmptyObj({ a: 1 });   // → false

Try-Catch

tryCatch

Wraps a synchronous function in a [error, result] tuple — the sync equivalent of to.

import { tryCatch } from '@rodbe/fn-utils';

const [err, result] = tryCatch(() => JSON.parse('{"ok":true}'));
if (err) {
  console.error(err);
} else {
  console.log(result); // → { ok: true }
}

// Catches thrown errors
const [parseErr] = tryCatch(() => JSON.parse('invalid json'));
console.log(parseErr instanceof Error); // → true

Fetcher

fetcher

A thin fetch wrapper that returns a [error, data] tuple instead of throwing. HTTP errors (non-2xx) are returned as FetchErr, network errors as Error.

Accepts all standard RequestInit options plus:

  • responseToJson?: boolean — when true, automatically parses the response body as JSON and returns it as Res.
  • cbOnError?: (err: Response) => void — callback invoked on non-2xx responses before returning the error tuple.
import { fetcher } from '@rodbe/fn-utils';

interface User {
  id: number;
  name: string;
}

// Basic usage — returns the raw Response
const [err, response] = await fetcher('https://api.example.com/users/1', {
  method: 'GET',
  headers: { Authorization: 'Bearer token' },
});

if (err) {
  console.log(err.status)
  return;
}

const user = await response.json() as User;

// With responseToJson — returns the parsed body typed as User
const [err, user] = await fetcher<User>('https://api.example.com/users/1', {
  method: 'GET',
  responseToJson: true,
});

if (err) {
  // HTTP error
  console.log(err.status);     // e.g. 404
  console.log(err.statusText); // e.g. 'Not Found'
} else {
  console.log(user.name); // user is typed as User
}

// With cbOnError — side-effect on HTTP errors (e.g. logging, toast)
const [err, user] = await fetcher<User>('https://api.example.com/users/1', {
  responseToJson: true,
  cbOnError: (res) => toast.error(`Request failed: ${res.status}`),
});

Types:

interface FetchErr {
  status: number;
  statusText: string;
}

retryFetchBuilder

Factory that builds a fetch function with automatic retry logic. Retries on configurable HTTP status codes with a delay between attempts.

Default config: 3 retries, 1500ms delay, retries on 429, 503, 504.

import { retryFetchBuilder } from '@rodbe/fn-utils';

// Using defaults (3 retries, 1500ms delay, statuses 429/503/504)
const fetchWithRetry = retryFetchBuilder();

const [err, data] = await fetchWithRetry<{ items: string[] }>(
  'https://api.example.com/items',
  { method: 'GET' }
);

// Custom config
const aggressiveRetry = retryFetchBuilder({
  retries: 5,
  retryDelay: 500,
  statusToRetry: [429, 500, 502, 503, 504],
});

const [err2, data2] = await aggressiveRetry<{ items: string[] }>(
  'https://api.example.com/items',
  { method: 'GET' }
);

Types:

interface FetcherConfig {
  retries: number;
  retryDelay: number;
  statusToRetry: Array<number>;
}

License

MIT