Skip to content

trananhtung/timefence

Repository files navigation

timefence

All Contributors

Put a time limit on any promise — with real AbortSignal cancellation and a composable deadline signal. Zero dependencies.

CI npm version bundle size types license

Promise.race([op, timer]) "times out" — but the slow operation keeps running in the background, holding a socket open and burning quota. timefence gives the operation an AbortSignal that fires on timeout, so the underlying fetch (or any cooperative work) is actually cancelled, not just ignored.

import { withTimeout } from "timefence";

// On timeout, the fetch is aborted — not left dangling.
const res = await withTimeout((signal) => fetch(url, { signal }), 5000);

Why timefence?

  • Real cancellation. The function form receives an AbortSignal that fires on timeout or when your own signal aborts — wire it to fetch/streams.
  • Fallback or throw. Reject with a typed TimeoutError, or resolve with a fallback value when you'd rather degrade than fail.
  • Composable deadlines. deadline(ms, signal?) returns an AbortSignal that trips after ms (or earlier if your signal aborts) — like AbortSignal.timeout but composable, with an unref'd timer so it won't keep Node alive.
  • Zero dependencies, ESM + CJS + types.

Install

npm install timefence
# or: pnpm add timefence  /  yarn add timefence  /  bun add timefence

API

withTimeout(input, ms, options?) → Promise<T>

input is a promise, or (signal) => Promise (preferred — enables cancellation).

await withTimeout(slowPromise, 1000);                         // throws TimeoutError
await withTimeout((s) => fetch(url, { signal: s }), 1000);     // aborts the fetch
await withTimeout(loadFresh(), 800, { fallback: () => cached });
Option Type Default Description
message string Message for the thrown TimeoutError.
signal AbortSignal Cancel early from outside (rejects with its reason).
fallback () => T | Promise<T> Resolve with this on timeout instead of throwing.

ms = Infinity disables the timeout while still honoring signal.

deadline(ms, signal?) → AbortSignal

const signal = deadline(10_000, userSignal);
await fetch(url, { signal });          // aborts after 10s, or when userSignal does

TimeoutError / isTimeoutError(err)

try {
  await withTimeout(op, 1000);
} catch (err) {
  if (isTimeoutError(err)) retryOrDegrade();
  else throw err;
}

Pairs well with

  • retryfn — retry an operation that timed out.
  • runpool / ratebucket — bound concurrency and rate; timefence bounds time.

Contributors ✨

This project follows the all-contributors specification. Contributions of any kind are welcome — code, docs, bug reports, ideas, reviews! See the emoji key for how each contribution is recognized, and open a PR or issue to get involved.

Thanks goes to these wonderful people:

Tung Tran
Tung Tran

💻 🚧

License

MIT © Tung Tran

About

Put a time limit on any promise, with real AbortSignal cancellation and a composable deadline signal. Zero dependencies.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages