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

@carl.fyi/runtime

v0.1.0

Published

Keep application plumbing predictable with retries, debouncing, typed results, caching and secure random codes.

Readme

@carl.fyi/runtime

Keep application plumbing predictable with retries, debouncing, typed results, caching and secure random codes.

Interactive documentation

Install

npm install @carl.fyi/runtime

Quick start

import { debounce } from "@carl.fyi/runtime";

const save = debounce((value: string) => console.log(value), 300);
save("draft");
if (save.pending()) save.flush();

Entry points

| Import | Purpose | | -------------------------- | ---------------------- | | @carl.fyi/runtime | All public exports | | @carl.fyi/runtime/async | Focused subpath import | | @carl.fyi/runtime/cache | Focused subpath import | | @carl.fyi/runtime/random | Focused subpath import | | @carl.fyi/runtime/result | Focused subpath import |

All entry points are ESM, side-effect-free, and include TypeScript declarations.

Public API

This is the complete export inventory. The detailed reference below mirrors the APIs demonstrated on the documentation website; its signatures, descriptions, defaults, errors, and examples are compiled from the package source.

| Export | Kind | Import from | Description | | --------------------------- | --------- | -------------------------- | ------------------------------------------------------------------------------- | | backoffDelay | function | @carl.fyi/runtime/async | Calculate one bounded exponential-backoff delay. | | BackoffOptions | interface | @carl.fyi/runtime/async | Public interface exported by this package. | | debounce | function | @carl.fyi/runtime/async | Create a trailing-edge function that runs after calls become quiet. | | DebouncedFunction | interface | @carl.fyi/runtime/async | Public interface exported by this package. | | withBackoff | function | @carl.fyi/runtime/async | Retry an asynchronous operation with bounded exponential backoff. | | AsyncCache | interface | @carl.fyi/runtime/cache | Public interface exported by this package. | | createCachedAsyncFunction | function | @carl.fyi/runtime/cache | Wrap an async function with read-through caching and in-flight deduplication. | | HashInput | type | @carl.fyi/runtime/cache | Public type exported by this package. | | MemoryCache | class | @carl.fyi/runtime/cache | Public class exported by this package. | | sha256Hex | function | @carl.fyi/runtime/cache | Hash text or bytes with SHA-256 and encode the digest as lowercase hexadecimal. | | randomCode | function | @carl.fyi/runtime/random | Generate an unbiased human-readable random code. | | randomString | function | @carl.fyi/runtime/random | Public function exported by this package. | | RandomStringOptions | interface | @carl.fyi/runtime/random | Public interface exported by this package. | | READABLE_CODE_ALPHABET | value | @carl.fyi/runtime/random | Public value exported by this package. | | err | value | @carl.fyi/runtime/result | Public value exported by this package. | | fromPromise | function | @carl.fyi/runtime/result | Capture a rejected promise in a typed Result. | | fromThrowable | function | @carl.fyi/runtime/result | Capture a synchronous exception in a typed Result. | | isErr | value | @carl.fyi/runtime/result | Public value exported by this package. | | isOk | value | @carl.fyi/runtime/result | Public value exported by this package. | | ok | value | @carl.fyi/runtime/result | Public value exported by this package. | | Result | type | @carl.fyi/runtime/result | Public type exported by this package. |

API reference

@carl.fyi/runtime/async

debounce

debounce<Arguments extends unknown[], Result>(fn: (...args: Arguments) => Result, waitMs: number): DebouncedFunction<Arguments, Result>

Create a trailing-edge function that runs after calls become quiet.

The wrapper retains only the latest arguments and receiver. Use cancel, flush, and pending to control scheduled work.

| Parameter | Type | Description | | --------- | -------------------------------- | ------------------------------------------ | | fn | (...args: Arguments) => Result | Function to invoke after the delay. | | waitMs | number | Non-negative finite delay in milliseconds. |

Returns: A debounced callable with cancellation, flushing, and pending-state helpers.

Throws

  • A RangeError when waitMs is negative or non-finite.

Example

import { debounce } from "@carl.fyi/runtime";

const save = debounce((value: string) => console.log(value), 300);
save("draft");
if (save.pending()) save.flush();

@carl.fyi/runtime/async

backoffDelay

backoffDelay(attempt: number, options?: Pick<BackoffOptions, "baseDelayMs" | "factor" | "maxDelayMs" | "jitter" | "random">): number

Calculate one bounded exponential-backoff delay.

attempt is zero-based. Jitter is clamped to the inclusive range from zero to one.

| Parameter | Type | Description | | -------------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | attempt | number | Zero-based retry index. | | options (optional) | Pick<BackoffOptions, "baseDelayMs" \| "factor" \| "maxDelayMs" \| "jitter" \| "random"> | Timing, cap, jitter, and random-source settings. | | options.baseDelayMs (optional) | number | Delay before the first retry, in milliseconds. Default: 200. | | options.factor (optional) | number | Multiplier applied for each subsequent retry. Default: 2. | | options.maxDelayMs (optional) | number | Upper bound for any delay, in milliseconds. Default: 30000. | | options.jitter (optional) | number | Symmetric random variation from zero to one. Default: 0.2. | | options.random (optional) | () => number | Random-number source used to make jitter testable. Default: Math.random. |

Returns: The rounded delay in milliseconds.

Throws

  • A RangeError when attempt is not a non-negative integer.

Example

import { backoffDelay } from "@carl.fyi/runtime";

const delays = [0, 1, 2].map((attempt) => backoffDelay(attempt, { baseDelayMs: 250, jitter: 0 }));
// [250, 500, 1000]

withBackoff

withBackoff<T>(operation: (attempt: number) => Promise<T>, options?: BackoffOptions): Promise<T>

Retry an asynchronous operation with bounded exponential backoff.

The first call is attempt zero and does not wait. Injectable timing hooks make tests deterministic.

| Parameter | Type | Description | | -------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------- | | operation | (attempt: number) => Promise<T> | Async operation receiving its zero-based attempt number. | | options (optional) | BackoffOptions | Retry count, timing, cancellation, and lifecycle hooks. | | options.retries (optional) | number | Number of retries after the initial attempt. Default: 3. | | options.baseDelayMs (optional) | number | Delay before the first retry, in milliseconds. Default: 200. | | options.factor (optional) | number | Multiplier applied for each subsequent retry. Default: 2. | | options.maxDelayMs (optional) | number | Upper bound for any delay, in milliseconds. Default: 30000. | | options.jitter (optional) | number | Symmetric random variation from zero to one. Default: 0.2. | | options.random (optional) | () => number | Random-number source used to make jitter testable. Default: Math.random. | | options.sleep (optional) | (milliseconds: number) => Promise<void> | Injectable delay implementation. | | options.shouldRetry (optional) | (error: unknown, attempt: number) => boolean | Predicate that can stop retries for a particular error. | | options.onRetry (optional) | (error: unknown, attempt: number, delayMs: number) => void | Callback invoked immediately before each retry delay. | | options.signal (optional) | AbortSignal | Abort signal checked before every attempt. |

Returns: A promise for the first successful operation result.

Throws

  • The last operation error, a cancellation reason, or an error from a supplied hook.

Example

import { withBackoff } from "@carl.fyi/runtime";

const value = await withBackoff((attempt) => fetch(`/api/data?attempt=${attempt}`), {
  retries: 4,
  baseDelayMs: 250,
});

@carl.fyi/runtime/result

fromThrowable

fromThrowable<T, E = unknown>(operation: () => T, mapError?: (error: unknown) => E): Result<T, E>

Capture a synchronous exception in a typed Result.

Successful values and mapped failures are returned as serialisable discriminated unions.

| Parameter | Type | Description | | --------------------- | ----------------------- | --------------------------------------------------------------------------- | | operation | () => T | Synchronous operation to execute once. | | mapError (optional) | (error: unknown) => E | Optional conversion from an unknown thrown value to the desired error type. |

Returns: An ok result with the value or an error result with the captured failure.

Example

import { fromThrowable } from "@carl.fyi/runtime";

const parsed = fromThrowable(() => JSON.parse('{"ok":true}'), String);
if (parsed.ok) console.log(parsed.value);

@carl.fyi/runtime/cache

sha256Hex

sha256Hex(input: HashInput): Promise<string>

Hash text or bytes with SHA-256 and encode the digest as lowercase hexadecimal.

The input is copied before Web Crypto receives it, so callers may safely reuse their original buffer.

| Parameter | Type | Description | | --------- | ----------- | ---------------------------------------------------- | | input | HashInput | UTF-8 text, an ArrayBuffer, or a typed byte array. |

Returns: A promise for the 64-character hexadecimal digest.

Example

import { sha256Hex } from "@carl.fyi/runtime";

const key = await sha256Hex("Useful things for making things.");
console.log(key.length); // 64

@carl.fyi/runtime/random

randomCode

randomCode(length?: number, options?: Omit<RandomStringOptions, "length" | "alphabet">): string

Generate an unbiased human-readable random code.

The alphabet omits visually ambiguous characters; rejection sampling avoids modulo bias.

| Parameter | Type | Description | | -------------------------------- | --------------------------------------------------- | ------------------------------------------------------------- | | length (optional) | number | Number of characters to generate. Default: 8. | | options (optional) | Omit<RandomStringOptions, "length" \| "alphabet"> | Optional injectable random-byte source. | | options.randomBytes (optional) | (length: number) => Uint8Array | Injectable cryptographic byte source for deterministic tests. |

Returns: A cryptographically random code from READABLE_CODE_ALPHABET.

Throws

  • A RangeError when length is outside one to 4096.

Example

import { randomCode } from "@carl.fyi/runtime";

const inviteCode = randomCode(8);
// e.g. "7KMW3QPX"

License

MIT