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

@resolvx/core

v2.4.2

Published

Composable TypeScript primitives for production Node.js — Result types, async utilities, caches, structured logging, typed HTTP.

Downloads

727

Readme

@resolvx/core

Composable TypeScript primitives for production Node.js.

No magic. No framework opinions. Seven focused modules you can import individually or together. Tree-shakeable, typed end-to-end, zero mandatory dependencies.

npm install @resolvx/core

chalk is an optional peer dependency for coloured log output. Install it if you want colour, skip it if you don't — the logger works either way.


Modules

result — Explicit error handling

Stop writing try/catch everywhere. Result<T, E> makes failure visible in function signatures.

import { capture, captureAsync, ok, err, combine, unwrapOr } from "@resolvx/core/result";

// Wrap a throwing function
const parsed = capture(() => JSON.parse(raw));
if (!parsed.ok) {
  console.error("Bad JSON:", parsed.error);
  return;
}
console.log(parsed.value);

// Async version
const result = await captureAsync(() => fetch(url).then(r => r.json()));

// Combine an array of Results — returns first Err or Ok([...values])
const all = combine([parseA, parseB, parseC]);

// Default on failure
const name = unwrapOr(parseName(input), "anonymous");

API: ok err capture captureAsync map mapErr andThen tap tapErr unwrapOr unwrapOrElse unwrap combine partition fromNullable fromThrowable


async — Async control flow

import { retry, pool, memoize, debounce, throttle, once, withTimeout, sleep } from "@resolvx/core/async";

// Retry with exponential backoff + jitter
const data = await retry(() => fetchFromApi(url), {
  attempts:       4,
  baseDelayMs:    300,
  isNonRetryable: e => e instanceof HttpError && e.status === 404,
  onFailedAttempt: (err, attempt, nextDelay) =>
    console.warn(`Attempt ${attempt} failed, retrying in ${nextDelay}ms`),
});

// Bounded concurrency — 5 requests at a time, output order preserved
const pages = await pool(urls.map(url => () => fetch(url).then(r => r.json())), 5);

// Memoize with TTL + in-flight deduplication
// Two concurrent calls with the same args share one execution
const getUser = memoize(fetchUser, { ttlMs: 60_000 });

// Timeout
const result = await withTimeout(() => heavyComputation(), 5000, "heavyComputation");

API: sleep withTimeout retry pool memoize debounce throttle once


cache — In-memory caching

Three implementations, consistent interface.

import { TtlCache, LruCache, DedupeCache } from "@resolvx/core/cache";

// Time-to-live cache — entries expire after ttlMs
const prices = new TtlCache<string, number>(30_000);
const price = await prices.getOrSet("ETH", () => fetchPrice("ETH"));

// LRU cache — evicts least-recently-used when full
const images = new LruCache<string, Buffer>(100);
images.set("logo", buffer);

// Deduplication cache — concurrent callers share one in-flight request
const users = new DedupeCache<string, User>(60_000);
// Called 10 times simultaneously → only 1 fetchUser() call
const user = await users.getOrFetch(userId, id => fetchUser(id));

API: TtlCache · LruCache · DedupeCache


fmt — Formatting

Pure functions. No side effects.

import { fmtNum, fmtUsd, fmtMs, fmtDuration, fmtBytes, fmtToken, fmtHex, fmtRelative, renderTable } from "@resolvx/core/fmt";

fmtNum(1_234_567.89, 2)   // "1,234,567.89"
fmtUsd(1234.5)             // "$1,234.50"
fmtMs(12_345)              // "12.35s"
fmtDuration(3725)          // "1h 2m 5s"
fmtBytes(1_536)            // "1.50 KB"
fmtToken(1_500_000n, 6)    // "1.500000"  (bigint — no precision loss)
fmtHex("0xabcdef1234", 6, 4) // "0xabcd…3234"
fmtRelative(Date.now() / 1000 - 3700) // "1h 1m ago"

// No-dependency ASCII table
console.log(renderTable(
  ["Name", "Age"],
  [["Alice", "30"], ["Bob", "25"]],
));

log — Structured logger

Named namespaces, child loggers, pluggable transport.

import { createLogger } from "@resolvx/core/log";

const log = createLogger("api");
log.info("Server started", { port: 3000 });
log.warn("Rate limit approaching", { remaining: 5 });
log.error("Request failed", new Error("timeout"), { url: "/api/data" });

// Child logger — inherits level and transport, adds context to every line
const reqLog = log.child("request", { requestId: "abc-123" });
reqLog.info("Processing");  // → ns=request requestId=abc-123

// Measure async operations
const data = await log.time("fetchData", () => fetch(url).then(r => r.json()));

// Control level at runtime
log.setLevel("debug");

// Custom transport (e.g. JSON to stdout for log aggregators)
const log2 = createLogger("worker", {
  transport: rec => process.stdout.write(JSON.stringify(rec) + "\n"),
});

Set LOG_LEVEL env var to control the default level (debug | info | warn | error | silent).


net — Typed HTTP

import { fetchJson, getJson, postJson, RateLimiter, HttpError, NetworkError } from "@resolvx/core/net";

// GET with timeout + retry (3 attempts, backoff, 4xx not retried)
const user = await getJson<User>("https://api.example.com/users/1");

// POST JSON
const created = await postJson<Post>("/api/posts", { title: "Hello" });

// Error types
try {
  await getJson("/api/data");
} catch (e) {
  if (e instanceof HttpError)    console.log(e.status, e.url);
  if (e instanceof NetworkError) console.log("DNS/connection failure", e.cause);
}

// Rate limiter — 10 req/s, bursting to 20
const limiter = new RateLimiter({ rps: 10, burst: 20 });
const throttledFetch = limiter.wrap(() => getJson(url));
await Promise.all(Array.from({ length: 100 }, throttledFetch));

types — TypeScript utilities

import { brand, assertUnreachable, hasKeys, isDefined, isString } from "@resolvx/core/types";

// Branded types — prevent mixing structurally identical primitives
type UserId  = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;

const uid = brand<UserId>("user-123");
// processOrder(uid) ← type error if OrderId is expected

// Exhaustiveness check — compile error if a union case is unhandled
function describe(status: "ok" | "pending" | "failed"): string {
  switch (status) {
    case "ok":      return "✓";
    case "pending": return "…";
    case "failed":  return "✗";
    default:        return assertUnreachable(status);
  }
}

// Runtime type narrowing
if (hasKeys(data, ["price", "symbol"])) {
  console.log(data.price); // data is Record<"price"|"symbol", unknown>
}

Requirements

  • Node.js ≥ 18 (native fetch)
  • TypeScript ≥ 5.0

Contributing

Bug reports and PRs welcome. Run npm test before submitting.

License

MIT