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

@nodelibraries/enhanced-abort-controller

v1.1.0

Published

Enhanced AbortController with Node.js-style patterns for modern applications

Readme

Enhanced Abort Controller

npm version License: MIT TypeScript Node.js

Enhanced AbortController with Node.js-style patterns for modern TypeScript applications.

🚀 Features

This library provides an enhanced version of the native AbortController with additional features for modern Node.js applications:

EnhancedAbortController

  • abort(reason?: string) - Immediately abort the operation with optional reason

  • abortAfter(ms: number) - Abort after a specified delay in milliseconds

  • abortAfterTimeSpan(timeSpan: TimeSpan) - Abort using TimeSpan objects

  • dispose() - Dispose resources and abort

  • reason - Get the abort reason

  • Static methods for creating timeout controllers and linked controllers

EnhancedAbortSignal

  • register(callback) - Register a callback with AbortRegistration

  • throwIfAborted(message?: string) - Throw AbortError if aborted

  • whenAborted - Promise that resolves when signal is aborted

  • canBeAborted - Check if signal can be aborted

  • Static properties for common signal patterns

  • Static methods for timeout and signal combination

TimeSpan

  • Time interval representation for precise time management
  • Multiple unit constructors (milliseconds, seconds, minutes, hours, days)
  • Total value properties for different time units
  • Static properties (zero, maxValue, minValue)

AbortRegistration

  • unregister() - Unregister the callback
  • dispose() - Dispose the registration
  • isDisposed - Check if registration is disposed

Error Handling

  • AbortError - Error thrown when operation is aborted
  • Custom error messages support
  • Proper error inheritance from native Error class

📦 Installation

npm install @nodelibraries/enhanced-abort-controller

TypeScript Support

This library is written in TypeScript and includes full type definitions. No additional @types package is required.

🎯 Quick Start

Basic Usage

import {
  EnhancedAbortController,
  EnhancedAbortSignal,
  AbortError,
} from '@nodelibraries/enhanced-abort-controller';

// Create a controller
const controller = new EnhancedAbortController();

// Register a callback
const registration = controller.signal.register(() => {
  console.log('⚠️ Operation was aborted!');
});

// Abort after 5 seconds
controller.abortAfter(5000);

// Use in async operations
async function doWork(signal: EnhancedAbortSignal) {
  for (let i = 0; i < 10; i++) {
    signal.throwIfAborted();
    console.log(`Working... ${i}`);
    await new Promise((resolve) => setTimeout(resolve, 1000));
  }
}

doWork(controller.signal).catch((err) => {
  if (err instanceof AbortError) {
    console.log('Operation was aborted');
  }
});

// Clean up
registration.unregister();

Timeout-based Abortion

import {
  EnhancedAbortController,
  TimeSpan,
} from '@nodelibraries/enhanced-abort-controller';

const controller = new EnhancedAbortController();

// Abort after 3 seconds using milliseconds
controller.abortAfter(3000);

// Or using TimeSpan
const timeSpan = TimeSpan.fromSeconds(3);
controller.abortAfterTimeSpan(timeSpan);

// Static timeout controller
const timeoutController = EnhancedAbortController.timeout(5000);

Linked Controllers

import { EnhancedAbortController } from '@nodelibraries/enhanced-abort-controller';

const controller1 = new EnhancedAbortController();
const controller2 = new EnhancedAbortController();
const controller3 = new EnhancedAbortController();

// Create a controller that aborts when any of the signals abort
const linkedController = EnhancedAbortController.linkSignals(
  controller1.signal,
  controller2.signal,
  controller3.signal
);

linkedController.signal.register(() => {
  console.log('🔗 Any of the linked signals was aborted!');
});

// Abort one of them
controller1.abort('User cancelled');

📚 API Reference

EnhancedAbortController

The main controller class that manages abort operations.

Constructor

new EnhancedAbortController();

Instance Methods

abort(reason?: string)

Immediately aborts the controller with an optional reason.

const controller = new EnhancedAbortController();
controller.abort('User cancelled the operation');
abortAfter(ms: number)

Aborts the controller after the specified number of milliseconds.

const controller = new EnhancedAbortController();
controller.abortAfter(5000); // Abort after 5 seconds
abortAfterTimeSpan(timeSpan: TimeSpan)

Aborts the controller using a TimeSpan object.

import { TimeSpan } from '@nodelibraries/enhanced-abort-controller';

const controller = new EnhancedAbortController();
const timeSpan = TimeSpan.fromMinutes(2.5);
controller.abortAfterTimeSpan(timeSpan);
dispose()

Disposes the controller and aborts it. After disposal, the controller cannot be reset.

const controller = new EnhancedAbortController();
controller.dispose();

Instance Properties

signal: EnhancedAbortSignal

The abort signal associated with this controller.

const controller = new EnhancedAbortController();
const signal = controller.signal;
isAborted: boolean

Whether the controller is currently aborted.

const controller = new EnhancedAbortController();
console.log(controller.isAborted); // false
controller.abort();
console.log(controller.isAborted); // true
isDisposed: boolean

Whether the controller has been disposed.

const controller = new EnhancedAbortController();
console.log(controller.isDisposed); // false
controller.dispose();
console.log(controller.isDisposed); // true
reason: string | undefined

The reason for the abort, if any.

const controller = new EnhancedAbortController();
controller.abort('User cancelled');
console.log(controller.reason); // "User cancelled"

Static Methods

linkSignals(...signals: EnhancedAbortSignal[]): EnhancedAbortController

Creates a controller that aborts when any of the provided signals abort.

const controller1 = new EnhancedAbortController();
const controller2 = new EnhancedAbortController();

const linkedController = EnhancedAbortController.linkSignals(
  controller1.signal,
  controller2.signal
);
createLinkedController(...signals: EnhancedAbortSignal[]): EnhancedAbortController

Alias for linkSignals.

timeout(ms: number): EnhancedAbortController

Creates a controller that automatically aborts after the specified time.

const timeoutController = EnhancedAbortController.timeout(3000);

EnhancedAbortSignal

Enhanced abort signal with additional functionality.

Instance Methods

register(callback: () => void): AbortRegistration

Registers a callback to be called when the signal is aborted.

const controller = new EnhancedAbortController();
const registration = controller.signal.register(() => {
  console.log('Signal was aborted!');
});

// Later, unregister
registration.unregister();
throwIfAborted(message?: string): void

Throws an AbortError if the signal is aborted.

const controller = new EnhancedAbortController();

try {
  controller.signal.throwIfAborted('Custom message');
  // Continue with work...
} catch (error) {
  if (error instanceof AbortError) {
    console.log('Operation was aborted:', error.message);
  }
}

Instance Properties

isAborted: boolean

Whether the signal is currently aborted.

const controller = new EnhancedAbortController();
console.log(controller.signal.isAborted); // false
controller.abort();
console.log(controller.signal.isAborted); // true
reason: string | undefined

The reason for the abort, if any.

const controller = new EnhancedAbortController();
controller.abort('User cancelled');
console.log(controller.signal.reason); // "User cancelled"
canBeAborted: boolean

Whether the signal can be aborted.

const noneSignal = EnhancedAbortSignal.none;
console.log(noneSignal.canBeAborted); // false
whenAborted: Promise<void>

A promise that resolves when the signal is aborted.

const controller = new EnhancedAbortController();

controller.signal.whenAborted.then(() => {
  console.log('Signal was aborted!');
});

// Later
controller.abort();
signal: AbortSignal

The underlying native AbortSignal.

const controller = new EnhancedAbortController();
const nativeSignal = controller.signal;

Static Properties

none: EnhancedAbortSignal

A signal that never aborts.

const neverAborting = EnhancedAbortSignal.none;
console.log(neverAborting.isAborted); // false
console.log(neverAborting.canBeAborted); // false
aborted: EnhancedAbortSignal

A signal that is already aborted.

const alreadyAborted = EnhancedAbortSignal.aborted;
console.log(alreadyAborted.isAborted); // true

Static Methods

timeout(ms: number): EnhancedAbortSignal

Creates a signal that automatically aborts after the specified time.

const timeoutSignal = EnhancedAbortSignal.timeout(2000);
any(signals: EnhancedAbortSignal[]): EnhancedAbortSignal

Creates a signal that aborts when any of the provided signals abort.

const signal1 = new EnhancedAbortController();
const signal2 = new EnhancedAbortController();

const anySignal = EnhancedAbortSignal.any([signal1.signal, signal2.signal]);

TimeSpan

A class for representing time intervals, inspired by .NET Core's TimeSpan.

Constructor

new TimeSpan(milliseconds: number)

Instance Properties

milliseconds: number

The total milliseconds of the time span.

const timeSpan = TimeSpan.fromSeconds(30);
console.log(timeSpan.milliseconds); // 30000
totalSeconds: number

The total seconds of the time span.

const timeSpan = TimeSpan.fromMinutes(2.5);
console.log(timeSpan.totalSeconds); // 150
totalMinutes: number

The total minutes of the time span.

const timeSpan = TimeSpan.fromHours(1.5);
console.log(timeSpan.totalMinutes); // 90
totalHours: number

The total hours of the time span.

const timeSpan = TimeSpan.fromDays(1.5);
console.log(timeSpan.totalHours); // 36
totalDays: number

The total days of the time span.

const timeSpan = TimeSpan.fromHours(48);
console.log(timeSpan.totalDays); // 2

Static Methods

fromMilliseconds(ms: number): TimeSpan

Creates a TimeSpan from milliseconds.

const timeSpan = TimeSpan.fromMilliseconds(1500);
fromSeconds(seconds: number): TimeSpan

Creates a TimeSpan from seconds.

const timeSpan = TimeSpan.fromSeconds(30);
fromMinutes(minutes: number): TimeSpan

Creates a TimeSpan from minutes.

const timeSpan = TimeSpan.fromMinutes(2.5);
fromHours(hours: number): TimeSpan

Creates a TimeSpan from hours.

const timeSpan = TimeSpan.fromHours(1.5);
fromDays(days: number): TimeSpan

Creates a TimeSpan from days.

const timeSpan = TimeSpan.fromDays(1.5);

Static Properties

zero: TimeSpan

A TimeSpan representing zero time.

console.log(TimeSpan.zero.milliseconds); // 0
maxValue: TimeSpan

A TimeSpan representing the maximum possible time.

console.log(TimeSpan.maxValue.milliseconds); // 9007199254740991
minValue: TimeSpan

A TimeSpan representing the minimum possible time.

console.log(TimeSpan.minValue.milliseconds); // -9007199254740991

AbortRegistration

Represents a registration for an abort signal callback.

Instance Methods

unregister(): void

Unregisters the callback from the signal.

const controller = new EnhancedAbortController();
const registration = controller.signal.register(() => {
  console.log('Aborted!');
});

registration.unregister();
dispose(): void

Disposes the registration (same as unregister).

const registration = controller.signal.register(() => {
  console.log('Aborted!');
});

registration.dispose();

Instance Properties

isDisposed: boolean

Whether the registration has been disposed.

const registration = controller.signal.register(() => {});
console.log(registration.isDisposed); // false
registration.unregister();
console.log(registration.isDisposed); // true

AbortError

Error thrown when an operation is aborted.

Constructor

new AbortError(message?: string)

Usage

import { AbortError } from '@nodelibraries/enhanced-abort-controller';

try {
  signal.throwIfAborted('Custom message');
} catch (error) {
  if (error instanceof AbortError) {
    console.log('Operation was aborted:', error.message);
  }
}

🔧 Advanced Usage Examples

Complex Async Workflow

import {
  EnhancedAbortController,
  EnhancedAbortSignal,
  AbortError,
} from '@nodelibraries/enhanced-abort-controller';

async function complexWorkflow(signal: EnhancedAbortSignal) {
  console.log('🔄 Starting complex workflow...');

  try {
    // Step 1: Data preparation
    signal.throwIfAborted();
    console.log('📊 Step 1: Preparing data...');
    await new Promise((resolve) => setTimeout(resolve, 500));

    // Step 2: Data processing
    signal.throwIfAborted();
    console.log('⚙️ Step 2: Processing data...');
    await new Promise((resolve) => setTimeout(resolve, 500));

    // Step 3: Data validation
    signal.throwIfAborted();
    console.log('✅ Step 3: Validating data...');
    await new Promise((resolve) => setTimeout(resolve, 500));

    console.log('✅ Complex workflow completed successfully!');
  } catch (error) {
    if (error instanceof AbortError) {
      console.log('⛔️ Complex workflow aborted:', error.message);
    } else {
      console.log('❌ Complex workflow failed:', error);
    }
  }
}

const controller = new EnhancedAbortController();
complexWorkflow(controller.signal);

// Abort after 1 second
setTimeout(() => {
  controller.abort('User cancelled workflow');
}, 1000);

🌐 Library Integration Examples

Fetch API Integration

import {
  EnhancedAbortController,
  EnhancedAbortSignal,
  AbortError,
} from '@nodelibraries/enhanced-abort-controller';

async function fetchWithAbort(url: string, signal: EnhancedAbortSignal) {
  try {
    const response = await fetch(url, {
      signal: signal.signal, // Use native AbortSignal
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    if (error instanceof AbortError) {
      console.log('Fetch was aborted:', error.message);
    }
    throw error;
  }
}

const controller = new EnhancedAbortController();
controller.abortAfter(5000); // Abort after 5 seconds

fetchWithAbort('https://api.example.com/data', controller.signal).catch(() =>
  console.log('Fetch completed')
);

Axios Integration

import {
  EnhancedAbortController,
  EnhancedAbortSignal,
  AbortError,
} from '@nodelibraries/enhanced-abort-controller';
import axios from 'axios';

async function axiosWithAbort(url: string, signal: EnhancedAbortSignal) {
  try {
    const response = await axios.get(url, {
      signal: signal.signal,
    });

    return response.data;
  } catch (error) {
    if (error instanceof AbortError) {
      console.log('Axios request was aborted:', error.message);
    }
    throw error;
  }
}

const controller = new EnhancedAbortController();
controller.abortAfter(3000);

axiosWithAbort('https://api.example.com/data', controller.signal).catch(() =>
  console.log('Axios request completed')
);

Resource Cleanup Pattern

import { EnhancedAbortController } from '@nodelibraries/enhanced-abort-controller';

const controller = new EnhancedAbortController();

// Simulate resource allocation
let resources = ['Resource 1', 'Resource 2', 'Resource 3'];
console.log('📦 Allocated resources:', resources);

const cleanupRegistration = controller.signal.register(() => {
  // Cleanup resources
  resources = [];
  console.log('🧹 Resources cleaned up due to abort');
});

// Simulate work
setTimeout(() => {
  console.log('✅ Work completed, cleaning up normally...');
  cleanupRegistration.unregister();
  resources = [];
  console.log('🧹 Resources cleaned up normally');
}, 1500);

// Abort after 1 second (before normal completion)
setTimeout(() => {
  controller.abort('Resource cleanup test');
}, 1000);

Multiple Controllers with Different Strategies

import {
  EnhancedAbortController,
  TimeSpan,
} from '@nodelibraries/enhanced-abort-controller';

// Controller with immediate abort
const immediateController = new EnhancedAbortController();
immediateController.signal.register(() => {
  console.log('⚡ Immediate controller aborted');
});

// Controller with timeout
const timeoutController = EnhancedAbortController.timeout(3000);
timeoutController.signal.register(() => {
  console.log('⏰ Timeout controller aborted');
});

// Controller with TimeSpan
const timeSpanController = new EnhancedAbortController();
timeSpanController.abortAfterTimeSpan(TimeSpan.fromSeconds(2.5));
timeSpanController.signal.register(() => {
  console.log('📅 TimeSpan controller aborted');
});

// Abort immediate controller after 1 second
setTimeout(() => {
  immediateController.abort('Immediate abort');
}, 1000);

Error Handling Patterns

import {
  EnhancedAbortController,
  EnhancedAbortSignal,
  AbortError,
} from '@nodelibraries/enhanced-abort-controller';

const controller = new EnhancedAbortController();

// Pattern 1: Try-catch with throwIfAborted
async function pattern1(signal: EnhancedAbortSignal) {
  try {
    signal.throwIfAborted();
    console.log('✅ Pattern 1: Operation completed');
  } catch (error) {
    if (error instanceof AbortError) {
      console.log('⛔️ Pattern 1: Operation aborted');
    }
  }
}

// Pattern 2: Check isAborted before operations
async function pattern2(signal: EnhancedAbortSignal) {
  if (signal.isAborted) {
    console.log('⛔️ Pattern 2: Signal already aborted');
    return;
  }
  console.log('✅ Pattern 2: Operation completed');
}

// Pattern 3: Use whenAborted promise
async function pattern3(signal: EnhancedAbortSignal) {
  await signal.whenAborted;
  console.log('⛔️ Pattern 3: Signal was aborted');
}

// Test patterns
pattern1(controller.signal);
pattern2(controller.signal);
pattern3(controller.signal);

// Abort after delay
setTimeout(() => {
  controller.abort('Error pattern test');
}, 800);

🧪 Testing

The library includes comprehensive test coverage. Run the tests with:

npm test

Run tests with coverage:

npm run test:coverage

📝 Development

Building

npm run build

Linting

npm run lint

Development Mode

npm run dev

Running Examples

npm run build
node dist/examples/showcases.js

🌐 GitHub Pages

This project includes GitHub Pages support for hosting documentation. The documentation is automatically deployed when changes are pushed to the main branch.

Setup

  1. Enable GitHub Pages in your repository settings:

    • Go to Settings → Pages
    • Source: Select "GitHub Actions"
  2. Automatic Deployment:

    • The .github/workflows/pages.yml workflow automatically builds and deploys documentation
    • Documentation is available at: https://nodelibraries.github.io/enhanced-abort-controller
  3. Manual Deployment:

    • The workflow can also be triggered manually from the Actions tab

Documentation Structure

  • docs/index.html - Main documentation page
  • Automatically generated from the project build
  • Includes API reference, examples, and usage patterns

Local Preview

To preview the documentation locally:

# Build the project
npm run build

# Serve the docs directory
npx serve docs
# or
python -m http.server 8000 -d docs

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • Built on top of the native Web API AbortController
  • Designed for modern TypeScript and Node.js applications
  • Node.js-style patterns for clean and efficient async operations

📖 Documentation

Full API documentation is available at:

🔗 Links

📊 Project Status

  • ✅ Full TypeScript support with type definitions
  • ✅ Comprehensive test coverage
  • ✅ Zero dependencies
  • ✅ Compatible with Node.js 16+ and modern browsers
  • ✅ MIT License

🚀 Quick Examples

Basic Timeout

import { EnhancedAbortController } from '@nodelibraries/enhanced-abort-controller';

const controller = new EnhancedAbortController();
controller.abortAfter(5000); // Auto-abort after 5 seconds

// Use with fetch
fetch('https://api.example.com/data', {
  signal: controller.signal.signal,
}).catch((err) => {
  if (err.name === 'AbortError') {
    console.log('Request was cancelled');
  }
});

Linked Controllers

import { EnhancedAbortController } from '@nodelibraries/enhanced-abort-controller';

const userController = new EnhancedAbortController();
const timeoutController = EnhancedAbortController.timeout(10000);

// Abort if user cancels OR timeout occurs
const linked = EnhancedAbortController.linkSignals(
  userController.signal,
  timeoutController.signal
);

// Use linked signal
fetch('https://api.example.com/data', {
  signal: linked.signal.signal,
});

Async Workflow with Cleanup

import {
  EnhancedAbortController,
  AbortError,
} from '@nodelibraries/enhanced-abort-controller';

async function processData(signal: EnhancedAbortSignal) {
  const resources: string[] = [];

  try {
    // Register cleanup
    signal.register(() => {
      console.log('Cleaning up resources...');
      resources.length = 0;
    });

    // Process data
    for (let i = 0; i < 100; i++) {
      signal.throwIfAborted();
      resources.push(`Resource ${i}`);
      await processItem(i);
    }
  } catch (error) {
    if (error instanceof AbortError) {
      console.log('Processing was cancelled');
    }
    throw error;
  }
}

Made with ❤️ for the TypeScript and Node.js community