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

awaitery

v1.0.19

Published

Wait for things to happen or just wait in general.

Readme

Awaitery

Usage

deferred

Create a promise whose resolve and reject functions can be called externally. This is useful for deterministic synchronization between concurrent operations.

import deferred from "awaitery/build/deferred.js"

const ready = deferred()

startWork().then(ready.resolve, ready.reject)
await ready.promise

retry

Retry a callback until it succeeds or you exhaust the configured tries (default 3); optionally wrap each attempt in a timeout and wait between failed attempts. Defaults to 3 tries with no timeout and no wait unless you pass options.

import retry from "awaitery/src/retry.js"

await retry({tries: 3, wait: 1000, timeout: 4000}, async () => {
  const submitButton = await systemTest.findByTestID("signInButton")

  await systemTest.click(submitButton)
})

await retry(async () => {
  const submitButton = await systemTest.findByTestID("signInButton")

  await systemTest.click(submitButton)
})

Cancellation and conditional retries

Pass a signal to cancel cooperatively and a shouldRetry predicate to stop early on non-retryable errors. shouldRetry receives a forward-compatible object argument (including the external signal) and may be async:

const controller = new AbortController()

await retry({tries: 5, wait: 1000, timeout: 4000, signal: controller.signal, shouldRetry: ({error, tryNumber, tries, signal}) => {
  if (error instanceof PermanentError) return false // rethrow immediately, no further attempts or delay

  return true
}}, async ({control}) => {
  // `control.signal` aborts on the per-attempt timeout or when `controller` aborts.
  await fetch(url, {signal: control.signal})
})

controller.abort() // no new attempt starts and any in-progress retry delay is cancelled

The callback's context depends on whether a timeout is set. With a timeout, it receives {control} (a TimeoutControl). Without a timeout, it receives {signal} — the external AbortSignal (or undefined when none was passed) — so owned work can still cooperate with cancellation:

await retry({tries: 5, wait: 1000, signal: controller.signal}, async ({signal}) => {
  await fetch(url, {signal}) // cancels when `controller` aborts
})

When cancelled, retry() rejects with signal.reason. Cancellation always wins: a non-cooperative callback (or shouldRetry) that resolves after the abort cannot override it. When signal is combined with timeout, the external signal is composed into the per-attempt TimeoutControl so the callback observes both the deadline and external cancellation through control.signal.

timeout

Run a callback with a hard timeout; if the timer wins, a TimeoutError is thrown, otherwise the callback’s return value is yielded. Defaults to a 5000ms timeout when called without options.

import timeout from "awaitery/src/timeout.js"

await timeout({timeout: 4000}, async () => {
  const submitButton = await systemTest.findByTestID("signInButton")

  await systemTest.click(submitButton)
})

await timeout(async () => {
  const submitButton = await systemTest.findByTestID("signInButton")

  await systemTest.click(submitButton)
})

Pass an external signal to cancel before the deadline. It is composed with the timeout: whichever fires first wins. A timeout rejects with a TimeoutError; external cancellation rejects with signal.reason. In both cases control.signal aborts with that same value, and every timer and listener is cleaned up:

const controller = new AbortController()

const promise = timeout({timeout: 4000, signal: controller.signal}, async ({control}) => {
  await fetch(url, {signal: control.signal})
})

controller.abort(new Error("navigated away")) // rejects `promise` with that exact error

Between async steps the callback can call control.check() to bail early: it throws immediately if control.signal has aborted (surfacing the external signal.reason, even before the deadline) and otherwise throws a TimeoutError once the deadline has passed.

TimeoutError is exported from the timeout module so callers can distinguish a deadline from errors thrown by the callback:

import timeout, {TimeoutError} from "awaitery/build/timeout.js"

try {
  await timeout({timeout: 4000}, runOperation)
} catch (error) {
  if (error instanceof TimeoutError) handleTimeout(error)
  else throw error
}

wait

Sleep for the given milliseconds. Pass an AbortSignal to cancel the sleep early:

import wait from "awaitery/src/wait.js"

await wait(1000)

const controller = new AbortController()

setTimeout(() => controller.abort(), 100)
await wait(1000, {signal: controller.signal}) // rejects with signal.reason after ~100ms

If the signal is already aborted the returned promise rejects immediately; otherwise it clears its timer and removes its listener when either the delay elapses or the signal aborts. The rejection value is signal.reason — the platform's AbortError (a DOMException) when you abort without an explicit reason.

waitFor

Keep retrying a callback while it throws (or rejects) until it eventually succeeds or a timeout is reached; uses a small delay between attempts and rethrows the last error on timeout. Options must be passed as the first argument when provided.

import waitFor from "awaitery/src/wait-for.js"

await waitFor(async () => {
  if (await fileExists(targetPath)) throw new Error("Target file exists")
})

await waitFor({timeout: 2000, wait: 100}, async () => {
  if (await fileExists(targetPath)) throw new Error("Target file exists")
})

Pass a signal to cancel while waiting. External cancellation is reflected in the callback's control.signal, the delay between attempts is cancellation-aware, and no new callback starts once cancelled. A callback that ignores its signal and resolves after cancellation or the deadline cannot win — the cancellation reason (or a TimeoutError) is surfaced instead of that stale success. waitFor() then rejects with signal.reason:

const controller = new AbortController()

await waitFor({timeout: 2000, wait: 100, signal: controller.signal}, async ({control}) => {
  await fetch(url, {signal: control.signal})
})