Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog

## Unreleased
## [4.0.0] - 2026-09-08

This is a major release because input validation and asynchronous request ordering
change observable behavior. See [Upgrading from 3.x](README.md#upgrading-from-3x)
before upgrading.

### Fixed
- Reserve interval allowance before asynchronous calls yield; recheck it after waiting.
Expand All @@ -14,6 +18,11 @@
- Async requests on one instance now run FIFO; synchronous requests can still consume capacity first.
- Fractional millisecond clock precision is retained, so remaining balances may differ slightly from earlier versions.

### Maintenance
- Refresh development dependencies within their existing declared ranges; no runtime dependencies are added.
- Build both module distributions in CI and include this changelog in the npm package.
- Exclude test files and TypeScript build caches from the published package.

## [3.0.0] - 2025-01-24
### Added
- **Dual Module Support:** Distributed as both CommonJS and ES Module, with separate `package.json` files for each format (no need for custom transformers). This improves compatibility with modern bundlers and frameworks.
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,36 @@ that can be removed each interval to comply with common API restrictions such as

yarn add limiter

## Upgrading from 3.x

Version 4 fixes concurrent accounting and waiting behavior. It keeps the existing
constructors, methods, CommonJS/ESM imports, and fractional-token support, but is
a major release because these observable behaviors change:

- Token counts and capacities must be finite, non-negative numbers no greater
than `Number.MAX_SAFE_INTEGER`. Numeric intervals must be finite and positive.
Invalid values now throw `RangeError`, or reject an asynchronous call. Validate
configuration and handle rejected `removeTokens()` promises; do not use
negative values, `NaN`, or `Infinity` as sentinels.
- Waiting `removeTokens()` calls on the same instance run in FIFO order. A large
request at the front can delay smaller requests behind it. Synchronous calls
and `fireImmediately` requests can still consume capacity ahead of the queue;
children sharing a parent do not have a global FIFO order.
- Concurrent requests now respect the interval allowance and charge a hierarchy
only once per successful removal. Workloads that previously exceeded their
configured limits may wait longer or receive an immediate rejection signal.
- Remaining balances retain fractional millisecond timing precision. Avoid exact
equality checks on fractional balances; use `tryRemoveTokens()` to check
whether a request can proceed immediately.

Zero-value conventions are unchanged: a standalone `TokenBucket` with

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document the changed zero-limit return value

For a RateLimiter configured with tokensPerInterval: 0, version 3 resolved removeTokens(0) with Infinity via the zero-size TokenBucket special case, whereas version 4 resolves it with this.tokenBucket.content, which is 0. Consumers that inspect the resolved balance can therefore change behavior on upgrade despite this statement that zero-value conventions are unchanged; either preserve the previous return value or call out this compatibility change in the migration notes.

Useful? React with 👍 / 👎.

`bucketSize: 0` is unlimited and bypasses parents; `tokensPerInterval: 0` refills
a finite bucket on every attempt. A `RateLimiter` with `tokensPerInterval: 0`
accepts only zero-token requests. These settings are not a general off switch.

See the [changelog](CHANGELOG.md) for the release history and
[Additional Notes](#additional-notes) for the full timing and queue semantics.

## Usage

A simple example allowing 150 requests per hour:
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "limiter",
"description": "A generic rate limiter for the web and node.js. Useful for API clients, web crawling, or other tasks that need to be throttled",
"version": "3.0.0",
"version": "4.0.0",
"author": "John Hurliman <jhurliman@jhurliman.org>",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
Expand All @@ -17,7 +17,10 @@
"license": "MIT",
"files": [
"dist",
"src"
"src",
"CHANGELOG.md",
"!**/*.test.*",
"!**/*.tsbuildinfo"
],
"jest": {
"moduleNameMapper": {
Expand Down
Loading