isotropic-timeout 0.13.1 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +0 -0
- package/README.md +28 -15
- package/lib/timeout.js +93 -2
- package/package.json +17 -16
package/LICENSE.md
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -5,16 +5,17 @@
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
A utility that limits the amount of time a callback function will wait to be called or a promise will wait to
|
|
8
|
+
A utility that limits the amount of time a callback function will wait to be called or a promise will wait to settle.
|
|
9
9
|
|
|
10
10
|
## Why Use This?
|
|
11
11
|
|
|
12
12
|
- **Prevent Indefinite Waiting**: Set maximum wait times for asynchronous operations
|
|
13
13
|
- **Dual API Support**: Works with both callbacks and promises
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
14
|
+
- **Cancelable**: The returned function or promise has a `cancel` method supporting reasons, abort signals, and silent cancellation
|
|
15
|
+
- **Temporal Support**: The timeout accepts a number of milliseconds or a `Temporal.Duration`
|
|
16
|
+
- **Standardized Errors**: Generates the same `TimeoutError`, `AbortError`, and `edError` objects used across the isotropic ecosystem
|
|
17
|
+
- **Late Response Handling**: Option to handle responses that arrive after cancellation
|
|
18
|
+
- **Minimal Dependencies**: A convenience wrapper around `isotropic-timeout-cancel`
|
|
18
19
|
|
|
19
20
|
## Installation
|
|
20
21
|
|
|
@@ -58,9 +59,9 @@ import _timeout from 'isotropic-timeout';
|
|
|
58
59
|
import _timeout from 'isotropic-timeout';
|
|
59
60
|
|
|
60
61
|
// Wrap a promise with a timeout
|
|
61
|
-
const _fetchWithTimeout = async url {
|
|
62
|
+
const _fetchWithTimeout = async url => {
|
|
62
63
|
try {
|
|
63
|
-
const response = await
|
|
64
|
+
const response = await _timeout(
|
|
64
65
|
5000, // Timeout in milliseconds
|
|
65
66
|
fetch(url), // Promise to wrap
|
|
66
67
|
(error, result) => { // Optional late callback
|
|
@@ -83,22 +84,34 @@ const _fetchWithTimeout = async url {
|
|
|
83
84
|
|
|
84
85
|
## API
|
|
85
86
|
|
|
86
|
-
### timeout(
|
|
87
|
+
### timeout(timeout, callbackFunctionOrPromise, lateCallbackFunction)
|
|
87
88
|
|
|
88
|
-
A function that applies a
|
|
89
|
+
A function that applies a time limit to a callback function or promise.
|
|
89
90
|
|
|
90
91
|
#### Parameters
|
|
91
92
|
|
|
92
|
-
- `
|
|
93
|
+
- `timeout` (Number | Temporal.Duration | Object): The time limit, or a config object. A number is interpreted as milliseconds. A config object accepts:
|
|
94
|
+
- `timeout` (Number | Temporal.Duration, optional): The time limit. When omitted or not finite, the operation only ends by completion or cancellation.
|
|
95
|
+
- `details` (Object, optional): Included as the `details` of generated errors
|
|
96
|
+
- `signal` (AbortSignal, optional): An abort signal that cancels the operation
|
|
97
|
+
- `subject` (String, optional): The subject of generated error messages. Default: `'Operation'`
|
|
93
98
|
- `callbackFunctionOrPromise` (Function|Promise):
|
|
94
99
|
- If a function: The callback to be wrapped with timeout functionality
|
|
95
100
|
- If a promise: The promise to be wrapped with timeout functionality
|
|
96
|
-
- `lateCallbackFunction` (Function, optional): Function to be called if the original operation completes after timeout
|
|
101
|
+
- `lateCallbackFunction` (Function, optional): Function to be called if the original operation completes after cancellation (whether by timeout, signal, or a `cancel` call). Its signature depends on the mode:
|
|
102
|
+
- Callback mode: invoked with the same `this` context and arguments that the wrapped function was called with (mirroring the original callback).
|
|
103
|
+
- Promise mode: invoked as a Node-style errback, `(null, value)` if the promise resolved, or `(error)` if it rejected.
|
|
97
104
|
|
|
98
105
|
#### Returns
|
|
99
106
|
|
|
100
|
-
- If `callbackFunctionOrPromise` is a function: Returns a wrapped function that will either call the original callback or
|
|
101
|
-
- If `callbackFunctionOrPromise` is a promise: Returns a new promise that will either
|
|
107
|
+
- If `callbackFunctionOrPromise` is a function: Returns a wrapped function that will either call the original callback or deliver a cancellation error
|
|
108
|
+
- If `callbackFunctionOrPromise` is a promise: Returns a new promise that will either settle with the original promise or reject with a cancellation error
|
|
109
|
+
|
|
110
|
+
Either return value has a `cancel(config)` method accepting the same `reason`, `signal`, and `silent` options as [isotropic-cancel](https://github.com/ibi-group/isotropic-cancel), returning the wrapped function or promise for chaining. Canceling delivers the error to the main callback or rejects the promise (unless `silent`), and subsequent completions route to the `lateCallbackFunction`.
|
|
111
|
+
|
|
112
|
+
#### Errors
|
|
113
|
+
|
|
114
|
+
Generated errors follow the isotropic conventions: `TimeoutError` with message `` `${subject} timed out` `` and `details` including `duration`, `AbortError` when a signal aborts, and `CanceledError` when `cancel` is called without a reason. See [isotropic-timeout-cancel](https://github.com/ibi-group/isotropic-timeout-cancel) for details.
|
|
102
115
|
|
|
103
116
|
## Examples
|
|
104
117
|
|
|
@@ -200,8 +213,8 @@ const _queryWithTimeout = (db, query, params, timeout = 5000) => {
|
|
|
200
213
|
|
|
201
214
|
When a timeout occurs, the utility generates a standardized `TimeoutError` (an instance of `isotropic-error`) with:
|
|
202
215
|
|
|
203
|
-
- `details`: Object containing the timeout duration
|
|
204
|
-
- `message`: '
|
|
216
|
+
- `details`: Object containing the timeout duration in `duration`, merged with any configured `details`
|
|
217
|
+
- `message`: 'Task timed out' (the subject is configurable)
|
|
205
218
|
- `name`: 'TimeoutError'
|
|
206
219
|
|
|
207
220
|
This makes error handling and identification consistent across your application.
|
package/lib/timeout.js
CHANGED
|
@@ -1,2 +1,93 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import _TimeoutCancel from 'isotropic-timeout-cancel';
|
|
2
|
+
|
|
3
|
+
export default (timeout, callbackFunctionOrPromise, lateCallbackFunction) => {
|
|
4
|
+
const config = typeof timeout === 'number' || timeout instanceof Temporal.Duration ?
|
|
5
|
+
{
|
|
6
|
+
timeout
|
|
7
|
+
} :
|
|
8
|
+
timeout ?? {};
|
|
9
|
+
|
|
10
|
+
if (typeof callbackFunctionOrPromise === 'function') {
|
|
11
|
+
const cancel = _TimeoutCancel({
|
|
12
|
+
details: config.details,
|
|
13
|
+
onCancel: ({
|
|
14
|
+
error
|
|
15
|
+
}) => {
|
|
16
|
+
if (error) {
|
|
17
|
+
callbackFunctionOrPromise(error);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
signal: config.signal,
|
|
21
|
+
subject: config.subject,
|
|
22
|
+
timeout: config.timeout
|
|
23
|
+
}),
|
|
24
|
+
wrappedCallbackFunction = function (...args) {
|
|
25
|
+
if (!cancel.canceled) {
|
|
26
|
+
cancel.complete();
|
|
27
|
+
|
|
28
|
+
return Reflect.apply(callbackFunctionOrPromise, this, args);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (lateCallbackFunction) {
|
|
32
|
+
return Reflect.apply(lateCallbackFunction, this, args);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
wrappedCallbackFunction.cancel = cancelConfig => {
|
|
37
|
+
cancel.cancel(cancelConfig);
|
|
38
|
+
|
|
39
|
+
return wrappedCallbackFunction;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return wrappedCallbackFunction;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
const {
|
|
47
|
+
promise,
|
|
48
|
+
reject,
|
|
49
|
+
resolve
|
|
50
|
+
} = Promise.withResolvers(),
|
|
51
|
+
cancel = _TimeoutCancel({
|
|
52
|
+
details: config.details,
|
|
53
|
+
onCancel: ({
|
|
54
|
+
error
|
|
55
|
+
}) => {
|
|
56
|
+
if (error) {
|
|
57
|
+
reject(error);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
signal: config.signal,
|
|
61
|
+
subject: config.subject,
|
|
62
|
+
timeout: config.timeout
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
callbackFunctionOrPromise.then(value => {
|
|
66
|
+
if (cancel.canceled) {
|
|
67
|
+
if (lateCallbackFunction) {
|
|
68
|
+
lateCallbackFunction(null, value);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
cancel.complete();
|
|
72
|
+
resolve(value);
|
|
73
|
+
}
|
|
74
|
+
}, error => {
|
|
75
|
+
if (cancel.canceled) {
|
|
76
|
+
if (lateCallbackFunction) {
|
|
77
|
+
lateCallbackFunction(error);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
cancel.complete();
|
|
81
|
+
reject(error);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
promise.cancel = cancelConfig => {
|
|
86
|
+
cancel.cancel(cancelConfig);
|
|
87
|
+
|
|
88
|
+
return promise;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return promise;
|
|
92
|
+
}
|
|
93
|
+
};
|
package/package.json
CHANGED
|
@@ -2,39 +2,40 @@
|
|
|
2
2
|
"author": "Steven Olmsted <steven.olmsted@ibigroup.com>",
|
|
3
3
|
"bugs": "https://github.com/ibi-group/isotropic-timeout/issues",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"isotropic-
|
|
6
|
-
"isotropic-later": "~0.13.1"
|
|
5
|
+
"isotropic-timeout-cancel": "~0.1.0"
|
|
7
6
|
},
|
|
8
|
-
"description": "Limit the amount of time a callback function will wait to be called",
|
|
7
|
+
"description": "Limit the amount of time a callback function will wait to be called or a promise will wait to settle",
|
|
9
8
|
"devDependencies": {
|
|
10
|
-
"
|
|
11
|
-
"isotropic-
|
|
9
|
+
"isotropic-dev-dependencies": "~0.4.0",
|
|
10
|
+
"isotropic-error": "~0.14.0",
|
|
11
|
+
"isotropic-later": "~0.15.0"
|
|
12
12
|
},
|
|
13
13
|
"engines": {
|
|
14
|
-
"node": "^
|
|
15
|
-
"npm": "^
|
|
14
|
+
"node": "^26.5.0",
|
|
15
|
+
"npm": "^11.17.0"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"lib"
|
|
19
19
|
],
|
|
20
20
|
"homepage": "https://github.com/ibi-group/isotropic-timeout",
|
|
21
21
|
"keywords": [
|
|
22
|
-
"
|
|
22
|
+
"callback",
|
|
23
|
+
"isotropic",
|
|
24
|
+
"promise",
|
|
25
|
+
"timeout"
|
|
23
26
|
],
|
|
24
27
|
"license": "BSD-3-Clause",
|
|
25
28
|
"main": "lib/timeout.js",
|
|
26
29
|
"name": "isotropic-timeout",
|
|
27
30
|
"repository": "github:ibi-group/isotropic-timeout",
|
|
28
31
|
"scripts": {
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"prepare": "npm run build",
|
|
34
|
-
"prepublishOnly": "npm test --coverage",
|
|
32
|
+
"lint": "eslint eslint.config.js lib test",
|
|
33
|
+
"posttest": "c8 -c ./node_modules/isotropic-dev-dependencies/config/c8.json check-coverage",
|
|
34
|
+
"prepare": "node ./node_modules/isotropic-dev-dependencies/lib/install-git-hooks.js",
|
|
35
|
+
"prepublishOnly": "npm test",
|
|
35
36
|
"pretest": "npm run lint",
|
|
36
|
-
"test": "
|
|
37
|
+
"test": "c8 -c ./node_modules/isotropic-dev-dependencies/config/c8.json node --test"
|
|
37
38
|
},
|
|
38
39
|
"type": "module",
|
|
39
|
-
"version": "0.
|
|
40
|
+
"version": "0.15.0"
|
|
40
41
|
}
|