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

ascall

v1.0.1

Published

A lightweight async call handler with built-in error and response management

Downloads

26

Readme

ASCall

npm version npm downloads TypeScript code style: prettier eslint License: ISC Conventional Commits


ASCall is a lightweight, strongly-typed TypeScript library for orchestrating asynchronous operations and returning standardized responses. It provides a flexible framework for managing success/failure outcomes, concurrency, and lifecycle control across complex workflows.

📘 Table of Contents

  1. Installation
  2. Overview
  3. Core Concepts
  4. ASCall Variants
  5. Usage Examples
  6. Extending Base Classes
  7. Testing & Development
  8. License

🧩 Installation

Using npm:

npm install ascall

Using yarn:

yarn add ascall

🧭 Overview

ASCall standardizes how asynchronous operations are executed and how results are represented. It ensures every call returns a typed, predictable, and consistent response.

The library is built around:

  • 🧱 Response - standardized result wrapper
  • ⚙️ ResponseManager - type-safe response builder
  • 🔁 ASCall family - orchestrators for different async calling patterns
  • 🧠 Extensible base classes - for building custom call strategies

⚙️ Core Concepts

Response

Encapsulates operation outcomes in a single structure:

const success = new Response(true, { data: 'ok' }, null)
const failure = new Response(false, null, new Error('Something went wrong'))

Response Manager

Implements ResponseManager type, it ensures all Response instances are correctly typed and constructed. Created via createResponseManager() the most basic one for Response, methods like fail succed don't really need to return the new instance of Response it's just for typing purpose, you may mutate the response instance and just cast it as required type

🧬 ASCall Variants

The library provides multiple specialized implementations of the base ASCallBase:

| Class | Description | | -------------------------- | -------------------------------------------------------- | | ASCall | Base implementation for simple async orchestration. | | ASCallDedumped | Prevents concurrent duplicate calls (deduplication). | | ASCallDedumpedKeyed | Deduplicates calls by unique keys. | | ASCallDedumpedKeyedTimed | Deduplicates and throttles calls by key and time window. | | ASCallBase | | | ASCallDedumpedBase | |

All variants share the same core principles and typing system - but apply different call strategies.

🚀 Usage Examples

Basic Example (ASCall)

import { ASCall, createResponseManager, parseError } from 'ascall'

const ascall = new ASCall(
  async () => {
    console.log('Executing action...')
    return 'Hello from ASCall!'
  },
  {
    parseError,
    responseManager: createResponseManager<void, Error>(),
  }
)

const response = await ascall.call()

if (response.isSuccess()) {
  console.log('✅ Success:', response.getPayload())
} else {
  console.error('❌ Failure:', response.getError())
}

Deduplication Example (ASCallDedumped)

import { ASCallDedumped, createResponseManager, parseError } from 'ascall'

const dedumpedCall = new ASCallDedumped(
  async () => {
    console.log('Fetching data...')
    return 'Data result'
  },
  {
    parseError,
    responseManager: createResponseManager<string, Error>(),
  }
)

// Multiple calls executed nearly simultaneously
const [r1, r2, r3] = await Promise.all([
  dedumpedCall.call(),
  dedumpedCall.call(),
  dedumpedCall.call(),
])

console.log(r1 === r2 && r2 === r3) // true -> same Promise reused

Use case: Avoids redundant concurrent API calls (e.g. clicking a button multiple times rapidly).

Keyed Deduplication Example (ASCallDedumpedKeyed)

import { ASCallDedumpedKeyed, createResponseManager, parseError } from 'ascall'

const fetchUser = new ASCallDedumpedKeyed(
  async (id: number) => {
    console.log('Fetching user', id)
    return { id, name: 'User ' + id }
  },
  {
    parseError,
    responseManager: createResponseManager<
      { id: number; name: string },
      Error
    >(),
  }
)

// Deduplicates by key (here: user ID)
const [u1, u2] = await Promise.all([fetchUser.call(1, 1), fetchUser.call(1, 1)])

console.log(u1 === u2) // true

Use case: Prevents duplicate network requests for the same key (e.g. same user ID).

Keyed + Timed Deduplication Example (ASCallDedumpedKeyedTimed)

import {
  ASCallDedumpedKeyedTimed,
  createResponseManager,
  parseError,
} from 'ascall'

const fetchUser = new ASCallDedumpedKeyedTimed(
  async (id: number) => {
    console.log('Fetching user', id)
    return { id, name: 'User ' + id }
  },
  {
    parseError,
    responseManager: createResponseManager<
      { id: number; name: string },
      Error
    >(),
  }
)

// First call triggers an actual request
const first = await fetchUser.call(1, 0, 1)

// Second call within 3s reuses the same response
const second = await fetchUser.call(1, 3000, 1)

setTimeout(async () => {
  // After 3 seconds, a new request is made
  const third = await fetchUser.call(1, 3000, 1)
  console.log(third !== first) // true
}, 4000)

Use case: Caches async calls for a short period to avoid unnecessary re-fetching.

🧩 Extending Base Classes

All ASCallBase variants are built on a shared base class hierarchy that you can extend to create custom logic.

For example, you can create your own Timed Retry ASCall:

import { Response, ASCallBase } from 'ascall'

class ASCallRetriable<
  TPayload,
  TError extends Error,
  TCallParams extends unknown[],
  TResponse extends Response<undefined, undefined, boolean>,
  TResponseSuccess extends Response<TPayload, undefined, true>,
  TResponseFailure extends Response<unknown, TError, false>,
> extends ASCallBase<
  TPayload,
  TError,
  TCallParams,
  TResponse,
  TResponseSuccess,
  TResponseFailure
> {
  private retries = 3

  async makeRequest(...parameters: TCallParams): Promise<TPayload> {
    let lastError: unknown

    for (let attempt = 1; attempt <= this.retries; attempt++) {
      try {
        const payload = await this.request(...parameters)
        return payload
      } catch (error) {
        lastError = error
      }
    }

    throw lastError
  }
}

This design pattern allows you to:

- Override lifecycle methods
- Inject caching, throttling, or queuing behavior
- Maintain type safety throughout

🧪 Testing & Development

Run all tests:

npm run test

Generate coverage:

npm run test -- --coverage
npm run lint:check
npm run format:check

Build the package:

npm run build

📄 License

ISC License Copyright © 2025 - saberls