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

@herowcode/utils

v1.7.0

Published

A lightweight collection of utility functions for everyday JavaScript/TypeScript development

Readme

@herowcode/utils

A tree-shakable TypeScript utility library for dates, strings, arrays, API calls, YouTube, and files — one install, every project.

npm TypeScript MIT License CI


📖 Context

The Problem

Every application I built required the same utility functions: format a date, debounce an event, extract a YouTube video ID, wrap an API call with error handling. The result was copy-pasted code scattered across dozens of projects — and when something needed fixing, I had to hunt down every copy.

The Goal

One library, one update, every project benefits. @herowcode/utils is built around two constraints:

  • Zero unnecessary overhead — tree-shakable, sideEffects: false, import only what you need
  • Universal — works in Node.js and browsers, with conditional exports per environment

Solo Project

Designed, built, and maintained by Judson Cairo as the shared foundation for all HerowCode projects — and open to the community.


🛠️ Stack

| Layer | Technology | |-------|------------| | Language | TypeScript 5.x | | Build | tsup — CJS + ESM + .d.ts declarations | | Testing | Vitest + jsdom | | Linting | Biome 2.x | | Package manager | pnpm | | CI/CD | GitHub Actions + npm OIDC provenance |

Why this stack?

tsup over Rollup/Webpack — Zero-config dual CJS/ESM output with automatic .d.ts generation, code splitting, and treeshaking in a single config file.

Biome over ESLint + Prettier — One tool for linting and formatting with near-instant feedback. Enforces naming conventions (I* interfaces, T* types, E* enums) across the codebase.

dayjs over date-fns — Smaller base size with a plugin system. The intl plugin enables Intl-based formatting without shipping a full locale registry.


📦 Modules

| Module | What it does | Docs | |--------|-------------|------| | /api | HTTP client with retry, auth tokens, and standardized errors | docs/api.md | | /array | shuffle, unique, markdownToText | docs/array.md | | /date | Format, relative time, timezone correction, time-spent parsing | docs/date.md | | /files | Compress images, download URLs, format bytes (browser + Node) | docs/files.md | | /function | debounce, throttle, tryCatch | docs/function.md | | /logger | Structured logger (Pino on Node, console-based on browser) | docs/logger.md | | /nextjs | OptimizedImage component | docs/nextjs.md | | /string | Case conversion, slugify, truncate, time formatting | docs/string.md | | /youtube | Extract IDs, generate URLs, video info with caching | docs/youtube.md |


🚀 Installation

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

Peer dependencies (only needed for specific modules):

# /nextjs and /youtube React hook
npm install react next

# /logger pretty output in dev (Node only — JSON in prod always works)
npm install -D pino-pretty

A Python template covering the same contract is shipped in templates/python/logger.py — copy it into your Python services. See docs/logger.md.


⚡ Quick Start

Always import from the specific module to keep your bundle small:

import { formatDate, getRelativeTime } from '@herowcode/utils/date';
import { capitalize, slugify, truncate } from '@herowcode/utils/string';
import { debounce, tryCatch } from '@herowcode/utils/function';
import { apiClient } from '@herowcode/utils/api';
import { extractYouTubeId, getYoutubeVideoInfo } from '@herowcode/utils/youtube';

Or import from the root entry (all modules bundled together):

import { formatDate, capitalize, debounce } from '@herowcode/utils';

💡 Key Challenge: Universal Exports

The hardest part of building this library was making modules like files and youtube work seamlessly in both browser and Node.js environments — without requiring consumers to configure anything.

Some functions only make sense in a browser (compressImage, downloadUrl); others only in Node.js (fileExists, fileDelete). The solution is conditional exports in package.json, resolved automatically by bundlers and the Node.js runtime:

"./files": {
  "browser": { "import": "./dist/files/index.browser.js" },
  "node":    { "import": "./dist/files/index.node.js" },
  "import":  { "default": "./dist/files/index.js" }
}

The exports field is auto-generated by scripts/sync-exports.cjs on every build — never edit it manually.

For getYoutubeVideoInfo specifically, the Node.js environment queries four sources in parallel and merges the results — each field picks the first non-empty value and thumbnails are deduped across sources:

1. InnerTube player endpoint (ANDROID → WEB client)  →  full metadata (primary)
2. Watch page HTML (ytInitialPlayerResponse)         →  full metadata
3. YouTube oEmbed API                                →  title + thumbnail
4. NoEmbed public API                                →  title + description + upload date

The InnerTube endpoint is used because it works reliably from datacenter/containerized environments where YouTube serves a consent interstitial instead of the normal watch page. Sources complement each other: if InnerTube returns metadata but oEmbed contributes an extra thumbnail size, the merged result has both.

Results are cached by video ID as a Promise — concurrent calls for the same video hit the network only once, and failed requests evict themselves from the cache automatically.


📋 Development

pnpm install          # Install dependencies
pnpm test             # Run tests in watch mode
pnpm test:run         # Single test run
pnpm test:coverage    # Coverage report (V8)
pnpm build            # Compile CJS + ESM + declarations
pnpm lint             # Biome check + tsc --noEmit

Run a single test file:

pnpm vitest run src/string/capitalize.test.ts

Note: package.json exports are auto-generated on every build. Do not edit the exports field manually.


📊 Metrics

| Metric | Value | |--------|-------| | npm downloads / month | npm monthly downloads | | npm downloads / week | npm weekly downloads | | Latest release | GitHub tag | | Last commit | GitHub last commit |