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

@vielzeug/toolkit

v1.1.3

Published

<div align="center"> <img src="../../docs/public/logo-utils.svg" alt="Toolkit Logo" width="120" />

Readme

@vielzeug/toolkit

npm version npm downloads License: MIT TypeScript Bundle Size

Features

  • 🎯 119 Type-Safe Utilities - Covering arrays, objects, strings, async operations, and more
  • 📦 Tree-Shakeable - Import only what you need, minimize bundle size
  • 🔒 Zero Dependencies - No supply chain risks, no version conflicts
  • 💪 Full TypeScript Support - Complete type inference and safety
  • Async-First - Built-in support for promises and async operations
  • 🧪 Battle-Tested - >95% test coverage, production-ready
  • 🌐 Isomorphic - Works in both browser and Node.js environments

Installation

::: code-group

pnpm add @vielzeug/toolkit
npm install @vielzeug/toolkit
yarn add @vielzeug/toolkit

:::

Quick Start

import { chunk, map, retry, pool } from '@vielzeug/toolkit';

// Array operations
const batches = chunk([1, 2, 3, 4, 5], 2);
// [[1, 2], [3, 4], [5]]

// Async map with automatic Promise handling
const users = await map([1, 2, 3], async (id) => fetchUser(id));

// Retry with exponential backoff
const data = await retry(() => fetch('/api/data').then((r) => r.json()), { times: 3, delay: 1000, backoff: 2 });

// Rate limiting with promise pool
const apiPool = pool(5); // Max 5 concurrent requests
const results = await Promise.all(urls.map((url) => apiPool(() => fetch(url))));

Categories

📊 Array (25 utilities)

Transform, filter, group, and manipulate arrays with full type safety.

import { group, uniq, flatten, sort } from '@vielzeug/toolkit';

// Group by property
const grouped = group(users, (user) => user.role);

// Remove duplicates
const unique = uniq([1, 2, 2, 3, 3, 3]);

// Flatten nested arrays
const flat = flatten([
  [1, 2],
  [3, [4, 5]],
]);

// Sort with custom comparator
const sorted = sort(items, (a, b) => a.price - b.price);

Available utilities: aggregate, alternate, arrange, chunk, compact, contains, every, filter, find, findIndex, findLast, flatten, group, list, map, pick, reduce, remoteList, search, select, shift, some, sort, substitute, uniq


⚡ Async (11 utilities)

Promise utilities, concurrency control, retries, and async patterns.

import { parallel, queue, waitFor, race, defer } from '@vielzeug/toolkit';

// Process with controlled concurrency
await parallel(3, urls, async (url) => fetch(url));

// Task queue with monitoring
const taskQueue = queue({ concurrency: 5 });
taskQueue.add(() => processTask());
await taskQueue.onIdle();

// Wait for condition
await waitFor(() => document.querySelector('#app') !== null);

// Race with minimum delay (better UX)
const data = await race(fetchData(), 500);

// Externally-controlled promise
const deferred = defer<string>();
setTimeout(() => deferred.resolve('Done!'), 1000);

Available utilities: attempt, defer, delay, parallel, pool, predict, queue, race, retry, sleep, waitFor


📅 Date (3 utilities)

Date manipulation and time calculations.

import { interval, timeDiff, expires } from '@vielzeug/toolkit';

// Calculate time intervals
const days = interval(new Date('2024-01-01'), new Date('2024-12-31'), 'days');

// Time difference
const diff = timeDiff(date1, date2);

// Check expiration
if (expires(expiryDate)) {
  // Handle expired
}

Available utilities: expires, interval, timeDiff


⚙️ Function (14 utilities)

Function composition, memoization, and execution control.

import { debounce, throttle, memo, pipe, curry } from '@vielzeug/toolkit';

// Debounce user input
const search = debounce((query) => fetchResults(query), 300);

// Throttle scroll events
const onScroll = throttle(() => updateUI(), 100);

// Memoize expensive calculations
const fibonacci = memo((n) => (n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)));

// Function composition
const transform = pipe(
  (x) => x * 2,
  (x) => x + 1,
  (x) => x.toString(),
);

// Currying
const add = curry((a, b, c) => a + b + c);
const add5 = add(5);

Available utilities: assert, assertParams, compare, compareBy, compose, curry, debounce, fp, memo, once, pipe, proxy, prune, throttle, worker


🔢 Math (17 utilities)

Mathematical operations, statistics, and calculations.

import { average, median, clamp, range, distribute } from '@vielzeug/toolkit';

// Calculate average
const avg = average([1, 2, 3, 4, 5]); // 3

// Find median
const med = median([1, 2, 3, 4, 5]); // 3

// Clamp value to range
const clamped = clamp(150, 0, 100); // 100

// Generate range
const numbers = range(1, 10); // [1, 2, 3, ..., 10]

// Distribute amount
const shares = distribute(100, 3); // [33.33, 33.33, 33.34]

Available utilities: abs, add, allocate, average, boil, clamp, distribute, divide, max, median, min, multiply, range, rate, round, subtract, sum


💰 Money (3 utilities)

Currency formatting and exchange calculations.

import { currency, exchange } from '@vielzeug/toolkit';

// Format currency
const formatted = currency(1234.56, 'USD'); // "$1,234.56"

// Currency exchange
const converted = exchange(100, 'USD', 'EUR', 0.85); // 85

Available utilities: currency, exchange, types


📦 Object (10 utilities)

Deep merging, cloning, diffing, and object manipulation.

import { merge, clone, diff, path, seek } from '@vielzeug/toolkit';

// Deep merge
const merged = merge(obj1, obj2);

// Deep clone
const copy = clone(original);

// Diff objects
const changes = diff(oldObj, newObj);

// Get nested value
const value = path(obj, 'user.address.city');

// Search object
const results = seek(data, (val) => val > 100);

Available utilities: cache, clone, diff, entries, keys, merge, parseJSON, path, seek, values


🎲 Random (4 utilities)

Random values, shuffling, and UUID generation.

import { random, shuffle, draw, uuid } from '@vielzeug/toolkit';

// Random number
const num = random(1, 100);

// Shuffle array
const shuffled = shuffle([1, 2, 3, 4, 5]);

// Draw random items
const winners = draw(participants, 3);

// Generate UUID
const id = uuid(); // "550e8400-e29b-41d4-a716-446655440000"

Available utilities: draw, random, shuffle, uuid


📝 String (6 utilities)

String formatting, case conversion, and similarity.

import { camelCase, kebabCase, pascalCase, snakeCase, truncate, similarity } from '@vielzeug/toolkit';

// Case conversions
camelCase('hello world'); // "helloWorld"
kebabCase('hello world'); // "hello-world"
pascalCase('hello world'); // "HelloWorld"
snakeCase('hello world'); // "hello_world"

// Truncate text
truncate('Long text here', 10); // "Long text..."

// String similarity
similarity('hello', 'hallo'); // 0.8

Available utilities: camelCase, kebabCase, pascalCase, similarity, snakeCase, truncate


✅ Typed (27 utilities)

Type guards, type checking, and validation.

import { isString, isArray, isPromise, isEmpty, isEqual } from '@vielzeug/toolkit';

// Type guards with narrowing
if (isString(value)) {
  // TypeScript knows value is string
  console.log(value.toUpperCase());
}

// Check arrays
if (isArray(data)) {
  data.forEach((item) => console.log(item));
}

// Promise detection
if (isPromise(result)) {
  await result;
}

// Empty check
if (isEmpty(obj)) {
  // Handle empty
}

// Deep equality
if (isEqual(obj1, obj2)) {
  // Objects are equal
}

Available utilities: ge, gt, is, isArray, isBoolean, isDate, isDefined, isEmpty, isEqual, isEven, isFunction, isNegative, isNil, isNumber, isObject, isOdd, isPositive, isPrimitive, isPromise, isRegex, isString, isWithin, isZero, le, lt, typeOf

Real-World Examples

API Rate Limiting with Retry

import { pool, retry, predict } from '@vielzeug/toolkit';

// Create rate-limited pool
const apiPool = pool(10); // Max 10 concurrent requests

async function fetchWithRetry(url: string) {
  return apiPool(() =>
    retry(
      () =>
        predict(
          async (signal) => {
            const response = await fetch(url, { signal });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            return response.json();
          },
          { timeout: 5000 },
        ),
      { times: 3, delay: 1000, backoff: 2 },
    ),
  );
}

// Process many URLs with rate limiting and retry
const results = await Promise.all(urls.map((url) => fetchWithRetry(url)));

Batch Processing with Progress

import { chunk, parallel, sleep } from '@vielzeug/toolkit';

async function processBatch(items: any[], batchSize = 10) {
  const batches = chunk(items, batchSize);
  const results = [];

  for (let i = 0; i < batches.length; i++) {
    console.log(`Processing batch ${i + 1}/${batches.length}`);

    const batchResults = await parallel(3, batches[i], async (item) => {
      return await processItem(item);
    });

    results.push(...batchResults);

    // Delay between batches
    if (i < batches.length - 1) {
      await sleep(1000);
    }
  }

  return results;
}

Form Validation Pipeline

import { pipe, curry, isEmpty, isString } from '@vielzeug/toolkit';

const required = (value: any) => {
  if (isEmpty(value)) throw new Error('Required field');
  return value;
};

const minLength = curry((min: number, value: string) => {
  if (!isString(value) || value.length < min) {
    throw new Error(`Minimum ${min} characters`);
  }
  return value;
});

const email = (value: string) => {
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
    throw new Error('Invalid email');
  }
  return value;
};

// Create validation pipeline
const validateEmail = pipe(required, minLength(5), email);

try {
  const validEmail = validateEmail(userInput);
} catch (error) {
  console.error(error.message);
}

Performance & Bundle Size

Tree-Shaking

Toolkit is designed for optimal tree-shaking. Import only what you use:

// ✅ Good - Only includes chunk function (~0.5KB gzipped)
import { chunk } from '@vielzeug/toolkit';

// ⚠️ Avoid - Imports entire library (~35KB gzipped)
import * as toolkit from '@vielzeug/toolkit';

Bundle Size by Category

| Category | Utilities | Approx. Size (gzipped) | | -------- | --------- | ---------------------- | | Array | 25 | ~8KB | | Async | 11 | ~3KB | | Date | 3 | ~1KB | | Function | 14 | ~5KB | | Math | 17 | ~4KB | | Money | 3 | ~1KB | | Object | 10 | ~3KB | | Random | 4 | ~1KB | | String | 6 | ~2KB | | Typed | 27 | ~3KB |

Note: Individual utilities are typically 0.1-0.8 KB gzipped each.

TypeScript Support

Full TypeScript support with complete type inference:

import { map, filter, group } from '@vielzeug/toolkit';

const numbers = [1, 2, 3, 4, 5];

// Type inferred as number[]
const doubled = map(numbers, (n) => n * 2);

// Type inferred as number[]
const evens = filter(numbers, (n) => n % 2 === 0);

// Type inferred as Record<string, User[]>
const byRole = group(users, (u) => u.role);

// Async operations automatically return Promise
const results = await map(ids, async (id) => fetchUser(id));
// Type: Promise<User[]>

Comparison with Alternatives

| Feature | Toolkit | Lodash | Ramda | Native JS | | ---------------------- | ---------------- | ----------------- | ----------------- | ---------- | | TypeScript Support | ✅ First-class | ⚠️ Via @types | ⚠️ Via @types | ❌ Limited | | Tree-shakeable | ✅ By default | ⚠️ lodash-es only | ✅ Yes | N/A | | Bundle Size (min+gzip) | ~0.1-1KB/utility | ~24KB (full) | ~12KB (full) | 0KB | | Dependencies | 0 | 0 | 0 | N/A | | Async Support | ✅ Built-in | ❌ Limited | ❌ Limited | ⚠️ Manual | | Learning Curve | Low | Low | High (FP focused) | Low |

Documentation

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development

# Install dependencies
pnpm install

# Build the package
pnpm build

# Run tests
pnpm test

# Run tests in watch mode
pnpm test:watch

# Type check
pnpm typecheck

License

MIT © Helmuth Saatkamp

Related Packages

Part of the @vielzeug monorepo: