Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cbb738e
chore: pin eslint-plugin
Marsup Oct 23, 2024
2690ce5
Support AbortSignal
kanongil Nov 30, 2023
3d130e7
Make signal rethrow more web-compatible
kanongil Nov 30, 2023
189747a
Cleanup docs
kanongil Oct 23, 2024
47d9144
Add typescript typings
kanongil Oct 23, 2024
f9b17ce
Fix background() missing return option support
kanongil Oct 23, 2024
c2ee4d7
3.0.2
Marsup Oct 23, 2024
27c8b50
Narrow error type for ignore()
kanongil Aug 27, 2025
566e70c
Make more web usage friendly
kanongil Aug 28, 2025
0683e81
Use prototype manipulation to enable much faster system check
kanongil Aug 28, 2025
ec7f2bc
Merge branch 'speedup' into next
kanongil Aug 31, 2025
e6dbe83
Remove redundant isBoom() and 'boom' type
kanongil Aug 28, 2025
d6daed3
Remove redundant isError()
kanongil Aug 28, 2025
2b5c182
Enforce that "types" option is required
kanongil Aug 28, 2025
13cc0ce
Only match objects that inherit Error
kanongil Aug 28, 2025
3ee7d0c
Merge branch 'feature-abortsignal' into next
kanongil Aug 31, 2025
e791b9f
Merge branch 'typings' into next
kanongil Aug 31, 2025
42e4134
Try to narrow all types for Hoek.ignore()
kanongil Aug 31, 2025
6ef478c
Cleanup typings
kanongil Aug 31, 2025
7aacf03
Add a "strict" option
kanongil Aug 31, 2025
d46788b
Make strict mode the default
kanongil Aug 31, 2025
5f96915
Merge branch 'option-strict' into next
kanongil Aug 31, 2025
735d624
Narrow rethrow() error when strict
kanongil Aug 31, 2025
f9b5e90
Rename ignore to assert
kanongil Aug 31, 2025
8b311a7
Make narrowing work when signal option is specified
kanongil Aug 31, 2025
e3aacc7
Throw TypeError on unhandled types
kanongil Sep 1, 2025
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
40 changes: 25 additions & 15 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ async function register(address, name) {
Throws the error passed if it matches any of the specified rules where:
- `err` - the error.
- `type` - a single item or an array of items of:
- An error constructor (e.g. `SyntaxError`).
- An error constructor (e.g. `SyntaxError`) - matches error created from constructor or any subclass.
- `'system'` - matches any languange native error or node assertions.
- `'boom'` - matches [**boom**](https://github.com/hapijs/boom) errors.
- `'abort'` - matches an `AbortError`, as generated on an `AbortSignal` by `AbortController.abort()`.
- `'timeout'` - matches a `TimeoutError`, as generated by `AbortSignal.timeout(delay)`.
- an object where each property is compared with the error and must match the error property
value. All the properties in the object must match the error but do not need to include all
the error properties.
Expand All @@ -90,29 +91,23 @@ Throws the error passed if it matches any of the specified rules where:
- `override` - an error used to override `err` when `err` matches. If used with `decorate`,
the `override` object is modified.
- `return` - if `true`, the error is returned instead of thrown. Defaults to `false`.
- `strict` - if `true`, any non-`Error` `err` throws a `TypeError`. Defaults to `true`.
- `signal` - an `AbortSignal`. Throws `signal.reason` if it has already been aborted.

### `ignore(err, types, [options])`
### `assert(err, types, [options])`

The opposite action of `rethrow()`. Ignores any errors matching the specified `types`. Any error
not matching is thrown after applying the `options`.

### `background(operation, [action], [types], [options])`

Awaits for the value to resolve in the background and then apply either the `rethrow()` or `ignore()`
Awaits for the value to resolve in the background and then apply either the `rethrow()` or `assert()`
actions where:
- `operation` - a function, promise, or value that is `await`ed on inside a `try...catch` and any
error thrown processed by the `action` rule.
- `action` - one of `'rethrow'` or `'ignore'`. Defaults to `'rethrow'`.
- `types` - same as the `types` argument passed to `rethrow()` or `ignore()`. Defaults to `'system'`.
- `options` - same as the `options` argument passed to `rethrow()` or `ignore()`.

### `isBoom(err)`

Returns `true` when `err` is a [**boom**](https://github.com/hapijs/boom) error.

### `isError(err)`

Returns `true` when `err` is an error.
- `action` - one of `'rethrow'` or `'assert'`. Defaults to `'rethrow'`.
- `types` - same as the `types` argument passed to `rethrow()` or `assert()`. Defaults to `'system'`.
- `options` - same as the `options` argument passed to `rethrow()` or `assert()`.

### `isSystem(err)`

Expand All @@ -124,3 +119,18 @@ Return `true` when `err` is one of:
- `TypeError`
- `URIError`
- Node's `AssertionError`
- Hoek's `AssertError`

### `isAbort(err)`

Returns `true` when `err` is an `AbortError`, as generated by `AbortSignal.abort()`.

Note that unlike other errors, `AbortError` cannot be considered a class in itself.
The best way to create a custom `AbortError` is with `new DOMException(message, 'AbortError')`.

### `isTimeout(err)`

Returns `true` when `err` is a `TimeoutError`, as generated by `AbortSignal.timeout(delay)`.

Note that unlike other errors, `TimeoutError` cannot be considered a class in itself.
The best way to create a custom `TimeoutError` is with `new DOMException(message, 'TimeoutError')`.
17 changes: 17 additions & 0 deletions lib/assertions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

const Assert = require('assert');

const AssertError = require('@hapi/hoek/assertError');


module.exports = [

// Node

Assert.AssertionError,

// Hoek

AssertError
];
135 changes: 135 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/**
* Possible type matching rule. One of:
* - An error constructor (e.g. `SyntaxError`).
* - `'system'` - matches any language native error or node assertions.
* - `'abort'` - matches an `AbortError`, as generated on an `AbortSignal` by `AbortController.abort()`.
* - `'timeout'` - matches a `TimeoutError`, as generated by `AbortSignal.timeout(delay)`.
* - an object where each property is compared with the error and must match the error property
* value. All the properties in the object must match the error but do not need to include all
* the error properties.
*/
type TypeRule = 'system' | 'abort' | 'timeout' | ErrorConstructor | { [key: PropertyKey]: any };

type Decoration = { [key: string]: any };

type TypeMapping<T extends TypeRule> =
T extends 'abort' ? Error & { name: 'AbortError' } :
T extends 'timeout' ? Error & { name: 'TimeoutError' } :
T extends abstract new (...args: any) => Error ? InstanceType<T> :
Error;

interface BounceOptions {

/**
* An object which is assigned to the `err`, copying the properties onto the error.
*/
decorate?: { [key: string]: any } | undefined;

/**
* An error used to override `err` when `err` matches.
* If used with `decorate`, the `override` object is modified.
*/
override?: Error | undefined;

/**
* If `true`, the error is returned instead of thrown. Defaults to `false`.
*/
return?: boolean | undefined;

/**
* If `true`, any non-`Error` `err` throws a`TypeError`. Defaults to `true`.
*/
strict?: boolean | undefined;

/**
* An `AbortSignal`. Throws `signal.reason` if it has already been aborted.
*/
signal?: AbortSignal | undefined;
}

/**
* Throws the error passed if it matches any of the specified rules.
*
* @param err - the error object to test.
* @param type - a single {@link TypeRule `TypeRule`} or an array of {@link TypeRule `TypeRule`}.
* @param options - optional {@link BounceOptions settings}.
*
* @returns possibly an `Error` depending on value of the `return` and `decorate` options.
*/
export function rethrow<E extends Error, D extends Decoration>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D, override: E }): (E & D) | undefined;
export function rethrow<T extends object, D extends Decoration>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D }): (T & D) | undefined;
export function rethrow<E extends Error>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, override: E }): E | undefined;
export function rethrow<T>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true }): T | undefined;
export function rethrow(err: any, types: TypeRule | TypeRule[], options?: BounceOptions & { strict?: true | undefined }): asserts err is Error;
export function rethrow(err: any, types: TypeRule | TypeRule[], options?: BounceOptions): void;

/**
* The opposite action of {@link rethrow `rethrow()`}. Ignores any errors matching the specified `types`.
* Any error not matching is thrown after applying the `options`.
*
* @param err - the error object to test.
* @param type - a single {@link TypeRule `TypeRule`} or an array of {@link TypeRule `TypeRule`}.
* @param options - optional {@link BounceOptions settings}.
*
* @returns possibly an `Error` depending on value of the `return` and `decorate` options.
*/
export function assert<E extends Error, D extends Decoration>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D, override: E }): (E & D) | undefined;
export function assert<T extends object, D extends Decoration>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D }): (T & D) | undefined;
export function assert<E extends Error>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, override: E }): E | undefined;
export function assert<T>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true }): T | undefined;
export function assert<T extends TypeRule>(err: any, types: T, options: { return?: false | undefined }): asserts err is TypeMapping<T>;
export function assert<T extends TypeRule>(err: any, types: T): asserts err is TypeMapping<T>;
export function assert(err: any, types: TypeRule | TypeRule[], options: { return?: false | undefined }): asserts err is Error;
export function assert(err: any, types: TypeRule | TypeRule[]): asserts err is Error;
export function assert(err: any, types: TypeRule | TypeRule[], options?: BounceOptions): void;

type Action = 'rethrow' | 'assert';

/**
* Awaits for the value to resolve in the background and then apply either the {@link rethrow `rethrow()`} or {@link rethrow `assert()`} action.
*
* @param operation - a function, promise, or value that is `await`ed on inside a `try...catch`
* and any error thrown processed by the `action` rule.
* @param action - one of `'rethrow'` or `'assert'`. Defaults to `'rethrow'`.
* @param types - same as the `types` argument passed to {@link rethrow `rethrow()`} or {@link rethrow `assert()`}. Defaults to `'system'`.
* @param options - same as the {@link BounceOptions `options`} argument passed to {@link rethrow `rethrow()`} or {@link rethrow `assert()`}.
*/
export function background<E extends Error, D extends Decoration>(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions & { return: true, override: E, decorate: D }): Promise<(E & D) | undefined>;
export function background<E extends Error>(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions & { return: true, override: E }): Promise<E | undefined>;
export function background(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions & { return: true }): Promise<any>;
export function background(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions): Promise<void>;

/**
* Return `true` when `err` is one of:
* - `EvalError`
* - `RangeError`
* - `ReferenceError`
* - `SyntaxError`
* - `TypeError`
* - `URIError`
* - Node's `AssertionError`
* - Hoek's `AssertError`
*
* @param err - Object to test.
*/
export function isSystem(err: unknown): err is TypeMapping<'system'>;

/**
* Returns `true` when `err` is an `AbortError`, as generated by `AbortSignal.abort()`.
*
* Note that unlike other errors, `AbortError` cannot be considered a class in itself.
* The best way to create a custom `AbortError` is with `new DOMException(message, 'AbortError')`.
*
* @param err - Object to test.
*/
export function isAbort(err: unknown): err is TypeMapping<'abort'>;

/**
* Returns `true` when `err` is a `TimeoutError`, as generated by `AbortSignal.timeout(delay)`.
*
* Note that unlike other errors, `TimeoutError` cannot be considered a class in itself.
* The best way to create a custom `TimeoutError` is with `new DOMException(message, 'TimeoutError')`.
*
* @param err - Object to test.
*/
export function isTimeout(err: unknown): err is TypeMapping<'timeout'>;
Loading
Loading