saborter 1.2.0 → 1.3.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/dist/index.cjs.js +70 -20
- package/dist/index.d.ts +99 -3
- package/dist/index.es.js +70 -20
- package/package.json +29 -4
- package/readme.md +169 -76
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.es.js.map +0 -1
package/dist/index.cjs.js
CHANGED
|
@@ -5,41 +5,91 @@ const ABORT_ERROR_WITHOUT_REASON_MESSAGE = "signal is aborted without reason";
|
|
|
5
5
|
const ABORT_ERROR_NAME = "AbortError";
|
|
6
6
|
const ERROR_CAUSE_PATH_NAME = "cause.name";
|
|
7
7
|
const ERROR_CAUSE_PATH_MESSAGE = "cause.message";
|
|
8
|
-
const ABORT_ERROR_MESSAGES = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
);
|
|
8
|
+
const ABORT_ERROR_MESSAGES = [ABORT_ERROR_MESSAGE, ABORT_ERROR_WITHOUT_REASON_MESSAGE];
|
|
9
|
+
class AbortError extends Error {
|
|
10
|
+
constructor(message, options) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = 20;
|
|
13
|
+
this.timestamp = Date.now();
|
|
14
|
+
this.name = ABORT_ERROR_NAME;
|
|
15
|
+
this.type = options?.type || "aborted";
|
|
16
|
+
this.reason = options?.reason;
|
|
17
|
+
this.signal = options?.signal;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const get = (object, path) => path.split(".").reduce((acc, key) => acc && acc[key], object);
|
|
21
|
+
const checkErrorCause = (error) => get(error, ERROR_CAUSE_PATH_NAME) === ABORT_ERROR_NAME || ABORT_ERROR_MESSAGES.includes(get(error, ERROR_CAUSE_PATH_MESSAGE));
|
|
22
|
+
const isError = (error) => error instanceof AbortError || "name" in error && error.name === ABORT_ERROR_NAME || ABORT_ERROR_MESSAGES.includes(error?.message ?? "") || checkErrorCause(error);
|
|
23
|
+
const getCauseMessage = (error) => {
|
|
24
|
+
return get(error, ERROR_CAUSE_PATH_MESSAGE);
|
|
25
|
+
};
|
|
26
|
+
class EventListener {
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.listeners = {
|
|
29
|
+
aborted: /* @__PURE__ */ new Set(),
|
|
30
|
+
cancelled: /* @__PURE__ */ new Set()
|
|
31
|
+
};
|
|
32
|
+
this.getListenersByType = (type) => {
|
|
33
|
+
return this.listeners[type];
|
|
34
|
+
};
|
|
35
|
+
this.addEventListener = (type, listener) => {
|
|
36
|
+
this.getListenersByType(type).add(listener);
|
|
37
|
+
return () => this.removeEventListener(type, listener);
|
|
38
|
+
};
|
|
39
|
+
this.removeEventListener = (type, listener) => {
|
|
40
|
+
this.getListenersByType(type).delete(listener);
|
|
41
|
+
};
|
|
42
|
+
this.dispatchEvent = (type, event) => {
|
|
43
|
+
if (type === "aborted" || type === "cancelled") {
|
|
44
|
+
this.onabort?.(event);
|
|
45
|
+
}
|
|
46
|
+
this.getListenersByType(type).forEach((listener) => listener(event));
|
|
47
|
+
};
|
|
48
|
+
this.onabort = options?.onAbort;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
21
51
|
const _Aborter = class _Aborter {
|
|
22
|
-
constructor() {
|
|
52
|
+
constructor(options) {
|
|
23
53
|
this.abortController = new AbortController();
|
|
24
54
|
this.try = (request, { isErrorNativeBehavior = false } = {}) => {
|
|
25
55
|
let promise = new Promise((resolve, reject) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
56
|
+
const cancelledAbortError = new AbortError("cancellation of the previous AbortController", {
|
|
57
|
+
type: "cancelled",
|
|
58
|
+
signal: this.signal
|
|
59
|
+
});
|
|
60
|
+
this.listeners.dispatchEvent("cancelled", cancelledAbortError);
|
|
61
|
+
const { signal } = this.abortWithRecovery(cancelledAbortError);
|
|
29
62
|
request(signal).then(resolve).catch((err) => {
|
|
30
63
|
const error = {
|
|
31
64
|
...err,
|
|
32
|
-
message: err?.message ||
|
|
65
|
+
message: err?.message || getCauseMessage(err) || ""
|
|
33
66
|
};
|
|
34
67
|
if (isErrorNativeBehavior || !_Aborter.isError(err)) {
|
|
35
68
|
return reject(error);
|
|
36
69
|
}
|
|
70
|
+
if (error?.type !== "cancelled") {
|
|
71
|
+
this.listeners.dispatchEvent(
|
|
72
|
+
"aborted",
|
|
73
|
+
new AbortError(error.message, {
|
|
74
|
+
signal: this.signal,
|
|
75
|
+
reason: get(error, "reason") || this.signal.reason
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
}
|
|
37
79
|
promise = null;
|
|
38
80
|
});
|
|
39
81
|
});
|
|
40
82
|
return promise;
|
|
41
83
|
};
|
|
42
|
-
this.abort = (reason) =>
|
|
84
|
+
this.abort = (reason) => {
|
|
85
|
+
this.abortController.abort(reason);
|
|
86
|
+
};
|
|
87
|
+
this.abortWithRecovery = (reason) => {
|
|
88
|
+
this.abort(reason);
|
|
89
|
+
this.abortController = new AbortController();
|
|
90
|
+
return this.abortController;
|
|
91
|
+
};
|
|
92
|
+
this.listeners = new EventListener({ onAbort: options?.onAbort });
|
|
43
93
|
}
|
|
44
94
|
/**
|
|
45
95
|
* Returns the AbortSignal object associated with this object.
|
|
@@ -51,5 +101,5 @@ const _Aborter = class _Aborter {
|
|
|
51
101
|
_Aborter.errorName = ABORT_ERROR_NAME;
|
|
52
102
|
_Aborter.isError = isError;
|
|
53
103
|
let Aborter = _Aborter;
|
|
104
|
+
exports.AbortError = AbortError;
|
|
54
105
|
exports.Aborter = Aborter;
|
|
55
|
-
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
export declare class Aborter {
|
|
2
2
|
protected abortController: AbortController;
|
|
3
|
+
/**
|
|
4
|
+
* Returns an `EventListener` instance to listen for `Aborter` events.
|
|
5
|
+
*/
|
|
6
|
+
listeners: EventListener_2;
|
|
7
|
+
constructor(options?: Types_2.AborterOptions);
|
|
3
8
|
/**
|
|
4
9
|
* The name of the error instance thrown by the AbortSignal.
|
|
5
10
|
* @readonly
|
|
11
|
+
* @deprecated use AbortError.name
|
|
6
12
|
*/
|
|
7
13
|
static readonly errorName = "AbortError";
|
|
8
14
|
/**
|
|
9
15
|
* Method of checking whether an error is an error AbortError.
|
|
10
16
|
* @returns boolean
|
|
11
17
|
*/
|
|
12
|
-
static isError: (error:
|
|
18
|
+
static isError: (error: any) => error is Error;
|
|
13
19
|
/**
|
|
14
20
|
* Returns the AbortSignal object associated with this object.
|
|
15
21
|
*/
|
|
@@ -20,15 +26,92 @@ export declare class Aborter {
|
|
|
20
26
|
* @param options an object that receives a set of settings for performing a request attempt
|
|
21
27
|
* @returns Promise
|
|
22
28
|
*/
|
|
23
|
-
try: <R>(request:
|
|
29
|
+
try: <R>(request: Types_2.AbortRequest<R>, { isErrorNativeBehavior }?: Types_2.FnTryOptions) => Promise<R>;
|
|
24
30
|
/**
|
|
25
31
|
* Calling this method sets the AbortSignal flag of this object and signals all observers that the associated action should be aborted.
|
|
26
32
|
*/
|
|
27
33
|
abort: (reason?: any) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Calling this method sets the AbortSignal flag of this object and signals all observers that the associated action should be aborted.
|
|
36
|
+
* After aborting, it restores the AbortSignal, resetting the isAborted property, and interaction with the signal property becomes available again.
|
|
37
|
+
*/
|
|
38
|
+
abortWithRecovery: (reason?: any) => AbortController;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare interface AborterOptions extends Pick<EventListenerOptions_2, 'onAbort'> {
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export declare class AbortError extends Error {
|
|
45
|
+
/**
|
|
46
|
+
* Interrupt error code.
|
|
47
|
+
* @readonly
|
|
48
|
+
*/
|
|
49
|
+
readonly code: number;
|
|
50
|
+
/**
|
|
51
|
+
* Interrupt type 'cancelled' | 'aborted'.
|
|
52
|
+
* @default `aborted`
|
|
53
|
+
*/
|
|
54
|
+
type: AbortErrorOptions['type'];
|
|
55
|
+
/**
|
|
56
|
+
*The timestamp in milliseconds when the error was created.
|
|
57
|
+
@readonly
|
|
58
|
+
@returns Date.now();
|
|
59
|
+
*/
|
|
60
|
+
readonly timestamp: number;
|
|
61
|
+
/**
|
|
62
|
+
* Additional reason or data associated with the interrupt.
|
|
63
|
+
*/
|
|
64
|
+
reason?: any;
|
|
65
|
+
/**
|
|
66
|
+
* AbortSignal that was just interrupted.
|
|
67
|
+
*/
|
|
68
|
+
signal?: AbortSignal;
|
|
69
|
+
constructor(message: string, options?: AbortErrorOptions);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
declare interface AbortErrorOptions {
|
|
73
|
+
type?: 'cancelled' | 'aborted';
|
|
74
|
+
reason?: any;
|
|
75
|
+
signal?: AbortSignal;
|
|
28
76
|
}
|
|
29
77
|
|
|
30
78
|
declare type AbortRequest<T> = (signal: AbortSignal) => Promise<T>;
|
|
31
79
|
|
|
80
|
+
declare type EventCallback<T extends EventListenerType> = EventMap[T] extends undefined ? () => void : (event: EventMap[T]) => void;
|
|
81
|
+
|
|
82
|
+
declare class EventListener_2 {
|
|
83
|
+
private listeners;
|
|
84
|
+
/**
|
|
85
|
+
* Method called when an Aborter request is cancelled
|
|
86
|
+
*/
|
|
87
|
+
onabort?: Types.OnAbortCallback;
|
|
88
|
+
constructor(options?: Types.EventListenerOptions);
|
|
89
|
+
private getListenersByType;
|
|
90
|
+
/**
|
|
91
|
+
* Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.
|
|
92
|
+
*/
|
|
93
|
+
addEventListener: <T extends Types.EventListenerType, L extends Types.EventCallback<T>>(type: T, listener: L) => VoidFunction;
|
|
94
|
+
/**
|
|
95
|
+
* Removes the event listener in target's event listener list with the same type and callback.
|
|
96
|
+
*/
|
|
97
|
+
removeEventListener: <T extends Types.EventListenerType, L extends Types.EventCallback<T>>(type: T, listener: L) => void;
|
|
98
|
+
/**
|
|
99
|
+
* Dispatches a synthetic event event to target
|
|
100
|
+
*/
|
|
101
|
+
dispatchEvent: <T extends Types.EventListenerType, E extends Types.EventMap[T]>(type: T, event: E) => void;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
declare interface EventListenerOptions_2 {
|
|
105
|
+
onAbort?: OnAbortCallback;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
declare type EventListenerType = keyof EventMap;
|
|
109
|
+
|
|
110
|
+
declare interface EventMap {
|
|
111
|
+
aborted: AbortError;
|
|
112
|
+
cancelled: AbortError;
|
|
113
|
+
}
|
|
114
|
+
|
|
32
115
|
declare interface FnTryOptions {
|
|
33
116
|
/**
|
|
34
117
|
* Returns the ability to catch a canceled request error in a catch block.
|
|
@@ -37,10 +120,23 @@ declare interface FnTryOptions {
|
|
|
37
120
|
isErrorNativeBehavior?: boolean;
|
|
38
121
|
}
|
|
39
122
|
|
|
123
|
+
declare type OnAbortCallback = (error: AbortError) => void;
|
|
124
|
+
|
|
40
125
|
declare namespace Types {
|
|
126
|
+
export {
|
|
127
|
+
EventMap,
|
|
128
|
+
EventListenerType,
|
|
129
|
+
EventCallback,
|
|
130
|
+
OnAbortCallback,
|
|
131
|
+
EventListenerOptions_2 as EventListenerOptions
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
declare namespace Types_2 {
|
|
41
136
|
export {
|
|
42
137
|
AbortRequest,
|
|
43
|
-
FnTryOptions
|
|
138
|
+
FnTryOptions,
|
|
139
|
+
AborterOptions
|
|
44
140
|
}
|
|
45
141
|
}
|
|
46
142
|
|
package/dist/index.es.js
CHANGED
|
@@ -3,41 +3,91 @@ const ABORT_ERROR_WITHOUT_REASON_MESSAGE = "signal is aborted without reason";
|
|
|
3
3
|
const ABORT_ERROR_NAME = "AbortError";
|
|
4
4
|
const ERROR_CAUSE_PATH_NAME = "cause.name";
|
|
5
5
|
const ERROR_CAUSE_PATH_MESSAGE = "cause.message";
|
|
6
|
-
const ABORT_ERROR_MESSAGES = [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
);
|
|
6
|
+
const ABORT_ERROR_MESSAGES = [ABORT_ERROR_MESSAGE, ABORT_ERROR_WITHOUT_REASON_MESSAGE];
|
|
7
|
+
class AbortError extends Error {
|
|
8
|
+
constructor(message, options) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = 20;
|
|
11
|
+
this.timestamp = Date.now();
|
|
12
|
+
this.name = ABORT_ERROR_NAME;
|
|
13
|
+
this.type = options?.type || "aborted";
|
|
14
|
+
this.reason = options?.reason;
|
|
15
|
+
this.signal = options?.signal;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const get = (object, path) => path.split(".").reduce((acc, key) => acc && acc[key], object);
|
|
19
|
+
const checkErrorCause = (error) => get(error, ERROR_CAUSE_PATH_NAME) === ABORT_ERROR_NAME || ABORT_ERROR_MESSAGES.includes(get(error, ERROR_CAUSE_PATH_MESSAGE));
|
|
20
|
+
const isError = (error) => error instanceof AbortError || "name" in error && error.name === ABORT_ERROR_NAME || ABORT_ERROR_MESSAGES.includes(error?.message ?? "") || checkErrorCause(error);
|
|
21
|
+
const getCauseMessage = (error) => {
|
|
22
|
+
return get(error, ERROR_CAUSE_PATH_MESSAGE);
|
|
23
|
+
};
|
|
24
|
+
class EventListener {
|
|
25
|
+
constructor(options) {
|
|
26
|
+
this.listeners = {
|
|
27
|
+
aborted: /* @__PURE__ */ new Set(),
|
|
28
|
+
cancelled: /* @__PURE__ */ new Set()
|
|
29
|
+
};
|
|
30
|
+
this.getListenersByType = (type) => {
|
|
31
|
+
return this.listeners[type];
|
|
32
|
+
};
|
|
33
|
+
this.addEventListener = (type, listener) => {
|
|
34
|
+
this.getListenersByType(type).add(listener);
|
|
35
|
+
return () => this.removeEventListener(type, listener);
|
|
36
|
+
};
|
|
37
|
+
this.removeEventListener = (type, listener) => {
|
|
38
|
+
this.getListenersByType(type).delete(listener);
|
|
39
|
+
};
|
|
40
|
+
this.dispatchEvent = (type, event) => {
|
|
41
|
+
if (type === "aborted" || type === "cancelled") {
|
|
42
|
+
this.onabort?.(event);
|
|
43
|
+
}
|
|
44
|
+
this.getListenersByType(type).forEach((listener) => listener(event));
|
|
45
|
+
};
|
|
46
|
+
this.onabort = options?.onAbort;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
19
49
|
const _Aborter = class _Aborter {
|
|
20
|
-
constructor() {
|
|
50
|
+
constructor(options) {
|
|
21
51
|
this.abortController = new AbortController();
|
|
22
52
|
this.try = (request, { isErrorNativeBehavior = false } = {}) => {
|
|
23
53
|
let promise = new Promise((resolve, reject) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
54
|
+
const cancelledAbortError = new AbortError("cancellation of the previous AbortController", {
|
|
55
|
+
type: "cancelled",
|
|
56
|
+
signal: this.signal
|
|
57
|
+
});
|
|
58
|
+
this.listeners.dispatchEvent("cancelled", cancelledAbortError);
|
|
59
|
+
const { signal } = this.abortWithRecovery(cancelledAbortError);
|
|
27
60
|
request(signal).then(resolve).catch((err) => {
|
|
28
61
|
const error = {
|
|
29
62
|
...err,
|
|
30
|
-
message: err?.message ||
|
|
63
|
+
message: err?.message || getCauseMessage(err) || ""
|
|
31
64
|
};
|
|
32
65
|
if (isErrorNativeBehavior || !_Aborter.isError(err)) {
|
|
33
66
|
return reject(error);
|
|
34
67
|
}
|
|
68
|
+
if (error?.type !== "cancelled") {
|
|
69
|
+
this.listeners.dispatchEvent(
|
|
70
|
+
"aborted",
|
|
71
|
+
new AbortError(error.message, {
|
|
72
|
+
signal: this.signal,
|
|
73
|
+
reason: get(error, "reason") || this.signal.reason
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
}
|
|
35
77
|
promise = null;
|
|
36
78
|
});
|
|
37
79
|
});
|
|
38
80
|
return promise;
|
|
39
81
|
};
|
|
40
|
-
this.abort = (reason) =>
|
|
82
|
+
this.abort = (reason) => {
|
|
83
|
+
this.abortController.abort(reason);
|
|
84
|
+
};
|
|
85
|
+
this.abortWithRecovery = (reason) => {
|
|
86
|
+
this.abort(reason);
|
|
87
|
+
this.abortController = new AbortController();
|
|
88
|
+
return this.abortController;
|
|
89
|
+
};
|
|
90
|
+
this.listeners = new EventListener({ onAbort: options?.onAbort });
|
|
41
91
|
}
|
|
42
92
|
/**
|
|
43
93
|
* Returns the AbortSignal object associated with this object.
|
|
@@ -50,6 +100,6 @@ _Aborter.errorName = ABORT_ERROR_NAME;
|
|
|
50
100
|
_Aborter.isError = isError;
|
|
51
101
|
let Aborter = _Aborter;
|
|
52
102
|
export {
|
|
103
|
+
AbortError,
|
|
53
104
|
Aborter
|
|
54
105
|
};
|
|
55
|
-
//# sourceMappingURL=index.es.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "saborter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A simple and efficient library for canceling asynchronous requests using AbortController",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.es.js",
|
|
@@ -37,23 +37,48 @@
|
|
|
37
37
|
],
|
|
38
38
|
"scripts": {
|
|
39
39
|
"prepublishOnly": "npm run build",
|
|
40
|
-
"build": "tsc && vite build",
|
|
41
|
-
"
|
|
40
|
+
"build": "npm run clean:dist && tsc && vite build",
|
|
41
|
+
"clean:dist": "rimraf dist",
|
|
42
|
+
"typecheck": "tsc --pretty --noEmit --skipLibCheck",
|
|
43
|
+
"verify:prettier": "npx prettier . --check",
|
|
44
|
+
"verify:eslint": "npx eslint \"./**/*.{js,jsx,ts,tsx}\" --max-warnings=0",
|
|
45
|
+
"verify": "npm run typecheck && npm run verify:prettier && npm run verify:eslint",
|
|
46
|
+
"fix:eslint": "npx eslint \"./**/*.{js,jsx,ts,tsx}\" --fix",
|
|
47
|
+
"fix:prettier": "npx prettier --write .",
|
|
48
|
+
"fix": "npm run fix:eslint && npm run fix:prettier",
|
|
49
|
+
"test": "jest --colors --coverage test --passWithNoTests",
|
|
50
|
+
"prepare": "husky"
|
|
42
51
|
},
|
|
43
52
|
"devDependencies": {
|
|
44
53
|
"@types/jest": "^30.0.0",
|
|
45
54
|
"@types/node": "^25.0.3",
|
|
46
55
|
"@typescript-eslint/eslint-plugin": "^8.50.1",
|
|
47
56
|
"@typescript-eslint/parser": "^8.50.1",
|
|
48
|
-
"eslint": "^
|
|
57
|
+
"eslint": "^8.11.0",
|
|
58
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
59
|
+
"eslint-config-prettier": "^10.1.8",
|
|
60
|
+
"eslint-plugin-import": "^2.32.0",
|
|
61
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
62
|
+
"husky": "^9.1.7",
|
|
49
63
|
"jest": "^30.2.0",
|
|
50
64
|
"jest-environment-jsdom": "^30.2.0",
|
|
65
|
+
"lint-staged": "^16.2.7",
|
|
51
66
|
"prettier": "^3.7.4",
|
|
67
|
+
"rimraf": "^6.1.2",
|
|
52
68
|
"ts-jest": "^29.4.6",
|
|
53
69
|
"ts-node": "^10.9.2",
|
|
54
70
|
"typescript": "^5.9.3",
|
|
55
71
|
"vite": "^7.3.0",
|
|
72
|
+
"vite-plugin-circular-dependency": "^0.5.0",
|
|
56
73
|
"vite-plugin-clean": "^2.0.1",
|
|
57
74
|
"vite-plugin-dts": "^4.5.4"
|
|
75
|
+
},
|
|
76
|
+
"lint-staged": {
|
|
77
|
+
"*.{js,jsx,ts,tsx}": [
|
|
78
|
+
"npm run fix:prettier"
|
|
79
|
+
],
|
|
80
|
+
"*.{json,md}": [
|
|
81
|
+
"npm run fix:prettier"
|
|
82
|
+
]
|
|
58
83
|
}
|
|
59
84
|
}
|
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/saborter)
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
[](https://github.com/TENSIILE/saborter)
|
|
@@ -28,14 +28,10 @@ const aborter = new Aborter();
|
|
|
28
28
|
// Use for the request
|
|
29
29
|
async function fetchData() {
|
|
30
30
|
try {
|
|
31
|
-
const result = await aborter.try(signal => fetch('/api/data', { signal })
|
|
31
|
+
const result = await aborter.try((signal) => fetch('/api/data', { signal }));
|
|
32
32
|
console.log('Data received:', result);
|
|
33
33
|
} catch (error) {
|
|
34
|
-
|
|
35
|
-
console.log('The request was canceled');
|
|
36
|
-
} else {
|
|
37
|
-
console.error('Request error:', error);
|
|
38
|
-
}
|
|
34
|
+
console.error('Request error:', error);
|
|
39
35
|
}
|
|
40
36
|
}
|
|
41
37
|
```
|
|
@@ -50,7 +46,7 @@ The `Aborter` class allows you to easily cancel ongoing requests:
|
|
|
50
46
|
const aborter = new Aborter();
|
|
51
47
|
|
|
52
48
|
// Start a long-running request
|
|
53
|
-
const longRequest = aborter.try(signal => fetch('/api/long-task', { signal }));
|
|
49
|
+
const longRequest = aborter.try((signal) => fetch('/api/long-task', { signal }));
|
|
54
50
|
|
|
55
51
|
// Cancel the request after 2 seconds
|
|
56
52
|
setTimeout(() => {
|
|
@@ -61,13 +57,13 @@ setTimeout(() => {
|
|
|
61
57
|
|
|
62
58
|
### 2. Automatically canceling previous requests
|
|
63
59
|
|
|
64
|
-
Each time
|
|
60
|
+
Each time `try()` is called, the previous request is automatically canceled:
|
|
65
61
|
|
|
66
62
|
```javascript
|
|
67
63
|
// When searching with autocomplete
|
|
68
64
|
async function handleSearch(query) {
|
|
69
65
|
// The previous request is automatically canceled
|
|
70
|
-
const results = await aborter.try(signal => fetch(`/api/search?q=${query}`, { signal }));
|
|
66
|
+
const results = await aborter.try((signal) => fetch(`/api/search?q=${query}`, { signal }));
|
|
71
67
|
return results;
|
|
72
68
|
}
|
|
73
69
|
|
|
@@ -88,12 +84,12 @@ const dataAborter = new Aborter();
|
|
|
88
84
|
|
|
89
85
|
// Manage user requests separately
|
|
90
86
|
async function fetchUser(id) {
|
|
91
|
-
return userAborter.try(signal => fetch(`/api/users/${id}`, { signal }));
|
|
87
|
+
return userAborter.try((signal) => fetch(`/api/users/${id}`, { signal }));
|
|
92
88
|
}
|
|
93
89
|
|
|
94
90
|
// And manage data separately
|
|
95
91
|
async function fetchData(params) {
|
|
96
|
-
return dataAborter.try(signal => fetch('/api/data', { signal, ...params }));
|
|
92
|
+
return dataAborter.try((signal) => fetch('/api/data', { signal, ...params }));
|
|
97
93
|
}
|
|
98
94
|
|
|
99
95
|
// Cancel only user requests
|
|
@@ -106,11 +102,28 @@ function cancelUserRequests() {
|
|
|
106
102
|
|
|
107
103
|
### Constructor
|
|
108
104
|
|
|
109
|
-
```
|
|
110
|
-
new Aborter();
|
|
105
|
+
```typescript
|
|
106
|
+
const aborter = new Aborter(options?: AborterOptions);
|
|
111
107
|
```
|
|
112
108
|
|
|
113
|
-
|
|
109
|
+
### Constructor Parameters
|
|
110
|
+
|
|
111
|
+
| Parameter | Type | Description | Required |
|
|
112
|
+
| --------- | ---------------- | ----------------------------- | -------- |
|
|
113
|
+
| `options` | `AborterOptions` | Aborter configuration options | No |
|
|
114
|
+
|
|
115
|
+
**AborterOptions:**
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
{
|
|
119
|
+
/*
|
|
120
|
+
Callback function for abort events.
|
|
121
|
+
Associated with EventListener.onabort.
|
|
122
|
+
It can be overridden via `aborter.listeners.onabort`
|
|
123
|
+
*/
|
|
124
|
+
onAbort?: OnAbortCallback;
|
|
125
|
+
}
|
|
126
|
+
```
|
|
114
127
|
|
|
115
128
|
### Properties
|
|
116
129
|
|
|
@@ -123,10 +136,32 @@ const aborter = new Aborter();
|
|
|
123
136
|
|
|
124
137
|
// Using signal in the request
|
|
125
138
|
fetch('/api/data', {
|
|
126
|
-
signal: aborter.signal
|
|
139
|
+
signal: aborter.signal
|
|
127
140
|
});
|
|
128
141
|
```
|
|
129
142
|
|
|
143
|
+
`listeners`
|
|
144
|
+
|
|
145
|
+
Returns an `EventListener` object to listen for `Aborter` events.
|
|
146
|
+
|
|
147
|
+
[Detailed documentation here](./docs/event-listener.md)
|
|
148
|
+
|
|
149
|
+
⚠️ `static errorName`
|
|
150
|
+
|
|
151
|
+
⚠️ `[DEPRECATED]:` Use `AbortError.name`.
|
|
152
|
+
|
|
153
|
+
Name of the `AbortError` error instance thrown by AbortSignal.
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
const result = await aborter
|
|
157
|
+
.try((signal) => fetch('/api/data', { signal }), { isErrorNativeBehavior: true })
|
|
158
|
+
.catch((error) => {
|
|
159
|
+
if (error.name === AbortError.name) {
|
|
160
|
+
console.log('Canceled');
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
130
165
|
### Methods
|
|
131
166
|
|
|
132
167
|
`try(request, options?)`
|
|
@@ -137,7 +172,7 @@ Executes an asynchronous request with the ability to cancel.
|
|
|
137
172
|
|
|
138
173
|
- `request: (signal: AbortSignal) => Promise<T>` - the function that fulfills the request
|
|
139
174
|
- `options?: Object` (optional)
|
|
140
|
-
- `isErrorNativeBehavior
|
|
175
|
+
- `isErrorNativeBehavior?: boolean` - a flag for controlling error handling. Default is `false`
|
|
141
176
|
|
|
142
177
|
**Returns:** `Promise<T>`
|
|
143
178
|
|
|
@@ -145,12 +180,12 @@ Executes an asynchronous request with the ability to cancel.
|
|
|
145
180
|
|
|
146
181
|
```javascript
|
|
147
182
|
// Simple request
|
|
148
|
-
const result = await aborter.try(signal => {
|
|
149
|
-
return fetch('/api/data', { signal }).then(response => response.json());
|
|
183
|
+
const result = await aborter.try((signal) => {
|
|
184
|
+
return fetch('/api/data', { signal }).then((response) => response.json());
|
|
150
185
|
});
|
|
151
186
|
|
|
152
187
|
// With custom request logic
|
|
153
|
-
const result = await aborter.try(async signal => {
|
|
188
|
+
const result = await aborter.try(async (signal) => {
|
|
154
189
|
const response = await fetch('/api/data', { signal });
|
|
155
190
|
if (!response.ok) {
|
|
156
191
|
throw new Error('Server Error');
|
|
@@ -169,26 +204,61 @@ Immediately cancels the currently executing request.
|
|
|
169
204
|
|
|
170
205
|
```javascript
|
|
171
206
|
// Start the request
|
|
172
|
-
const requestPromise = aborter.try(signal => fetch('/api/data', { signal }), { isErrorNativeBehavior: true });
|
|
207
|
+
const requestPromise = aborter.try((signal) => fetch('/api/data', { signal }), { isErrorNativeBehavior: true });
|
|
173
208
|
|
|
174
209
|
// Cancel
|
|
175
210
|
aborter.abort();
|
|
176
211
|
|
|
177
212
|
// Handle cancellation
|
|
178
|
-
requestPromise.catch(error => {
|
|
213
|
+
requestPromise.catch((error) => {
|
|
179
214
|
if (error.name === 'AbortError') {
|
|
180
215
|
console.log('Request canceled');
|
|
181
216
|
}
|
|
182
217
|
});
|
|
183
218
|
```
|
|
184
219
|
|
|
220
|
+
`abortWithRecovery(reason?)`
|
|
221
|
+
|
|
222
|
+
Immediately cancels the currently executing request.
|
|
223
|
+
After aborting, it restores the `AbortSignal`, resetting the `isAborted` property, and interaction with the `signal` property becomes available again.
|
|
224
|
+
|
|
225
|
+
**Parameters:**
|
|
226
|
+
|
|
227
|
+
- `reason?: any` - the reason for aborting the request (optional)
|
|
228
|
+
|
|
229
|
+
**Returns:** `AbortController`
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
// Create an Aborter instance
|
|
233
|
+
const aborter = new Aborter();
|
|
234
|
+
|
|
235
|
+
// Data retrieval function
|
|
236
|
+
async function fetchData() {
|
|
237
|
+
try {
|
|
238
|
+
const data = await fetch('/api/data', { signal: aborter.signal });
|
|
239
|
+
} catch (error) {
|
|
240
|
+
// Any error, except AbortError, will go here
|
|
241
|
+
console.log(error);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Calling a function with a request
|
|
246
|
+
fetchData();
|
|
247
|
+
|
|
248
|
+
// We interrupt the request and then restore the signal
|
|
249
|
+
aborter.abortWithRecovery();
|
|
250
|
+
|
|
251
|
+
// Call the function again
|
|
252
|
+
fetchData();
|
|
253
|
+
```
|
|
254
|
+
|
|
185
255
|
`static isError(error)`
|
|
186
256
|
|
|
187
257
|
Static method for checking if an object is an `AbortError` error.
|
|
188
258
|
|
|
189
259
|
```javascript
|
|
190
260
|
try {
|
|
191
|
-
await aborter.try(signal => fetch('/api/data', { signal }), { isErrorNativeBehavior: true });
|
|
261
|
+
await aborter.try((signal) => fetch('/api/data', { signal }), { isErrorNativeBehavior: true });
|
|
192
262
|
} catch (error) {
|
|
193
263
|
if (Aborter.isError(error)) {
|
|
194
264
|
console.log('This is a cancellation error');
|
|
@@ -198,20 +268,80 @@ try {
|
|
|
198
268
|
}
|
|
199
269
|
```
|
|
200
270
|
|
|
201
|
-
|
|
271
|
+
## 🔌 Additional APIs
|
|
202
272
|
|
|
203
|
-
|
|
273
|
+
- [**AbortError**](./docs/abort-error.md) - Custom error for working with Aborter.
|
|
274
|
+
|
|
275
|
+
## ⚠️ Important Features
|
|
276
|
+
|
|
277
|
+
### Error Handling
|
|
278
|
+
|
|
279
|
+
By default, the `try()` method does not reject the promise on `AbortError` (cancellation error). This prevents the `catch` block from being called when the request is canceled.
|
|
280
|
+
|
|
281
|
+
If you want the default behavior (the promise to be rejected on any error), use the `isErrorNativeBehavior` option:
|
|
204
282
|
|
|
205
283
|
```javascript
|
|
284
|
+
// The promise will be rejected even if an AbortError occurs
|
|
206
285
|
const result = await aborter
|
|
207
|
-
.try(signal => fetch('/api/data', { signal }), { isErrorNativeBehavior: true })
|
|
208
|
-
.catch(error => {
|
|
209
|
-
|
|
210
|
-
|
|
286
|
+
.try((signal) => fetch('/api/data', { signal }), { isErrorNativeBehavior: true })
|
|
287
|
+
.catch((error) => {
|
|
288
|
+
// ALL errors, including cancellations, will go here
|
|
289
|
+
if (error.name === 'AbortError') {
|
|
290
|
+
console.log('Cancelled');
|
|
211
291
|
}
|
|
212
292
|
});
|
|
213
293
|
```
|
|
214
294
|
|
|
295
|
+
### Finally block
|
|
296
|
+
|
|
297
|
+
By ignoring `AbortError` errors, the `finally` block will only be executed if other errors are received or if the request is successful.
|
|
298
|
+
|
|
299
|
+
```javascript
|
|
300
|
+
const result = await aborter
|
|
301
|
+
.try((signal) => fetch('/api/data', { signal }))
|
|
302
|
+
.catch((error) => {
|
|
303
|
+
// Any error, except AbortError, will go here
|
|
304
|
+
console.log(error);
|
|
305
|
+
})
|
|
306
|
+
.finally(() => {
|
|
307
|
+
// The request was successfully completed or we caught a "throw"
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Everything will also work if you use the `try-catch` syntax.
|
|
312
|
+
|
|
313
|
+
```javascript
|
|
314
|
+
try {
|
|
315
|
+
const result = await aborter.try((signal) => fetch('/api/data', { signal }));
|
|
316
|
+
} catch (error) {
|
|
317
|
+
// Any error, except AbortError, will go here
|
|
318
|
+
console.log(error);
|
|
319
|
+
} finally {
|
|
320
|
+
// The request was successfully completed or we caught a "throw"
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
#### ⚠️ Attention!
|
|
325
|
+
|
|
326
|
+
With the `isErrorNativeBehavior` flag enabled, the `finally` block will also be executed.
|
|
327
|
+
|
|
328
|
+
### Resource Cleanup
|
|
329
|
+
|
|
330
|
+
Always abort requests when unmounting components or closing pages:
|
|
331
|
+
|
|
332
|
+
```javascript
|
|
333
|
+
// In React
|
|
334
|
+
useEffect(() => {
|
|
335
|
+
const aborter = new Aborter();
|
|
336
|
+
|
|
337
|
+
// Make requests
|
|
338
|
+
|
|
339
|
+
return () => {
|
|
340
|
+
aborter.abort(); // Clean up on unmount
|
|
341
|
+
};
|
|
342
|
+
}, []);
|
|
343
|
+
```
|
|
344
|
+
|
|
215
345
|
## 🎯 Usage Examples
|
|
216
346
|
|
|
217
347
|
### Example 1: Autocomplete
|
|
@@ -224,7 +354,7 @@ class SearchAutocomplete {
|
|
|
224
354
|
if (!query.trim()) return [];
|
|
225
355
|
|
|
226
356
|
try {
|
|
227
|
-
const results = await this.aborter.try(async signal => {
|
|
357
|
+
const results = await this.aborter.try(async (signal) => {
|
|
228
358
|
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal });
|
|
229
359
|
|
|
230
360
|
return response.json();
|
|
@@ -258,11 +388,11 @@ class FileUploader {
|
|
|
258
388
|
|
|
259
389
|
try {
|
|
260
390
|
await this.aborter.try(
|
|
261
|
-
async signal => {
|
|
391
|
+
async (signal) => {
|
|
262
392
|
const response = await fetch('/api/upload', {
|
|
263
393
|
method: 'POST',
|
|
264
394
|
body: formData,
|
|
265
|
-
signal
|
|
395
|
+
signal
|
|
266
396
|
});
|
|
267
397
|
|
|
268
398
|
// Track progress
|
|
@@ -278,7 +408,7 @@ class FileUploader {
|
|
|
278
408
|
this.progress = Math.round((receivedLength / contentLength) * 100);
|
|
279
409
|
}
|
|
280
410
|
},
|
|
281
|
-
{ isErrorNativeBehavior: true }
|
|
411
|
+
{ isErrorNativeBehavior: true }
|
|
282
412
|
);
|
|
283
413
|
|
|
284
414
|
console.log('File uploaded successfully');
|
|
@@ -319,7 +449,7 @@ function DataFetcher({ url }) {
|
|
|
319
449
|
const fetchData = async () => {
|
|
320
450
|
setLoading(true);
|
|
321
451
|
try {
|
|
322
|
-
const result = await aborterRef.current.try(async signal => {
|
|
452
|
+
const result = await aborterRef.current.try(async (signal) => {
|
|
323
453
|
const response = await fetch(url, { signal });
|
|
324
454
|
return response.json();
|
|
325
455
|
});
|
|
@@ -361,7 +491,7 @@ export default {
|
|
|
361
491
|
return {
|
|
362
492
|
aborter: null,
|
|
363
493
|
data: null,
|
|
364
|
-
loading: false
|
|
494
|
+
loading: false
|
|
365
495
|
};
|
|
366
496
|
},
|
|
367
497
|
created() {
|
|
@@ -374,7 +504,7 @@ export default {
|
|
|
374
504
|
async fetchData() {
|
|
375
505
|
this.loading = true;
|
|
376
506
|
try {
|
|
377
|
-
this.data = await this.aborter.try(async signal => {
|
|
507
|
+
this.data = await this.aborter.try(async (signal) => {
|
|
378
508
|
const response = await fetch(this.url, { signal });
|
|
379
509
|
return response.json();
|
|
380
510
|
});
|
|
@@ -386,46 +516,9 @@ export default {
|
|
|
386
516
|
},
|
|
387
517
|
cancelRequest() {
|
|
388
518
|
this.aborter.abort();
|
|
389
|
-
},
|
|
390
|
-
},
|
|
391
|
-
};
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
## ⚠️ Important Features
|
|
395
|
-
|
|
396
|
-
### Error Handling
|
|
397
|
-
|
|
398
|
-
By default, the `try()` method does not reject the promise on `AbortError` (cancellation error). This prevents the `catch` block from being called when the request is canceled.
|
|
399
|
-
|
|
400
|
-
If you want the default behavior (the promise to be rejected on any error), use the `isErrorNativeBehavior` option:
|
|
401
|
-
|
|
402
|
-
```javascript
|
|
403
|
-
// The promise will be rejected even if an AbortError occurs
|
|
404
|
-
const result = await aborter
|
|
405
|
-
.try(signal => fetch('/api/data', { signal }), { isErrorNativeBehavior: true })
|
|
406
|
-
.catch(error => {
|
|
407
|
-
// ALL errors, including cancellations, will go here
|
|
408
|
-
if (error.name === 'AbortError') {
|
|
409
|
-
console.log('Cancelled');
|
|
410
519
|
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
### Resource Cleanup
|
|
415
|
-
|
|
416
|
-
Always abort requests when unmounting components or closing pages:
|
|
417
|
-
|
|
418
|
-
```javascript
|
|
419
|
-
// In React
|
|
420
|
-
useEffect(() => {
|
|
421
|
-
const aborter = new Aborter();
|
|
422
|
-
|
|
423
|
-
// Make requests
|
|
424
|
-
|
|
425
|
-
return () => {
|
|
426
|
-
aborter.abort(); // Clean up on unmount
|
|
427
|
-
};
|
|
428
|
-
}, []);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
429
522
|
```
|
|
430
523
|
|
|
431
524
|
## 💻 Compatibility
|
package/dist/index.cjs.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/constants/constants.ts","../src/utils/utils.ts","../src/aborter.ts"],"sourcesContent":["const ABORT_ERROR_MESSAGE = 'The user aborted a request.';\nconst ABORT_ERROR_WITHOUT_REASON_MESSAGE = 'signal is aborted without reason';\nexport const ABORT_ERROR_NAME = 'AbortError';\nexport const ERROR_CAUSE_PATH_NAME = 'cause.name';\nexport const ERROR_CAUSE_PATH_MESSAGE = 'cause.message';\nexport const ABORT_ERROR_MESSAGES = [\n ABORT_ERROR_MESSAGE,\n ABORT_ERROR_WITHOUT_REASON_MESSAGE,\n];\n","import * as Constants from '../constants';\n\nexport const get = <T, R>(object: T, path: string) =>\n path\n .split('.')\n .reduce(\n (acc, key) => acc && (acc as Record<string, any>)[key],\n object\n ) as unknown as R;\n\nexport const isError = (error: unknown): error is Error =>\n Constants.ABORT_ERROR_MESSAGES.includes(\n (error as Error | undefined)?.message ?? ''\n ) ||\n get(error, Constants.ERROR_CAUSE_PATH_NAME) === Constants.ABORT_ERROR_NAME ||\n Constants.ABORT_ERROR_MESSAGES.includes(\n get(error, Constants.ERROR_CAUSE_PATH_MESSAGE)\n );\n","import * as Utils from './utils';\nimport * as Constants from './constants';\nimport * as Types from './types';\n\nexport class Aborter {\n protected abortController = new AbortController();\n\n /**\n * The name of the error instance thrown by the AbortSignal.\n * @readonly\n */\n public static readonly errorName = Constants.ABORT_ERROR_NAME;\n /**\n * Method of checking whether an error is an error AbortError.\n * @returns boolean\n */\n public static isError = Utils.isError;\n\n /**\n * Returns the AbortSignal object associated with this object.\n */\n public get signal(): AbortSignal {\n return this.abortController.signal;\n }\n\n /**\n * Performs an asynchronous request with cancellation of the previous request, preventing the call of the catch block when the request is canceled and the subsequent finally block.\n * @param request callback function\n * @param options an object that receives a set of settings for performing a request attempt\n * @returns Promise\n */\n public try = <R>(\n request: Types.AbortRequest<R>,\n { isErrorNativeBehavior = false }: Types.FnTryOptions = {},\n ): Promise<R> => {\n let promise: Promise<R> | null = new Promise<R>((resolve, reject) => {\n this.abort();\n\n this.abortController = new AbortController();\n\n const { signal } = this.abortController;\n\n request(signal)\n .then(resolve)\n .catch((err: Error) => {\n const error: Error = {\n ...err,\n message: err?.message || Utils.get(err, Constants.ERROR_CAUSE_PATH_MESSAGE) || '',\n };\n\n if (isErrorNativeBehavior || !Aborter.isError(err)) {\n return reject(error);\n }\n\n promise = null;\n });\n });\n\n return promise;\n };\n\n /**\n * Calling this method sets the AbortSignal flag of this object and signals all observers that the associated action should be aborted.\n */\n public abort = (reason?: any) => this.abortController.abort(reason);\n}\n"],"names":["Constants.ABORT_ERROR_MESSAGES","Constants.ERROR_CAUSE_PATH_NAME","Constants.ABORT_ERROR_NAME","Constants.ERROR_CAUSE_PATH_MESSAGE","Utils.get","Utils.isError"],"mappings":";;AAAA,MAAM,sBAAsB;AAC5B,MAAM,qCAAqC;AACpC,MAAM,mBAAmB;AACzB,MAAM,wBAAwB;AAC9B,MAAM,2BAA2B;AACjC,MAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AACF;ACNO,MAAM,MAAM,CAAO,QAAW,SACnC,KACG,MAAM,GAAG,EACT;AAAA,EACC,CAAC,KAAK,QAAQ,OAAQ,IAA4B,GAAG;AAAA,EACrD;AACF;AAEG,MAAM,UAAU,CAAC,UACtBA,qBAA+B;AAAA,EAC5B,OAA6B,WAAW;AAC3C,KACA,IAAI,OAAOC,qBAA+B,MAAMC,oBAChDF,qBAA+B;AAAA,EAC7B,IAAI,OAAOG,wBAAkC;AAC/C;ACbK,MAAM,WAAN,MAAM,SAAQ;AAAA,EAAd,cAAA;AACL,SAAU,kBAAkB,IAAI,gBAAA;AA0BhC,SAAO,MAAM,CACX,SACA,EAAE,wBAAwB,MAAA,IAA8B,OACzC;AACf,UAAI,UAA6B,IAAI,QAAW,CAAC,SAAS,WAAW;AACnE,aAAK,MAAA;AAEL,aAAK,kBAAkB,IAAI,gBAAA;AAE3B,cAAM,EAAE,WAAW,KAAK;AAExB,gBAAQ,MAAM,EACX,KAAK,OAAO,EACZ,MAAM,CAAC,QAAe;AACrB,gBAAM,QAAe;AAAA,YACnB,GAAG;AAAA,YACH,SAAS,KAAK,WAAWC,IAAU,KAAKD,wBAAkC,KAAK;AAAA,UAAA;AAGjF,cAAI,yBAAyB,CAAC,SAAQ,QAAQ,GAAG,GAAG;AAClD,mBAAO,OAAO,KAAK;AAAA,UACrB;AAEA,oBAAU;AAAA,QACZ,CAAC;AAAA,MACL,CAAC;AAED,aAAO;AAAA,IACT;AAKA,SAAO,QAAQ,CAAC,WAAiB,KAAK,gBAAgB,MAAM,MAAM;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EA3ClE,IAAW,SAAsB;AAC/B,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AA0CF;AAtDE,SAAuB,YAAYD;AAKnC,SAAc,UAAUG;AAZnB,IAAM,UAAN;;"}
|
package/dist/index.es.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../src/constants/constants.ts","../src/utils/utils.ts","../src/aborter.ts"],"sourcesContent":["const ABORT_ERROR_MESSAGE = 'The user aborted a request.';\nconst ABORT_ERROR_WITHOUT_REASON_MESSAGE = 'signal is aborted without reason';\nexport const ABORT_ERROR_NAME = 'AbortError';\nexport const ERROR_CAUSE_PATH_NAME = 'cause.name';\nexport const ERROR_CAUSE_PATH_MESSAGE = 'cause.message';\nexport const ABORT_ERROR_MESSAGES = [\n ABORT_ERROR_MESSAGE,\n ABORT_ERROR_WITHOUT_REASON_MESSAGE,\n];\n","import * as Constants from '../constants';\n\nexport const get = <T, R>(object: T, path: string) =>\n path\n .split('.')\n .reduce(\n (acc, key) => acc && (acc as Record<string, any>)[key],\n object\n ) as unknown as R;\n\nexport const isError = (error: unknown): error is Error =>\n Constants.ABORT_ERROR_MESSAGES.includes(\n (error as Error | undefined)?.message ?? ''\n ) ||\n get(error, Constants.ERROR_CAUSE_PATH_NAME) === Constants.ABORT_ERROR_NAME ||\n Constants.ABORT_ERROR_MESSAGES.includes(\n get(error, Constants.ERROR_CAUSE_PATH_MESSAGE)\n );\n","import * as Utils from './utils';\nimport * as Constants from './constants';\nimport * as Types from './types';\n\nexport class Aborter {\n protected abortController = new AbortController();\n\n /**\n * The name of the error instance thrown by the AbortSignal.\n * @readonly\n */\n public static readonly errorName = Constants.ABORT_ERROR_NAME;\n /**\n * Method of checking whether an error is an error AbortError.\n * @returns boolean\n */\n public static isError = Utils.isError;\n\n /**\n * Returns the AbortSignal object associated with this object.\n */\n public get signal(): AbortSignal {\n return this.abortController.signal;\n }\n\n /**\n * Performs an asynchronous request with cancellation of the previous request, preventing the call of the catch block when the request is canceled and the subsequent finally block.\n * @param request callback function\n * @param options an object that receives a set of settings for performing a request attempt\n * @returns Promise\n */\n public try = <R>(\n request: Types.AbortRequest<R>,\n { isErrorNativeBehavior = false }: Types.FnTryOptions = {},\n ): Promise<R> => {\n let promise: Promise<R> | null = new Promise<R>((resolve, reject) => {\n this.abort();\n\n this.abortController = new AbortController();\n\n const { signal } = this.abortController;\n\n request(signal)\n .then(resolve)\n .catch((err: Error) => {\n const error: Error = {\n ...err,\n message: err?.message || Utils.get(err, Constants.ERROR_CAUSE_PATH_MESSAGE) || '',\n };\n\n if (isErrorNativeBehavior || !Aborter.isError(err)) {\n return reject(error);\n }\n\n promise = null;\n });\n });\n\n return promise;\n };\n\n /**\n * Calling this method sets the AbortSignal flag of this object and signals all observers that the associated action should be aborted.\n */\n public abort = (reason?: any) => this.abortController.abort(reason);\n}\n"],"names":["Constants.ABORT_ERROR_MESSAGES","Constants.ERROR_CAUSE_PATH_NAME","Constants.ABORT_ERROR_NAME","Constants.ERROR_CAUSE_PATH_MESSAGE","Utils.get","Utils.isError"],"mappings":"AAAA,MAAM,sBAAsB;AAC5B,MAAM,qCAAqC;AACpC,MAAM,mBAAmB;AACzB,MAAM,wBAAwB;AAC9B,MAAM,2BAA2B;AACjC,MAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AACF;ACNO,MAAM,MAAM,CAAO,QAAW,SACnC,KACG,MAAM,GAAG,EACT;AAAA,EACC,CAAC,KAAK,QAAQ,OAAQ,IAA4B,GAAG;AAAA,EACrD;AACF;AAEG,MAAM,UAAU,CAAC,UACtBA,qBAA+B;AAAA,EAC5B,OAA6B,WAAW;AAC3C,KACA,IAAI,OAAOC,qBAA+B,MAAMC,oBAChDF,qBAA+B;AAAA,EAC7B,IAAI,OAAOG,wBAAkC;AAC/C;ACbK,MAAM,WAAN,MAAM,SAAQ;AAAA,EAAd,cAAA;AACL,SAAU,kBAAkB,IAAI,gBAAA;AA0BhC,SAAO,MAAM,CACX,SACA,EAAE,wBAAwB,MAAA,IAA8B,OACzC;AACf,UAAI,UAA6B,IAAI,QAAW,CAAC,SAAS,WAAW;AACnE,aAAK,MAAA;AAEL,aAAK,kBAAkB,IAAI,gBAAA;AAE3B,cAAM,EAAE,WAAW,KAAK;AAExB,gBAAQ,MAAM,EACX,KAAK,OAAO,EACZ,MAAM,CAAC,QAAe;AACrB,gBAAM,QAAe;AAAA,YACnB,GAAG;AAAA,YACH,SAAS,KAAK,WAAWC,IAAU,KAAKD,wBAAkC,KAAK;AAAA,UAAA;AAGjF,cAAI,yBAAyB,CAAC,SAAQ,QAAQ,GAAG,GAAG;AAClD,mBAAO,OAAO,KAAK;AAAA,UACrB;AAEA,oBAAU;AAAA,QACZ,CAAC;AAAA,MACL,CAAC;AAED,aAAO;AAAA,IACT;AAKA,SAAO,QAAQ,CAAC,WAAiB,KAAK,gBAAgB,MAAM,MAAM;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EA3ClE,IAAW,SAAsB;AAC/B,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AA0CF;AAtDE,SAAuB,YAAYD;AAKnC,SAAc,UAAUG;AAZnB,IAAM,UAAN;"}
|