# @abacus/throttlers

> A modern, zero-dependency throttling toolkit for JavaScript and TypeScript

A flexible collection of throttling algorithms to control the rate of asynchronous operations. Ideal for APIs, queues, animations, or any scenario requiring consistent pacing.

## ✨ Features

- Modular throttler implementations
- Smart controls via retry callback, timeout, and `AbortSignal`
- Supports burst smoothing and rate guarantees
- Written in TypeScript, compatible with ESM & CJS
- Zero external dependencies

## 📦 Installation

Using npm:

```bash
npm install @abacus/throttlers
```

Using yarn:

```bash
yarn add @abacus/throttlers
```

## 🚀 Usage

```ts
import { FixedWindowThrottler } from "@abacus/throttlers";

const throttler = new FixedWindowThrottler({ duration: 5000, limit: 5 });

for (let i = 0; i < 10; i++) {
  await throttler.wait();
  console.log("Executed:", i);
}
```

## 🧪 Throttler Interface

All throttlers inherit from the abstract `Throttler` class:

```ts
abstract class Throttler {
  tryWait(): boolean;
  wait(options?: ThrottlerWaitOptions): Promise<void>;
}
```

### `ThrottlerWaitOptions`

```ts
interface ThrottlerWaitOptions {
  signal?: AbortSignal;
  timeout?: number;
  onRetry?: (timestamp: number, throttler: Throttler) => boolean | void;
}
```

## ⏱ Throttler Implementations

### 🔁 Fixed Window

```ts
import { FixedWindowThrottler } from "@abacus/throttlers";
new FixedWindowThrottler({ duration: 1000, limit: 5 });
```

### 🔂 Sliding Window

```ts
import { SlidingWindowThrottler } from "@abacus/throttlers";
new SlidingWindowThrottler({ duration: 1000, limit: 5 });
```

### 🪙 Token Bucket

```ts
import { TokenBucketThrottler } from "@abacus/throttlers";
new TokenBucketThrottler({ capacity: 10, refillRate: 5 });
```

### 🪣 Leaky Bucket

```ts
import { LeakyBucketThrottler } from "@abacus/throttlers";
new LeakyBucketThrottler({ capacity: 10, leakRate: 5 });
```

### 📏 Linear Interval

```ts
import { LinearThrottler } from "@abacus/throttlers";
new LinearThrottler({ duration: 200 });
```

## ⛔ Abort & Timeout

```ts
const controller = new AbortController();

try {
  await throttler.wait({ signal: controller.signal, timeout: 1000 });
} catch (err) {
  if (err.name === "AbortError") {
    console.log("Cancelled");
  } else if (err.name === "TimeoutError") {
    console.log("Timed out");
  }
}
```

## 🔁 Retry Hook

```ts
await throttler.wait({
  onRetry: (ts, throttler) => {
    console.log(`Delaying until ${ts.toFixed(2)}ms`);
    return true; // Return false to cancel
  },
});
```

## 🧱 Compatibility

- ✅ TypeScript & JavaScript
- ✅ Node.js v14+
- ✅ ESM & CommonJS
- ✅ Works in modern browsers (with `performance.now()`)

## 📄 License

MIT

## 📫 Feedback or Contributions?

Open issues, submit PRs, or reach out — we’d love your input!
