Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

199 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Common stuff πŸ”¨

codecov CodeFactor semantic-release code style: Biome

JavaScript and NodeJS are missing a lot of core functionalities. The goal of this library is to bring a variety of useful helpers on both NodeJS & Browser with strong TypeScript typing and zero dependencies.

The package is isomorphic β€” every helper runs in browsers, Node, Deno, Bun, and workers. Runtime-specific APIs (e.g. Buffer) are feature-detected with portable fallbacks. The build is ESM with "sideEffects": false, so unused exports are tree-shaken.

Missing something? Create feature request!

Read Documentation πŸ“˜

Installation

npm version npm

Install with NPM/yarn:

# NPM
npm install common-stuff
# Yarn
yarn add common-stuff

Import what you need:

import { isEqual } from "common-stuff";

if (isEqual({ a: 1 }, { a: 1 })) {
    console.log("Hello");
}

Always import only what is necessary to take full advantage of tree shaking.

Examples

Universal iterable helpers

The iterable module provides one set of helpers that work across Array, Set, Map, Record, generic Iterable, and AsyncIterable β€” preserving the input container type and switching to Promise automatically when the callback is async.

Available: map, flatMap, filter, reduce, forEach, find, some, every, size, toArray, take, drop, partition, zip.

import { map, flatMap, filter, reduce, partition, zip } from "common-stuff";

// Array β†’ Array
map([1, 2, 3], (v) => v * 2);
// [2, 4, 6]

// Set β†’ Set (preserves container)
filter(new Set([1, 2, 3, 4]), (v) => v % 2 === 0);
// Set { 2, 4 }

// Map β†’ Map (callback receives [k, v])
map(new Map([["a", 1]]), ([k, v]) => [k.toUpperCase(), v * 10]);
// Map { 'A' => 10 }

// Record β†’ Record (iterated as [k, v] entries)
flatMap({ a: 1, b: 2 }, ([k, v]) => (v % 2 ? [[k, v]] : []));
// { a: 1 }

// Async iterable + async mapper
async function* gen() {
    yield 1;
    yield 2;
    yield 3;
}
await reduce(gen(), (a, b) => a + b);
// 6

// Partition into matching / non-matching halves
partition([1, 2, 3, 4], (v) => v % 2 === 0);
// [[2, 4], [1, 3]]

// Zip element-wise, stopping at the shortest
zip([1, 2, 3], ["a", "b"]);
// [[1, 'a'], [2, 'b']]

Using FP patterns

import {
    pipe,
    sortBy,
    deduplicateBy,
    chunk,
    ensureArray,
    groupBy,
    reduce,
} from "common-stuff";

const result = pipe(
    [{ value: 4 }, { value: 6 }, { value: 8 }],
    (v) => sortBy(v, (o) => o.value),
    (v) => deduplicateBy(v, (o) => o.value),
    (v) => v.map((o) => ensureArray(o.value)),
    (v) => chunk(v, 2),
    (v) => groupBy(v, (o) => o.length)
);
// [ [1, [[[ 8 ]]]],[ 2, [[[ 4 ], [ 6 ]]]] ]

// Using reduce with async iterable
async function* gen() {
    yield 1;
    yield 2;
    yield 3;
}
const total = await reduce(gen(), (a, b) => a + b); // 6

With arrow functions you can easily use pipe with any function

Parsing env variables

For example we have following ENV variables:

CONFIG__PRIVATE_KEY="my key"
CONFIG__PUBLIC_KEY="my key"
CONFIG__ALLOWED_IPS='["127.0.0.1", "localhost"]'
import { convertToNested, camelCase } from "common-stuff";

const config = convertToNested(process.env, {
    separator: "__",
    transformKey: camelCase,
}).config;
// { privateKey: 'my key', publicKey: 'my key', allowedIps: ['127.0.0.1', 'localhost'] }

Using Http errors

import { HttpError, HttpStatusCodes } from "common-stuff";

app.get("/", function (req, res) {
    throw new HttpError(
        HttpStatusCodes.INTERNAL_SERVER_ERROR,
        "Some secret error message"
    );
});

// Handle unknown errors
app.use(function (err, req, res, next) {
    if (err instanceof HttpError) {
        // Log full error message
        console.error(err.message);

        // Return safe error message without private details
        return res.status(err.status).send(err.publicMessage);
    }
    next();
});

This example returns 500 error message with text Internal Server Error and logs private message to console. Check express-async-errors for Express JS async support.

Common browser helpers

import { parseCookies, generateCookie, parseQueryString } from "common-stuff";

parseCookies(document.cookie);
// {session: '26e761be168533cbf0742f8c295176c7'}

document.cookie = generateCookie("name", "John", { expires: 7 });

parseQueryString(location.search);
// { page: ['1'], limit: ['20']}

Migrating from v1 to v2

Breaking changes only:

  • ESM-only. CJS/UMD entry points removed; require("common-stuff") no longer works.
  • httpErrorHandler removed β€” inline the middleware (it was a thin instanceof HttpError wrapper).
  • HttpStatusCodes / HttpStatusReasons are const objects, not enums (required by erasableSyntaxOnly). Value reads are unchanged; the type HttpStatusCodes is gone β€” use (typeof HttpStatusCodes)[keyof typeof HttpStatusCodes] if needed.
  • Array-only flatMap removed. The universal flatMap (iterable module) requires callbacks to return an iterable and only passes (item, index).
  • parseSize returns number | undefined instead of -1.
  • merge<A, B>(target, source): A & B β€” return type is inferred. Explicit merge<MyShape>(a, b) calls need to pass both generics or cast.
  • hashCode integers changed (prefixed with typeof to avoid falsy collisions). Invalidate any persisted hashes.
  • difference / intersection / union / shuffle now correctly return T[] for mutable inputs (v1 always returned ReadonlyArray<T> due to overload order).
  • isArray narrows readonly inputs to ReadonlyArray<T> (v1 narrowed them to mutable Array<T>); runtime switched to Array.isArray (fixes cross-realm).
  • getByKey infers the return type from literal paths. Pass T explicitly for dynamic paths.

About

Collection of common helpers and utils for both JavaScript and NodeJS with TypeScript support

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages