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

@zukhruf/lease

v0.8.0

Published

A lease and its loss: the holder gets an AbortSignal that aborts once, with LeaseLostError, when another holder may have the right. The issuer keeps a LeaseController.

Readme

@zukhruf/lease

A lease gives one holder the right to act for a subject, for example a key of a mutex or the leadership of an election. The holder must know when it lost that right. This package gives the holder a signal that aborts when another holder may have the right. @zukhruf/mutex, @zukhruf/single-flight, and @zukhruf/election give out their leases with it.

The words in these documents have one meaning each. See the glossary in CONTEXT.md.

A lease is a signal

A holder gets a Lease. A lease has one property: signal, an AbortSignal.

  • The signal aborts one time, with a LeaseLostError, when another holder may have the right.
  • The signal never aborts when the holder releases the lease.

The holder stops its work when the signal aborts. Give the signal to each call that takes a signal, and check it before each write:

import type { Lease } from '@zukhruf/lease';

async function copyRows(lease: Lease, batches: Row[][]) {
  for (const batch of batches) {
    lease.signal.throwIfAborted();
    await fetch('https://warehouse.example/rows', {
      method: 'POST',
      body: JSON.stringify(batch),
      signal: lease.signal,
    });
  }
}

Tell a lost lease from other errors

The reason of the signal is a LeaseLostError. Its subject names what the lease gave the right to. Its cause, when there is one, is what the issuer saw: for example, the error of a coordinator that refused the claim.

import { LeaseLostError } from '@zukhruf/lease';

try {
  await copyRows(lease, batches);
} catch (error) {
  if (error instanceof LeaseLostError) {
    console.log(`Another holder may have ${error.subject} now.`, error.cause);
  }
  throw error;
}

A catch with instanceof LeaseLostError works for the leases of each package that uses this package, because they all give the same class.

Give out a lease

An issuer makes one LeaseController for each lease. It keeps the controller, and it gives the holder only the signal. AbortController and AbortSignal use the same split: only the code that has the controller can abort the signal.

import { type Lease, LeaseController } from '@zukhruf/lease';

const controller = new LeaseController('orders');
const lease: Lease = { signal: controller.signal };

// The coordinator refused the claim, so another holder may have it:
controller.lose(new Error('The coordinator refused the claim.'));

// The holder released the lease:
controller.end();
  • lose(cause?) aborts the signal with new LeaseLostError(subject, { cause }). When you give no cause, the error has no cause property.
  • A lease is lost one time. A second lose keeps the reason of the first.
  • end() never aborts the signal. After end(), lose does nothing: the holder gave the right up, so it cannot lose it. A loss that the issuer sees late, after the release, does not reach the holder.
  • end() can be called again. It keeps the reason of an earlier loss.

A lease lasts for a session, not for a time

In many systems, a lease ends after a time unless the holder renews it. A lease of zukhruf has no timer. It ends when the holder releases it, or when the holder's process stops: the operating system then frees the claim of that process. It is lost when the issuer decides that another holder may have the right, for example when a coordinator refuses the claim after a failover. Thus this package has no timer and no renew.

A lease warns the holder. It does not protect a resource

A holder can stop for some time, for example in a long garbage collection, and then write. In that time, the issuer can see the loss and give the right to another holder. The holder writes before it checks its signal. Thus the signal is a warning, not a protection.

To protect a resource, use a fencing token. The resource keeps the highest token that it accepted, and it refuses a write with a lower token. Fencing tokens are in @zukhruf/fencing. A lease and a fencing token are two concepts: some systems use a lease with no token, and others use a token with no lease. See ADR 0001.

The same concepts in other systems

| This package | Other systems | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Lease | Lease: Gray and Cheriton, "Leases: An Efficient Fault-Tolerant Mechanism for Distributed File Cache Consistency" (1989); Kubernetes coordination.k8s.io/v1 Lease; etcd concurrency.Session | | lease.signal aborts | etcd Session.Done() closes its channel; Go ctx.Done() closes | | LeaseLostError | Hazelcast LockOwnershipLostException; Go context.Cause(ctx) | | LeaseController and Lease | Web AbortController and AbortSignal; Go context.WithCancelCause, which returns the context and its cancel function | | lose(cause) keeps the first reason | Go cancel(cause): a second call does nothing; AbortController.abort(reason): a second call does nothing |

The leases of Gray and Cheriton, Kubernetes, and etcd last for a time, and the holder renews them. The leases of zukhruf last for a session.