Skip to content

Commit

Permalink
Require Node.js 16
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Aug 24, 2023
1 parent 95a3a4a commit b38fd69
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 76 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ jobs:
fail-fast: false
matrix:
node-version:
- 20
- 18
- 16
- 14
- 12
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
16 changes: 6 additions & 10 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {OperationOptions} from 'retry';
import {type OperationOptions} from 'retry';

export class AbortError extends Error {
readonly name: 'AbortError';
Expand All @@ -12,12 +12,12 @@ export class AbortError extends Error {
constructor(message: string | Error);
}

export interface FailedAttemptError extends Error {
export type FailedAttemptError = {
readonly attemptNumber: number;
readonly retriesLeft: number;
}
} & Error;

export interface Options extends OperationOptions {
export type Options = {
/**
Callback invoked on each retry. Receives the error thrown by `input` as the first argument with properties `attemptNumber` and `retriesLeft` which indicate the current attempt number and the number of attempts left, respectively.
Expand All @@ -44,18 +44,14 @@ export interface Options extends OperationOptions {
/**
You can abort retrying using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
When `AbortController.abort(reason)` is called, the promise will be rejected with `reason` as the error message.
*Requires Node.js 16 or later.*
```
import pRetry from 'p-retry';
const run = async () => { … };
const controller = new AbortController();
cancelButton.addEventListener('click', () => {
controller.abort('User clicked cancel button');
controller.abort(new Error('User clicked cancel button'));
});
try {
Expand All @@ -67,7 +63,7 @@ export interface Options extends OperationOptions {
```
*/
readonly signal?: AbortSignal;
}
} & OperationOptions;

/**
Returns a `Promise` that is fulfilled when calling `input` returns a fulfilled promise. If calling `input` returns a rejected promise, `input` is called again until the max retries are reached, it then rejects with the last rejection reason.
Expand Down
2 changes: 1 addition & 1 deletion index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expectType} from 'tsd';
import pRetry, {AbortError, FailedAttemptError} from './index.js';
import pRetry, {AbortError, type FailedAttemptError} from './index.js';

expectType<Promise<number>>(
pRetry(async count => {
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"type": "module",
"exports": "./index.js",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": ">=16.17"
},
"scripts": {
"test": "xo && ava && tsd"
Expand Down Expand Up @@ -42,13 +42,13 @@
"bluebird"
],
"dependencies": {
"@types/retry": "0.12.1",
"@types/retry": "0.12.2",
"retry": "^0.13.1"
},
"devDependencies": {
"ava": "^4.1.0",
"delay": "^5.0.0",
"tsd": "^0.19.1",
"xo": "^0.48.0"
"ava": "^5.3.1",
"delay": "^6.0.0",
"tsd": "^0.28.1",
"xo": "^0.56.0"
}
}
6 changes: 1 addition & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,18 +105,14 @@ Type: [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSign

You can abort retrying using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).

When `AbortController.abort(reason)` is called, the promise will be rejected with `reason` if it's an instance of `Error`, or a `DOMException` with `reason` as its message otherwise. If no reason is provided, the promise will reject with a `DOMException`.

*Requires Node.js 16 or later.*

```js
import pRetry from 'p-retry';

const run = async () => { … };
const controller = new AbortController();

cancelButton.addEventListener('click', () => {
controller.abort('User clicked cancel button');
controller.abort(new Error('User clicked cancel button'));
});

try {
Expand Down
116 changes: 66 additions & 50 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,30 @@ test('onFailedAttempt is called expected number of times', async t => {
t.is(error.attemptNumber, ++attemptNumber);

switch (index) {
case 1:
case 1: {
t.is(error.retriesLeft, retries);
break;
case 2:
}

case 2: {
t.is(error.retriesLeft, 4);
break;
case 3:
}

case 3: {
t.is(error.retriesLeft, 3);
break;
case 4:
}

case 4: {
t.is(error.retriesLeft, 2);
break;
default:
}

default: {
t.fail('onFailedAttempt was called more than 4 times');
break;
}
}
},
retries,
Expand Down Expand Up @@ -137,21 +146,30 @@ test('onFailedAttempt is called before last rejection', async t => {
t.is(error.attemptNumber, ++j);

switch (i) {
case 1:
case 1: {
t.is(error.retriesLeft, r);
break;
case 2:
}

case 2: {
t.is(error.retriesLeft, 2);
break;
case 3:
}

case 3: {
t.is(error.retriesLeft, 1);
break;
case 4:
}

case 4: {
t.is(error.retriesLeft, 0);
break;
default:
}

default: {
t.fail('onFailedAttempt was called more than 4 times');
break;
}
}
},
retries: r,
Expand Down Expand Up @@ -212,52 +230,50 @@ test('throws useful error message when non-error is thrown', async t => {
});
});

if (globalThis.AbortController !== undefined) {
test('aborts with an AbortSignal', async t => {
t.plan(2);

let index = 0;
const controller = new AbortController();
test('aborts with an AbortSignal', async t => {
t.plan(2);

await t.throwsAsync(pRetry(async attemptNumber => {
await delay(40);
index++;
if (attemptNumber === 3) {
controller.abort();
}
let index = 0;
const controller = new AbortController();

throw fixtureError;
}, {
signal: controller.signal,
}), {
instanceOf: globalThis.DOMException === undefined ? Error : DOMException,
/// message: 'The operation was aborted.',
});
await t.throwsAsync(pRetry(async attemptNumber => {
await delay(40);
index++;
if (attemptNumber === 3) {
controller.abort();
}

t.is(index, 3);
throw fixtureError;
}, {
signal: controller.signal,
}), {
// TODO: Make this only `instanceOf: DOMException` when targeting Node.js 18.
instanceOf: globalThis.DOMException === undefined ? Error : DOMException,
});

test('preserves the abort reason', async t => {
t.plan(2);

let index = 0;
const controller = new AbortController();
t.is(index, 3);
});

await t.throwsAsync(pRetry(async attemptNumber => {
await delay(40);
index++;
if (attemptNumber === 3) {
controller.abort(fixtureError);
return;
}
test('preserves the abort reason', async t => {
t.plan(2);

throw fixtureError;
}, {
signal: controller.signal,
}), {
is: fixtureError,
});
let index = 0;
const controller = new AbortController();

t.is(index, 3);
await t.throwsAsync(pRetry(async attemptNumber => {
await delay(40);
index++;
if (attemptNumber === 3) {
controller.abort(fixtureError);
return;
}

throw fixtureError;
}, {
signal: controller.signal,
}), {
is: fixtureError,
});
}

t.is(index, 3);
});

0 comments on commit b38fd69

Please sign in to comment.