keq 2.9.0 → 2.10.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/CHANGELOG.md +7 -0
- package/dist/esm/src/constant.d.ts +2 -0
- package/dist/esm/src/constant.js +2 -0
- package/dist/esm/src/core.d.ts +30 -0
- package/dist/esm/src/core.js +162 -53
- package/dist/esm/src/exception/abort.exception.d.ts +3 -0
- package/dist/esm/src/exception/abort.exception.js +6 -0
- package/dist/esm/src/index.d.ts +1 -0
- package/dist/esm/src/index.js +1 -0
- package/dist/esm/src/is/is-abort-signal.d.ts +1 -0
- package/dist/esm/src/is/is-abort-signal.js +8 -0
- package/dist/esm/src/middlewares/fetch-arguments-middleware.js +5 -1
- package/dist/esm/src/middlewares/retry-middleware.js +20 -3
- package/dist/esm/src/middlewares/timeout-middleware.js +3 -1
- package/dist/esm/src/types/keq-context.d.ts +10 -1
- package/dist/esm/src/types/keq-context.js +1 -1
- package/dist/umd/src/constant.d.ts +2 -0
- package/dist/umd/src/constant.js +3 -1
- package/dist/umd/src/core.d.ts +30 -0
- package/dist/umd/src/core.js +162 -53
- package/dist/umd/src/exception/abort.exception.d.ts +3 -0
- package/dist/umd/src/exception/abort.exception.js +20 -0
- package/dist/umd/src/index.d.ts +1 -0
- package/dist/umd/src/index.js +4 -2
- package/dist/umd/src/is/is-abort-signal.d.ts +1 -0
- package/dist/umd/src/is/is-abort-signal.js +22 -0
- package/dist/umd/src/middlewares/fetch-arguments-middleware.js +4 -0
- package/dist/umd/src/middlewares/retry-middleware.js +21 -4
- package/dist/umd/src/middlewares/timeout-middleware.js +4 -2
- package/dist/umd/src/types/keq-context.d.ts +10 -1
- package/package.json +10 -13
- package/.claude/settings.local.json +0 -26
- package/packages/cache/.turbo/turbo-build.log +0 -29
- package/packages/cache/dist/index.d.mts +0 -354
- package/packages/cache/dist/index.d.mts.map +0 -1
- package/packages/cache/dist/index.d.ts +0 -353
- package/packages/cache/dist/index.d.ts.map +0 -1
- package/packages/cache/dist/index.js +0 -1271
- package/packages/cache/dist/index.js.map +0 -1
- package/packages/cache/dist/index.mjs +0 -1237
- package/packages/cache/dist/index.mjs.map +0 -1
- package/packages/cli/.turbo/turbo-build.log +0 -91
- package/packages/cli/dist/cli.cjs +0 -1364
- package/packages/cli/dist/cli.cjs.map +0 -1
- package/packages/cli/dist/cli.d.cts +0 -1
- package/packages/cli/dist/cli.d.mts +0 -1
- package/packages/cli/dist/cli.mjs +0 -1359
- package/packages/cli/dist/cli.mjs.map +0 -1
- package/packages/cli/dist/compiler-0Kli6UCr.cjs +0 -738
- package/packages/cli/dist/compiler-0Kli6UCr.cjs.map +0 -1
- package/packages/cli/dist/compiler-C3AE8j54.mjs +0 -715
- package/packages/cli/dist/compiler-C3AE8j54.mjs.map +0 -1
- package/packages/cli/dist/index.cjs +0 -20
- package/packages/cli/dist/index.cjs.map +0 -1
- package/packages/cli/dist/index.d.cts +0 -17
- package/packages/cli/dist/index.d.cts.map +0 -1
- package/packages/cli/dist/index.d.mts +0 -17
- package/packages/cli/dist/index.d.mts.map +0 -1
- package/packages/cli/dist/index.mjs +0 -10
- package/packages/cli/dist/index.mjs.map +0 -1
- package/packages/cli/dist/init-BNhD2oCI.mjs +0 -168
- package/packages/cli/dist/init-BNhD2oCI.mjs.map +0 -1
- package/packages/cli/dist/init-DqxLcRSQ.cjs +0 -170
- package/packages/cli/dist/init-DqxLcRSQ.cjs.map +0 -1
- package/packages/cli/dist/logger-D7PyVZo3.cjs +0 -46
- package/packages/cli/dist/logger-D7PyVZo3.cjs.map +0 -1
- package/packages/cli/dist/logger-QLBHySQ3.mjs +0 -12
- package/packages/cli/dist/logger-QLBHySQ3.mjs.map +0 -1
- package/packages/cli/dist/micro-function.translator-BmJZzkKh.cjs +0 -16
- package/packages/cli/dist/micro-function.translator-BmJZzkKh.cjs.map +0 -1
- package/packages/cli/dist/micro-function.translator-CDfkj4Tt.mjs +0 -11
- package/packages/cli/dist/micro-function.translator-CDfkj4Tt.mjs.map +0 -1
- package/packages/cli/dist/mock-command-Bp1LxSls.mjs +0 -350
- package/packages/cli/dist/mock-command-Bp1LxSls.mjs.map +0 -1
- package/packages/cli/dist/mock-command-WZcfy5Iq.cjs +0 -353
- package/packages/cli/dist/mock-command-WZcfy5Iq.cjs.map +0 -1
- package/packages/cli/dist/plugins-CgMhaNZq.cjs +0 -3558
- package/packages/cli/dist/plugins-CgMhaNZq.cjs.map +0 -1
- package/packages/cli/dist/plugins-DCvJ8iHR.mjs +0 -3280
- package/packages/cli/dist/plugins-DCvJ8iHR.mjs.map +0 -1
- package/packages/cli/dist/plugins.cjs +0 -36
- package/packages/cli/dist/plugins.d.cts +0 -2
- package/packages/cli/dist/plugins.d.mts +0 -2
- package/packages/cli/dist/plugins.mjs +0 -2
- package/packages/cli/dist/runtime-config-BWQlPhiB.d.cts +0 -780
- package/packages/cli/dist/runtime-config-BWQlPhiB.d.cts.map +0 -1
- package/packages/cli/dist/runtime-config-CrzK-Ucf.d.mts +0 -780
- package/packages/cli/dist/runtime-config-CrzK-Ucf.d.mts.map +0 -1
- package/packages/cli/dist/translators.cjs +0 -14
- package/packages/cli/dist/translators.cjs.map +0 -1
- package/packages/cli/dist/translators.d.cts +0 -14
- package/packages/cli/dist/translators.d.cts.map +0 -1
- package/packages/cli/dist/translators.d.mts +0 -14
- package/packages/cli/dist/translators.d.mts.map +0 -1
- package/packages/cli/dist/translators.mjs +0 -12
- package/packages/cli/dist/translators.mjs.map +0 -1
- package/packages/cli/node_modules/.bin/eslint +0 -21
- package/packages/cli/node_modules/.bin/jiti +0 -21
- package/packages/cli/node_modules/.bin/js-yaml +0 -21
- package/packages/cli/node_modules/.bin/jsf +0 -21
- package/packages/cli/node_modules/.bin/jsonpath +0 -21
- package/packages/cli/node_modules/.bin/jsonpath-plus +0 -21
- package/packages/cli/node_modules/.bin/semver +0 -21
- package/packages/cli/node_modules/.bin/tsc +0 -21
- package/packages/cli/node_modules/.bin/tsserver +0 -21
- package/packages/exception/.turbo/turbo-build.log +0 -29
- package/packages/exception/dist/index.d.mts +0 -21
- package/packages/exception/dist/index.d.mts.map +0 -1
- package/packages/exception/dist/index.d.ts +0 -21
- package/packages/exception/dist/index.d.ts.map +0 -1
- package/packages/exception/dist/index.js +0 -104
- package/packages/exception/dist/index.js.map +0 -1
- package/packages/exception/dist/index.mjs +0 -99
- package/packages/exception/dist/index.mjs.map +0 -1
- package/packages/headers/.turbo/turbo-build.log +0 -29
- package/packages/headers/dist/index.d.mts +0 -46
- package/packages/headers/dist/index.d.mts.map +0 -1
- package/packages/headers/dist/index.d.ts +0 -46
- package/packages/headers/dist/index.d.ts.map +0 -1
- package/packages/headers/dist/index.js +0 -81
- package/packages/headers/dist/index.js.map +0 -1
- package/packages/headers/dist/index.mjs +0 -75
- package/packages/headers/dist/index.mjs.map +0 -1
- package/packages/keq/.turbo/turbo-build.log +0 -29
- package/packages/keq/dist/index.d.mts +0 -962
- package/packages/keq/dist/index.d.mts.map +0 -1
- package/packages/keq/dist/index.d.ts +0 -962
- package/packages/keq/dist/index.d.ts.map +0 -1
- package/packages/keq/dist/index.js +0 -1876
- package/packages/keq/dist/index.js.map +0 -1
- package/packages/keq/dist/index.mjs +0 -1814
- package/packages/keq/dist/index.mjs.map +0 -1
- package/packages/nestjs/.turbo/turbo-build.log +0 -29
- package/packages/nestjs/dist/index.d.mts +0 -52
- package/packages/nestjs/dist/index.d.mts.map +0 -1
- package/packages/nestjs/dist/index.d.ts +0 -52
- package/packages/nestjs/dist/index.d.ts.map +0 -1
- package/packages/nestjs/dist/index.js +0 -166
- package/packages/nestjs/dist/index.js.map +0 -1
- package/packages/nestjs/dist/index.mjs +0 -136
- package/packages/nestjs/dist/index.mjs.map +0 -1
- package/packages/test/.turbo/turbo-build.log +0 -6
- package/packages/url/.turbo/turbo-build.log +0 -29
- package/packages/url/dist/index.d.mts +0 -9
- package/packages/url/dist/index.d.mts.map +0 -1
- package/packages/url/dist/index.d.ts +0 -9
- package/packages/url/dist/index.d.ts.map +0 -1
- package/packages/url/dist/index.js +0 -43
- package/packages/url/dist/index.js.map +0 -1
- package/packages/url/dist/index.mjs +0 -40
- package/packages/url/dist/index.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [2.10.0](https://github.com/keq-request/keq/compare/v2.9.0...v2.10.0) (2026-11-07)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* add abort and abortWhen request methods ([29b4d9c](https://github.com/keq-request/keq/commit/29b4d9c668d0432944913e55043278efd09e05ce))
|
|
11
|
+
|
|
5
12
|
## [2.9.0](https://github.com/keq-request/keq/compare/v2.8.14...v2.9.0) (2026-06-17)
|
|
6
13
|
|
|
7
14
|
|
package/dist/esm/src/constant.js
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export const OUTPUT_PROPERTY = Symbol('outputProperty');
|
|
2
2
|
export const ABORT_PROPERTY = Symbol('abortProperty');
|
|
3
|
+
export const SESSION_ABORTED_PROPERTY = Symbol('sessionAbortedProperty');
|
|
4
|
+
export const SESSION_ABORT_CONTROLLER_PROPERTY = Symbol('sessionAbortControllerProperty');
|
package/dist/esm/src/core.d.ts
CHANGED
|
@@ -12,6 +12,18 @@ export declare class Core<OUTPUT> {
|
|
|
12
12
|
*/
|
|
13
13
|
__identifier__: string;
|
|
14
14
|
private requestPromise?;
|
|
15
|
+
/** Whether abort() has been called on this request. */
|
|
16
|
+
private __aborted__;
|
|
17
|
+
/** The reason passed to abort(). */
|
|
18
|
+
private __abortReason__;
|
|
19
|
+
/** The context of the running attempt, used to abort the in-flight fetch. */
|
|
20
|
+
private __activeContext__?;
|
|
21
|
+
/** Aborts as soon as abort() is called, used to interrupt retry delays. */
|
|
22
|
+
private __sessionAbortController__?;
|
|
23
|
+
/** Cleanup callbacks registered by abortWhen(). */
|
|
24
|
+
private __abortWhenCleanups__;
|
|
25
|
+
/** Whether the request has settled (resolved or rejected). */
|
|
26
|
+
private __settled__;
|
|
15
27
|
protected requestContext: Omit<KeqContextRequest, 'abort' | '__url__'>;
|
|
16
28
|
protected __listeners__: KeqListeners;
|
|
17
29
|
protected __global__: Record<string, any>;
|
|
@@ -22,6 +34,24 @@ export declare class Core<OUTPUT> {
|
|
|
22
34
|
prependMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
23
35
|
appendMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
24
36
|
on<K extends keyof KeqEvents>(event: K, listener: (data: KeqEvents[K]) => void): this;
|
|
37
|
+
/**
|
|
38
|
+
* Abort the request manually.
|
|
39
|
+
*
|
|
40
|
+
* The request rejects with the given reason (an AbortException by default),
|
|
41
|
+
* and no further retry is performed. It is safe to call abort() before the
|
|
42
|
+
* request is sent.
|
|
43
|
+
*
|
|
44
|
+
* @description 手动中止请求
|
|
45
|
+
*/
|
|
46
|
+
abort(reason?: any): void;
|
|
47
|
+
/**
|
|
48
|
+
* Abort the request when the given AbortSignal aborts,
|
|
49
|
+
* or when the given Promise settles (resolves or rejects).
|
|
50
|
+
*
|
|
51
|
+
* @description 当 signal 中止或 promise 完成时终止请求
|
|
52
|
+
*/
|
|
53
|
+
abortWhen(source: AbortSignal | PromiseLike<unknown>): this;
|
|
54
|
+
private __clearAbortWhenCleanups__;
|
|
25
55
|
private run;
|
|
26
56
|
end(): Promise<OUTPUT>;
|
|
27
57
|
/**
|
package/dist/esm/src/core.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import mitt from 'mitt';
|
|
3
|
+
import { AbortException } from './exception/abort.exception.js';
|
|
3
4
|
import { Exception } from './exception/exception.js';
|
|
5
|
+
import { InvalidArgumentsExceptions } from './exception/invalid-arguments.exception.js';
|
|
6
|
+
import { isAbortSignal } from './is/is-abort-signal.js';
|
|
4
7
|
import { cloneBody } from './util/clone-body.js';
|
|
5
|
-
import { ABORT_PROPERTY, OUTPUT_PROPERTY } from './constant.js';
|
|
8
|
+
import { ABORT_PROPERTY, OUTPUT_PROPERTY, SESSION_ABORTED_PROPERTY, SESSION_ABORT_CONTROLLER_PROPERTY } from './constant.js';
|
|
6
9
|
import { composeMiddleware } from './util/compose-middleware.js';
|
|
7
10
|
import { shallowClone } from './util/shallow-clone.js';
|
|
8
11
|
import { compileUrl } from './util/compile-url.js';
|
|
@@ -16,6 +19,18 @@ export class Core {
|
|
|
16
19
|
*/
|
|
17
20
|
__identifier__;
|
|
18
21
|
requestPromise;
|
|
22
|
+
/** Whether abort() has been called on this request. */
|
|
23
|
+
__aborted__ = false;
|
|
24
|
+
/** The reason passed to abort(). */
|
|
25
|
+
__abortReason__;
|
|
26
|
+
/** The context of the running attempt, used to abort the in-flight fetch. */
|
|
27
|
+
__activeContext__;
|
|
28
|
+
/** Aborts as soon as abort() is called, used to interrupt retry delays. */
|
|
29
|
+
__sessionAbortController__;
|
|
30
|
+
/** Cleanup callbacks registered by abortWhen(). */
|
|
31
|
+
__abortWhenCleanups__ = [];
|
|
32
|
+
/** Whether the request has settled (resolved or rejected). */
|
|
33
|
+
__settled__ = false;
|
|
19
34
|
requestContext;
|
|
20
35
|
__listeners__ = {};
|
|
21
36
|
__global__;
|
|
@@ -50,7 +65,74 @@ export class Core {
|
|
|
50
65
|
this.__listeners__[event].push(listener);
|
|
51
66
|
return this;
|
|
52
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Abort the request manually.
|
|
70
|
+
*
|
|
71
|
+
* The request rejects with the given reason (an AbortException by default),
|
|
72
|
+
* and no further retry is performed. It is safe to call abort() before the
|
|
73
|
+
* request is sent.
|
|
74
|
+
*
|
|
75
|
+
* @description 手动中止请求
|
|
76
|
+
*/
|
|
77
|
+
abort(reason = new AbortException('Request aborted')) {
|
|
78
|
+
if (this.__aborted__ || this.__settled__)
|
|
79
|
+
return;
|
|
80
|
+
this.__aborted__ = true;
|
|
81
|
+
this.__abortReason__ = reason;
|
|
82
|
+
const ctx = this.__activeContext__;
|
|
83
|
+
if (ctx)
|
|
84
|
+
ctx.abort(reason);
|
|
85
|
+
this.__clearAbortWhenCleanups__();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Abort the request when the given AbortSignal aborts,
|
|
89
|
+
* or when the given Promise settles (resolves or rejects).
|
|
90
|
+
*
|
|
91
|
+
* @description 当 signal 中止或 promise 完成时终止请求
|
|
92
|
+
*/
|
|
93
|
+
abortWhen(source) {
|
|
94
|
+
if (this.__aborted__ || this.__settled__)
|
|
95
|
+
return this;
|
|
96
|
+
if (isAbortSignal(source)) {
|
|
97
|
+
const reason = () => source.reason ?? new AbortException('Request aborted by AbortSignal passed to abortWhen()');
|
|
98
|
+
if (source.aborted) {
|
|
99
|
+
this.abort(reason());
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
const onAbort = () => this.abort(reason());
|
|
103
|
+
source.addEventListener('abort', onAbort, { once: true });
|
|
104
|
+
this.__abortWhenCleanups__.push(() => source.removeEventListener('abort', onAbort));
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
if (typeof source === 'object' && source !== null && typeof source.then === 'function') {
|
|
108
|
+
const reason = new AbortException('Request aborted by Promise passed to abortWhen()');
|
|
109
|
+
let cancelled = false;
|
|
110
|
+
this.__abortWhenCleanups__.push(() => {
|
|
111
|
+
cancelled = true;
|
|
112
|
+
});
|
|
113
|
+
void Promise.resolve(source).then(() => {
|
|
114
|
+
if (!cancelled)
|
|
115
|
+
this.abort(reason);
|
|
116
|
+
}, () => {
|
|
117
|
+
if (!cancelled)
|
|
118
|
+
this.abort(reason);
|
|
119
|
+
});
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
throw new InvalidArgumentsExceptions();
|
|
123
|
+
}
|
|
124
|
+
__clearAbortWhenCleanups__() {
|
|
125
|
+
const cleanups = this.__abortWhenCleanups__;
|
|
126
|
+
this.__abortWhenCleanups__ = [];
|
|
127
|
+
for (const cleanup of cleanups)
|
|
128
|
+
cleanup();
|
|
129
|
+
}
|
|
53
130
|
async run() {
|
|
131
|
+
if (this.__aborted__) {
|
|
132
|
+
this.__settled__ = true;
|
|
133
|
+
this.__clearAbortWhenCleanups__();
|
|
134
|
+
throw this.__abortReason__;
|
|
135
|
+
}
|
|
54
136
|
const headers = new Headers();
|
|
55
137
|
for (const [key, value] of this.requestContext.headers.entries()) {
|
|
56
138
|
headers.append(key, value);
|
|
@@ -100,69 +182,98 @@ export class Core {
|
|
|
100
182
|
},
|
|
101
183
|
[ABORT_PROPERTY]: undefined,
|
|
102
184
|
abort(reason) {
|
|
185
|
+
// Mark the request as aborted, so pending retries are stopped
|
|
186
|
+
this[SESSION_ABORTED_PROPERTY] = reason;
|
|
187
|
+
this[SESSION_ABORT_CONTROLLER_PROPERTY]?.abort(reason);
|
|
103
188
|
const abortController = this[ABORT_PROPERTY];
|
|
104
|
-
if (abortController)
|
|
189
|
+
if (abortController)
|
|
105
190
|
abortController.abort(reason);
|
|
106
|
-
}
|
|
107
191
|
},
|
|
108
192
|
};
|
|
193
|
+
const sessionAbortController = new AbortController();
|
|
194
|
+
this.__sessionAbortController__ = sessionAbortController;
|
|
195
|
+
this.__activeContext__ = ctx;
|
|
196
|
+
ctx[SESSION_ABORT_CONTROLLER_PROPERTY] = sessionAbortController;
|
|
109
197
|
const middleware = composeMiddleware([...this.__prepend_middlewares__, ...this.__append_middlewares__]);
|
|
110
|
-
await middleware(ctx, async function emptyNext() { });
|
|
111
|
-
const output = ctx[OUTPUT_PROPERTY];
|
|
112
|
-
if (ctx.options.resolveWithFullResponse || ctx.options.resolveWith === 'response') {
|
|
113
|
-
return ctx.response?.clone();
|
|
114
|
-
}
|
|
115
|
-
const response = ctx.response;
|
|
116
|
-
if (!response) {
|
|
117
|
-
return (OUTPUT_PROPERTY in ctx) ? output : undefined;
|
|
118
|
-
}
|
|
119
|
-
if (ctx.options.resolveWith === 'text') {
|
|
120
|
-
return await response.text();
|
|
121
|
-
}
|
|
122
|
-
else if (ctx.options.resolveWith === 'json') {
|
|
123
|
-
return unwrap(await response.json());
|
|
124
|
-
}
|
|
125
|
-
else if (ctx.options.resolveWith === 'form-data') {
|
|
126
|
-
return await response.formData();
|
|
127
|
-
}
|
|
128
|
-
else if (ctx.options.resolveWith === 'blob') {
|
|
129
|
-
return await response.blob();
|
|
130
|
-
}
|
|
131
|
-
else if (ctx.options.resolveWith === 'array-buffer') {
|
|
132
|
-
return await response.arrayBuffer();
|
|
133
|
-
}
|
|
134
|
-
if (OUTPUT_PROPERTY in ctx) {
|
|
135
|
-
return output;
|
|
136
|
-
}
|
|
137
|
-
if (response.status === 204) {
|
|
138
|
-
// 204: NO CONTENT
|
|
139
|
-
return undefined;
|
|
140
|
-
}
|
|
141
|
-
const contentType = response.headers.get('content-type') || '';
|
|
142
198
|
try {
|
|
143
|
-
|
|
199
|
+
await middleware(ctx, async function emptyNext() { });
|
|
200
|
+
if (this.__aborted__)
|
|
201
|
+
throw this.__abortReason__;
|
|
202
|
+
const output = ctx[OUTPUT_PROPERTY];
|
|
203
|
+
if (ctx.options.resolveWithFullResponse || ctx.options.resolveWith === 'response') {
|
|
204
|
+
return ctx.response?.clone();
|
|
205
|
+
}
|
|
206
|
+
const response = ctx.response;
|
|
207
|
+
if (!response) {
|
|
208
|
+
return (OUTPUT_PROPERTY in ctx) ? output : undefined;
|
|
209
|
+
}
|
|
210
|
+
if (ctx.options.resolveWith === 'text') {
|
|
211
|
+
return await response.text();
|
|
212
|
+
}
|
|
213
|
+
else if (ctx.options.resolveWith === 'json') {
|
|
144
214
|
return unwrap(await response.json());
|
|
145
215
|
}
|
|
146
|
-
else if (
|
|
216
|
+
else if (ctx.options.resolveWith === 'form-data') {
|
|
147
217
|
return await response.formData();
|
|
148
218
|
}
|
|
149
|
-
else if (
|
|
150
|
-
return await response.
|
|
219
|
+
else if (ctx.options.resolveWith === 'blob') {
|
|
220
|
+
return await response.blob();
|
|
221
|
+
}
|
|
222
|
+
else if (ctx.options.resolveWith === 'array-buffer') {
|
|
223
|
+
return await response.arrayBuffer();
|
|
224
|
+
}
|
|
225
|
+
if (OUTPUT_PROPERTY in ctx) {
|
|
226
|
+
return output;
|
|
151
227
|
}
|
|
228
|
+
if (response.status === 204) {
|
|
229
|
+
// 204: NO CONTENT
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
const contentType = response.headers.get('content-type') || '';
|
|
233
|
+
try {
|
|
234
|
+
if (contentType.includes('application/json')) {
|
|
235
|
+
return unwrap(await response.json());
|
|
236
|
+
}
|
|
237
|
+
else if (contentType.includes('multipart/form-data')) {
|
|
238
|
+
return await response.formData();
|
|
239
|
+
}
|
|
240
|
+
else if (contentType.includes('plain/text')) {
|
|
241
|
+
return await response.text();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch (e) {
|
|
245
|
+
console.warn('Failed to auto parse response body', e);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Unable to parse response body
|
|
249
|
+
* Return undefined
|
|
250
|
+
* Enable users to discover the problem
|
|
251
|
+
* And modify the method of parsing response
|
|
252
|
+
*/
|
|
253
|
+
return undefined;
|
|
152
254
|
}
|
|
153
|
-
catch (
|
|
154
|
-
|
|
255
|
+
catch (error) {
|
|
256
|
+
if (this.__aborted__)
|
|
257
|
+
throw this.__abortReason__;
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
if (this.__activeContext__ === ctx)
|
|
262
|
+
this.__activeContext__ = undefined;
|
|
263
|
+
if (this.__sessionAbortController__ === sessionAbortController)
|
|
264
|
+
this.__sessionAbortController__ = undefined;
|
|
265
|
+
this.__settled__ = true;
|
|
266
|
+
this.__clearAbortWhenCleanups__();
|
|
155
267
|
}
|
|
156
|
-
/**
|
|
157
|
-
* Unable to parse response body
|
|
158
|
-
* Return undefined
|
|
159
|
-
* Enable users to discover the problem
|
|
160
|
-
* And modify the method of parsing response
|
|
161
|
-
*/
|
|
162
|
-
return undefined;
|
|
163
268
|
}
|
|
164
|
-
|
|
165
|
-
|
|
269
|
+
end() {
|
|
270
|
+
if (!this.requestPromise) {
|
|
271
|
+
this.requestPromise = this.run();
|
|
272
|
+
// `end()` can be used to send the request without awaiting the result,
|
|
273
|
+
// mark the rejection as handled to avoid an unhandled rejection
|
|
274
|
+
void this.requestPromise.catch(() => { });
|
|
275
|
+
}
|
|
276
|
+
return this.requestPromise;
|
|
166
277
|
}
|
|
167
278
|
/**
|
|
168
279
|
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
|
@@ -171,9 +282,7 @@ export class Core {
|
|
|
171
282
|
* @returns A Promise for the completion of which ever callback is executed.
|
|
172
283
|
*/
|
|
173
284
|
then(onfulfilled, onrejected) {
|
|
174
|
-
|
|
175
|
-
this.requestPromise = this.end();
|
|
176
|
-
return this.requestPromise.then(onfulfilled, onrejected);
|
|
285
|
+
return this.end().then(onfulfilled, onrejected);
|
|
177
286
|
}
|
|
178
287
|
catch(onrejected) {
|
|
179
288
|
return this.end().catch(onrejected);
|
package/dist/esm/src/index.d.ts
CHANGED
package/dist/esm/src/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isAbortSignal(value: unknown): value is AbortSignal;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function isAbortSignal(value) {
|
|
2
|
+
if (typeof AbortSignal !== 'undefined' && value instanceof AbortSignal)
|
|
3
|
+
return true;
|
|
4
|
+
return typeof value === 'object' && value !== null
|
|
5
|
+
&& typeof value.aborted === 'boolean'
|
|
6
|
+
&& typeof value.addEventListener === 'function'
|
|
7
|
+
&& typeof value.removeEventListener === 'function';
|
|
8
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Exception } from '../exception/exception.js';
|
|
2
|
-
import { ABORT_PROPERTY } from '../constant.js';
|
|
2
|
+
import { ABORT_PROPERTY, SESSION_ABORTED_PROPERTY } from '../constant.js';
|
|
3
3
|
import { isBuffer } from "../is/is-buffer.js";
|
|
4
4
|
import { isBlob } from "../is/is-blob.js";
|
|
5
5
|
import { isArrayBuffer } from "../is/is-array-buffer.js";
|
|
@@ -81,6 +81,10 @@ export function fetchArgumentsMiddleware() {
|
|
|
81
81
|
}
|
|
82
82
|
const abortController = new AbortController();
|
|
83
83
|
ctx[ABORT_PROPERTY] = abortController;
|
|
84
|
+
// The request may have been aborted before the abort controller was created
|
|
85
|
+
const sessionAbortReason = ctx[SESSION_ABORTED_PROPERTY];
|
|
86
|
+
if (sessionAbortReason)
|
|
87
|
+
abortController.abort(sessionAbortReason);
|
|
84
88
|
const requestInit = {
|
|
85
89
|
method: request.method.toUpperCase(),
|
|
86
90
|
headers: request.headers,
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { SESSION_ABORTED_PROPERTY, SESSION_ABORT_CONTROLLER_PROPERTY } from '../constant.js';
|
|
2
|
+
function sleep(ms, signal) {
|
|
3
|
+
if (signal?.aborted)
|
|
4
|
+
return Promise.resolve();
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
const timer = setTimeout(() => finish(), ms);
|
|
7
|
+
function finish() {
|
|
8
|
+
clearTimeout(timer);
|
|
9
|
+
signal?.removeEventListener('abort', finish);
|
|
10
|
+
resolve();
|
|
11
|
+
}
|
|
12
|
+
signal?.addEventListener('abort', finish, { once: true });
|
|
13
|
+
});
|
|
3
14
|
}
|
|
4
15
|
export function retryMiddleware() {
|
|
5
16
|
return async function retryMiddleware(ctx, next) {
|
|
@@ -27,6 +38,9 @@ export function retryMiddleware() {
|
|
|
27
38
|
retryOn: undefined,
|
|
28
39
|
};
|
|
29
40
|
for (let i = 0; i < retryTimes; i++) {
|
|
41
|
+
// The request has been aborted by user, stop retrying
|
|
42
|
+
if (ctx[SESSION_ABORTED_PROPERTY])
|
|
43
|
+
throw ctx[SESSION_ABORTED_PROPERTY];
|
|
30
44
|
let err = null;
|
|
31
45
|
try {
|
|
32
46
|
ctx.fetchArguments = undefined;
|
|
@@ -39,6 +53,9 @@ export function retryMiddleware() {
|
|
|
39
53
|
catch (e) {
|
|
40
54
|
err = e;
|
|
41
55
|
}
|
|
56
|
+
// The request has been aborted by user, stop retrying
|
|
57
|
+
if (ctx[SESSION_ABORTED_PROPERTY])
|
|
58
|
+
throw ctx[SESSION_ABORTED_PROPERTY];
|
|
42
59
|
if (i === retryTimes - 1) {
|
|
43
60
|
if (err)
|
|
44
61
|
throw err;
|
|
@@ -53,7 +70,7 @@ export function retryMiddleware() {
|
|
|
53
70
|
ctx.retry = { attempt: i, error: err, delay };
|
|
54
71
|
ctx.emitter.emit('retry', ctx);
|
|
55
72
|
if (delay > 0)
|
|
56
|
-
await sleep(delay);
|
|
73
|
+
await sleep(delay, ctx[SESSION_ABORT_CONTROLLER_PROPERTY]?.signal);
|
|
57
74
|
}
|
|
58
75
|
};
|
|
59
76
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ABORT_PROPERTY } from '../constant.js';
|
|
1
2
|
export function timeoutMiddleware() {
|
|
2
3
|
return async function timeoutMiddleware(ctx, next) {
|
|
3
4
|
if (!ctx.options.timeout || ctx.options.timeout.millisecond <= 0) {
|
|
@@ -8,7 +9,8 @@ export function timeoutMiddleware() {
|
|
|
8
9
|
ctx.emitter.on('fetch', (ctx) => {
|
|
9
10
|
setTimeout(() => {
|
|
10
11
|
const err = new DOMException(`keq request timeout(${millisecond}ms)`, 'AbortError');
|
|
11
|
-
|
|
12
|
+
// Only abort the current attempt, so that the retry middleware can retry
|
|
13
|
+
ctx[ABORT_PROPERTY]?.abort(err);
|
|
12
14
|
}, millisecond);
|
|
13
15
|
});
|
|
14
16
|
await next();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ABORT_PROPERTY, OUTPUT_PROPERTY } from '../constant.js';
|
|
1
|
+
import { ABORT_PROPERTY, OUTPUT_PROPERTY, SESSION_ABORTED_PROPERTY, SESSION_ABORT_CONTROLLER_PROPERTY } from '../constant.js';
|
|
2
2
|
import type { Emitter } from 'mitt';
|
|
3
3
|
import type { KeqOptionsParameter } from './keq-options.js';
|
|
4
4
|
import type { KeqEvents } from './keq-events.js';
|
|
@@ -23,6 +23,15 @@ export interface KeqContext {
|
|
|
23
23
|
};
|
|
24
24
|
[ABORT_PROPERTY]?: AbortController;
|
|
25
25
|
abort: (reason: any) => void;
|
|
26
|
+
/**
|
|
27
|
+
* The reason of the request being aborted by user (abort/abortWhen)
|
|
28
|
+
*/
|
|
29
|
+
[SESSION_ABORTED_PROPERTY]?: any;
|
|
30
|
+
/**
|
|
31
|
+
* Aborts when the request is aborted (abort/abortWhen or context.abort()),
|
|
32
|
+
* used by middlewares (e.g. retry) to interrupt pending work
|
|
33
|
+
*/
|
|
34
|
+
[SESSION_ABORT_CONTROLLER_PROPERTY]?: AbortController;
|
|
26
35
|
/**
|
|
27
36
|
* The unique identifier of the request's location in the code
|
|
28
37
|
* @readonly
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { ABORT_PROPERTY, OUTPUT_PROPERTY } from '../constant.js';
|
|
2
|
+
import { ABORT_PROPERTY, OUTPUT_PROPERTY, SESSION_ABORTED_PROPERTY, SESSION_ABORT_CONTROLLER_PROPERTY } from '../constant.js';
|
package/dist/umd/src/constant.js
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
})(function (require, exports) {
|
|
10
10
|
"use strict";
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.ABORT_PROPERTY = exports.OUTPUT_PROPERTY = void 0;
|
|
12
|
+
exports.SESSION_ABORT_CONTROLLER_PROPERTY = exports.SESSION_ABORTED_PROPERTY = exports.ABORT_PROPERTY = exports.OUTPUT_PROPERTY = void 0;
|
|
13
13
|
exports.OUTPUT_PROPERTY = Symbol('outputProperty');
|
|
14
14
|
exports.ABORT_PROPERTY = Symbol('abortProperty');
|
|
15
|
+
exports.SESSION_ABORTED_PROPERTY = Symbol('sessionAbortedProperty');
|
|
16
|
+
exports.SESSION_ABORT_CONTROLLER_PROPERTY = Symbol('sessionAbortControllerProperty');
|
|
15
17
|
});
|
package/dist/umd/src/core.d.ts
CHANGED
|
@@ -12,6 +12,18 @@ export declare class Core<OUTPUT> {
|
|
|
12
12
|
*/
|
|
13
13
|
__identifier__: string;
|
|
14
14
|
private requestPromise?;
|
|
15
|
+
/** Whether abort() has been called on this request. */
|
|
16
|
+
private __aborted__;
|
|
17
|
+
/** The reason passed to abort(). */
|
|
18
|
+
private __abortReason__;
|
|
19
|
+
/** The context of the running attempt, used to abort the in-flight fetch. */
|
|
20
|
+
private __activeContext__?;
|
|
21
|
+
/** Aborts as soon as abort() is called, used to interrupt retry delays. */
|
|
22
|
+
private __sessionAbortController__?;
|
|
23
|
+
/** Cleanup callbacks registered by abortWhen(). */
|
|
24
|
+
private __abortWhenCleanups__;
|
|
25
|
+
/** Whether the request has settled (resolved or rejected). */
|
|
26
|
+
private __settled__;
|
|
15
27
|
protected requestContext: Omit<KeqContextRequest, 'abort' | '__url__'>;
|
|
16
28
|
protected __listeners__: KeqListeners;
|
|
17
29
|
protected __global__: Record<string, any>;
|
|
@@ -22,6 +34,24 @@ export declare class Core<OUTPUT> {
|
|
|
22
34
|
prependMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
23
35
|
appendMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
24
36
|
on<K extends keyof KeqEvents>(event: K, listener: (data: KeqEvents[K]) => void): this;
|
|
37
|
+
/**
|
|
38
|
+
* Abort the request manually.
|
|
39
|
+
*
|
|
40
|
+
* The request rejects with the given reason (an AbortException by default),
|
|
41
|
+
* and no further retry is performed. It is safe to call abort() before the
|
|
42
|
+
* request is sent.
|
|
43
|
+
*
|
|
44
|
+
* @description 手动中止请求
|
|
45
|
+
*/
|
|
46
|
+
abort(reason?: any): void;
|
|
47
|
+
/**
|
|
48
|
+
* Abort the request when the given AbortSignal aborts,
|
|
49
|
+
* or when the given Promise settles (resolves or rejects).
|
|
50
|
+
*
|
|
51
|
+
* @description 当 signal 中止或 promise 完成时终止请求
|
|
52
|
+
*/
|
|
53
|
+
abortWhen(source: AbortSignal | PromiseLike<unknown>): this;
|
|
54
|
+
private __clearAbortWhenCleanups__;
|
|
25
55
|
private run;
|
|
26
56
|
end(): Promise<OUTPUT>;
|
|
27
57
|
/**
|