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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@pivanov/utils

v0.0.3

Published

A collection of personal utilities to live a happier life

Readme

@pivanov/utils

Features

  • 🔒 Type-Safe - Full TypeScript support with strict type checking and excellent type inference
  • 🎯 Tree-Shakeable - Import only what you need for minimal bundle size
  • Performance Focused - Optimized implementations with no external dependencies
  • 🧪 Well Tested - Comprehensive test coverage for reliability
  • 📦 Modular - Organized into focused modules for easy navigation
  • 📝 Well Documented - Detailed JSDoc comments and examples

Installation

pnpm add @pivanov/utils
# or
npm install @pivanov/utils
# or
yarn add @pivanov/utils

Quick Start

import { camelCase } from '@pivanov/utils/string';
import { pick } from '@pivanov/utils/object';
import { isString } from '@pivanov/utils/assertion';

camelCase('foo-bar'); // 'fooBar'
pick({ name: 'John', age: 30 }, ['name']); // { name: 'John' }
isString('hello'); // true

API Reference

Type Guards & Assertions

Runtime type checking with TypeScript type narrowing.

import {
  isString,
  isNumber,
  isBoolean,
  isObject,
  isFunction,
  isNull,
  isUndefined,
} from '@pivanov/utils/assertion';

// Type guards automatically narrow TypeScript types
function processValue(value: unknown) {
  if (isString(value)) {
    return value.toUpperCase(); // TypeScript knows this is a string
  }
  if (isNumber(value)) {
    return value.toFixed(2); // TypeScript knows this is a number
  }
}

// Examples
isString('hello'); // true
isNumber(42); // true
isBoolean(true); // true
isObject({}); // true (plain objects only, not arrays)
isFunction(() => {}); // true
isNull(null); // true
isUndefined(undefined); // true

Object Utilities

Immutable object manipulation with full type safety.

import { pick, omit, merge, deepMerge } from '@pivanov/utils/object';

// Pick specific properties
const user = { name: 'John', age: 30, email: '[email protected]' };
pick(user, ['name', 'email']);
// { name: 'John', email: '[email protected]' }

// Omit specific properties
omit(user, ['email']);
// { name: 'John', age: 30 }

// Shallow merge
merge({ a: 1, b: 2 }, { b: 3, c: 4 });
// { a: 1, b: 3, c: 4 }

// Deep merge with nested structures
deepMerge(
  { user: { name: 'John', settings: { theme: 'dark' } } },
  { user: { settings: { fontSize: 14 } } }
);
// { user: { name: 'John', settings: { theme: 'dark', fontSize: 14 } } }

String Utilities

String transformation utilities with TypeScript template literal types support.

import {
  camelCase,
  pascalCase,
  kebabCase,
  slugify,
  capitalize,
  uncapitalize,
  capitalizeFirstLetter,
} from '@pivanov/utils/string';

// Case transformations
camelCase('foo-bar'); // 'fooBar'
camelCase('FOO_BAR'); // 'fooBar'

pascalCase('foo-bar'); // 'FooBar'
pascalCase('foo_bar_baz'); // 'FooBarBaz'

kebabCase('fooBar'); // 'foo-bar'
kebabCase('XMLHttpRequest'); // 'xml-http-request'

slugify('Hello World!'); // 'hello-world'
slugify('Über Café'); // 'uber-cafe'

// Capitalization with TypeScript support
capitalize('hello'); // 'Hello' (type: Capitalize<'hello'>)
uncapitalize('Hello'); // 'hello' (type: Uncapitalize<'Hello'>)
capitalizeFirstLetter('hello world'); // 'Hello world'

When to use each:

  • camelCase: JavaScript/TypeScript variables and properties
  • pascalCase: Class names, React components, TypeScript types
  • kebabCase: CSS classes, HTML attributes, file names
  • slugify: URL slugs (more aggressive than kebabCase)

Promise Utilities

Simple async utilities for better promise handling.

import { sleep } from '@pivanov/utils/promise';

async function example() {
  console.log('Start');
  await sleep(1000); // Wait 1 second
  console.log('Done');
}

Deep Clone & Equality

High-performance deep cloning and comparison with circular reference handling.

import { deepClone, isEqual } from '@pivanov/utils/tools';

// Deep clone complex structures
const original = {
  nested: { array: [1, 2, { value: 3 }] },
  date: new Date(),
  map: new Map([['key', 'value']]),
  set: new Set([1, 2, 3]),
  circular: {} as any,
};
original.circular = original; // Circular reference

const cloned = deepClone(original);
// Fully independent copy with circular references preserved

// Deep equality comparison
isEqual({ a: [1, 2, 3] }, { a: [1, 2, 3] }); // true
isEqual(new Date('2024-01-01'), new Date('2024-01-01')); // true
isEqual([1, 2, [3, 4]], [1, 2, [3, 4]]); // true
isEqual(new Set([1, 2]), new Set([2, 1])); // false (Sets maintain order)

Supported types:

  • Primitives (string, number, boolean, null, undefined, symbol, bigint)
  • Arrays (including sparse arrays)
  • Plain objects (with getters/setters)
  • Date, RegExp, Map, Set
  • TypedArrays, ArrayBuffer, Buffer
  • Circular references

Event Bus

Type-safe, lightweight event bus with React hooks support.

import { busDispatch, busSubscribe, useEventBus } from '@pivanov/utils/tools';

// Define your application events (optional but recommended)
type AppEvents = {
  'user-logged-in': { id: number; name: string };
  'data-updated': { timestamp: number };
  'notification': { message: string; type: 'info' | 'error' };
};

// React hook usage (auto-unsubscribes on unmount)
function UserProfile() {
  useEventBus<AppEvents>('user-logged-in', (data) => {
    console.log(`Welcome ${data.name}!`);
  });

  return <div>Profile</div>;
}

// Vanilla JavaScript usage
const unsubscribe = busSubscribe<AppEvents>('data-updated', (data) => {
  console.log('Updated at:', data.timestamp);
});

// Later: cleanup
unsubscribe();

// Dispatch events anywhere in your app
busDispatch<AppEvents>('user-logged-in', { id: 1, name: 'John' });
busDispatch<AppEvents>('notification', {
  message: 'Settings saved',
  type: 'info',
});

Features:

  • Fully type-safe with TypeScript
  • Works across React and vanilla JavaScript
  • Automatic cleanup with React hook
  • Uses hashed topic names to avoid collisions
  • Zero dependencies

Browser Cache API

Type-safe wrapper around the browser Cache API with expiration support.

import {
  storageSetItem,
  storageGetItem,
  storageRemoveItem,
  storageExists,
  storageClear,
  storageClearByPrefixOrSuffix,
  storageGetAllKeys,
  storageCalculateSize,
} from '@pivanov/utils/tools';

const CACHE_NAME = 'my-app-cache';

// Store data
await storageSetItem(CACHE_NAME, 'user-data', {
  id: 1,
  name: 'John',
  bigNumber: BigInt(9007199254740991), // BigInt support!
});

// Retrieve data
const userData = await storageGetItem<{ id: number; name: string }>(
  CACHE_NAME,
  'user-data'
);

// Check existence
const exists = await storageExists(CACHE_NAME, 'user-data');

// Remove specific item
await storageRemoveItem(CACHE_NAME, 'user-data');

// Get all keys
const keys = await storageGetAllKeys(CACHE_NAME);

// Clear items by prefix
await storageClearByPrefixOrSuffix(CACHE_NAME, 'temp-', true);

// Clear items by suffix
await storageClearByPrefixOrSuffix(CACHE_NAME, '-cache', false);

// Calculate cache size (in bytes)
const totalSize = await storageCalculateSize(CACHE_NAME);
const itemSize = await storageCalculateSize(CACHE_NAME, 'user-data');

// Clear all cache
await storageClear(CACHE_NAME);

Features:

  • Automatic JSON serialization/deserialization
  • BigInt support (automatically converted to strings)
  • Type-safe with generics
  • Works with absolute URLs as keys
  • Size calculation utilities

DOM Utilities

Browser-safe DOM manipulation helpers.

import {
  isBrowser,
  checkVisibility,
  setStyleProperties,
  calculateRenderedTextWidth,
} from '@pivanov/utils/tools';

// Check if running in browser (SSR-safe)
if (isBrowser()) {
  // Browser-only code
  window.addEventListener('scroll', handleScroll);
}

// Check element visibility in viewport
const element = document.querySelector('.my-element') as HTMLElement;
if (checkVisibility(element)) {
  element.classList.add('visible');
}

// Set CSS custom properties
setStyleProperties(element, {
  '--primary-color': '#3b82f6',
  '--spacing': '1rem',
  '--border-radius': '8px',
});

// Calculate text width for dynamic layouts
const width = calculateRenderedTextWidth('Hello World', 16);
const widthUppercase = calculateRenderedTextWidth('Hello World', 16, true);
const widthCustomFont = calculateRenderedTextWidth(
  'Hello World',
  16,
  false,
  'Arial'
);

Tree Shaking

Import only what you need to minimize bundle size:

// ✅ Good: Import specific utilities
import { camelCase } from '@pivanov/utils/string';
import { deepClone } from '@pivanov/utils/tools';

// ❌ Avoid: Importing everything
import * as utils from '@pivanov/utils';

TypeScript Support

All utilities provide excellent type inference:

import { pick } from '@pivanov/utils/object';
import { capitalize } from '@pivanov/utils/string';

// TypeScript infers exact types
const user = { name: 'John', age: 30, email: '[email protected]' } as const;
const picked = pick(user, ['name', 'email']);
// Type: { name: "John"; email: "[email protected]" }

const str = 'hello' as const;
const capitalized = capitalize(str);
// Type: "Hello"

Module Overview

@pivanov/utils
├── /assertion    - Type guards (isString, isNumber, etc.)
├── /object       - Object utilities (pick, omit, merge, deepMerge)
├── /promise      - Async utilities (sleep)
├── /string       - String utilities (camelCase, kebabCase, etc.)
└── /tools        - Various tools
    ├── deepClone
    ├── isEqual
    ├── DOM utilities (isBrowser, checkVisibility, etc.)
    ├── eventBus (busDispatch, busSubscribe, useEventBus)
    └── Cache API (storageSetItem, storageGetItem, etc.)

Browser Compatibility

  • Modern browsers with ES2015+ support
  • Cache API requires browser support (Chrome 40+, Firefox 41+, Safari 11.1+)
  • SSR-safe with browser environment detection

License

MIT © Pavel Ivanov