keq 2.5.4 → 2.6.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/.node-version +1 -0
- package/CHANGELOG.md +21 -0
- package/dist/esm/src/constant.d.ts +1 -0
- package/dist/esm/src/constant.js +1 -0
- package/dist/esm/src/core.d.ts +4 -1
- package/dist/esm/src/core.js +23 -2
- package/dist/esm/src/create-request.js +1 -1
- package/dist/esm/src/index.d.ts +12 -10
- package/dist/esm/src/is/is-url-search-params.js +3 -6
- package/dist/esm/src/keq.js +2 -4
- package/dist/esm/src/middlewares/abort-flow-control-middleware.js +11 -13
- package/dist/esm/src/middlewares/fetch-arguments-middleware.js +7 -1
- package/dist/esm/src/middlewares/fetch-middleware.js +1 -0
- package/dist/esm/src/middlewares/proxy-response-middleware.js +1 -1
- package/dist/esm/src/middlewares/retry-middleware.js +5 -0
- package/dist/esm/src/middlewares/timeout-middleware.js +6 -11
- package/dist/esm/src/types/keq-context.d.ts +17 -6
- package/dist/esm/src/types/keq-context.js +1 -1
- package/dist/esm/src/types/keq-events.d.ts +8 -0
- package/dist/esm/src/types/keq-events.js +1 -0
- package/dist/esm/src/types/keq-flow-control.d.ts +1 -1
- package/dist/esm/src/types/keq-global.d.ts +6 -0
- package/dist/esm/src/types/keq-global.js +1 -0
- package/dist/esm/src/types/keq-middleware.d.ts +2 -2
- package/dist/esm/src/types/keq-options.d.ts +6 -6
- package/dist/esm/src/types/keq-request-init.d.ts +1 -1
- package/dist/esm/src/types/keq-request.d.ts +5 -5
- package/dist/esm/src/types/keq-retry-delay.d.ts +1 -1
- package/dist/esm/src/types/keq-retry-on.d.ts +1 -1
- package/dist/esm/src/types/keq-route.d.ts +1 -1
- package/dist/umd/src/constant.d.ts +1 -0
- package/dist/umd/src/constant.js +2 -1
- package/dist/umd/src/core.d.ts +4 -1
- package/dist/umd/src/core.js +26 -2
- package/dist/umd/src/create-request.js +1 -1
- package/dist/umd/src/index.d.ts +12 -10
- package/dist/umd/src/is/is-url-search-params.js +3 -6
- package/dist/umd/src/keq.js +2 -4
- package/dist/umd/src/middlewares/abort-flow-control-middleware.js +11 -13
- package/dist/umd/src/middlewares/fetch-arguments-middleware.js +8 -2
- package/dist/umd/src/middlewares/fetch-middleware.js +1 -0
- package/dist/umd/src/middlewares/proxy-response-middleware.js +1 -1
- package/dist/umd/src/middlewares/retry-middleware.js +5 -0
- package/dist/umd/src/middlewares/timeout-middleware.js +6 -11
- package/dist/umd/src/types/keq-context.d.ts +17 -6
- package/dist/umd/src/types/keq-context.js +2 -2
- package/dist/umd/src/types/keq-events.d.ts +8 -0
- package/dist/umd/src/types/keq-events.js +12 -0
- package/dist/umd/src/types/keq-flow-control.d.ts +1 -1
- package/dist/umd/src/types/keq-global.d.ts +6 -0
- package/dist/umd/src/types/keq-global.js +12 -0
- package/dist/umd/src/types/keq-middleware.d.ts +2 -2
- package/dist/umd/src/types/keq-options.d.ts +6 -6
- package/dist/umd/src/types/keq-request-init.d.ts +1 -1
- package/dist/umd/src/types/keq-request.d.ts +5 -5
- package/dist/umd/src/types/keq-retry-delay.d.ts +1 -1
- package/dist/umd/src/types/keq-retry-on.d.ts +1 -1
- package/dist/umd/src/types/keq-route.d.ts +1 -1
- package/package.json +2 -1
- package/dist/esm/src/exception/file-expected.exception.d.ts +0 -4
- package/dist/esm/src/exception/file-expected.exception.js +0 -6
- package/dist/umd/src/exception/file-expected.exception.d.ts +0 -4
- package/dist/umd/src/exception/file-expected.exception.js +0 -20
package/.node-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
v20.13.1
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
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.6.0](https://github.com/keq-request/keq/compare/v2.5.5...v2.6.0) (2024-05-28)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* use .on(eventName, listener) add event listener ([500ef14](https://github.com/keq-request/keq/commit/500ef140b513d614c3454d0e9023dd501e5d1ef6))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* esm import syntax ([c312146](https://github.com/keq-request/keq/commit/c312146ffeb456bcfb1e0e6e2f2a3c8c773e6003))
|
|
16
|
+
* the body is undeifned when send plain/text request ([ed24ba6](https://github.com/keq-request/keq/commit/ed24ba6f5ef3a565fb3eb6be496be09ed0fa40f9))
|
|
17
|
+
|
|
18
|
+
## [2.5.5](https://github.com/keq-request/keq/compare/v2.5.4...v2.5.5) (2024-05-26)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* avoid conflicts between flowController and timeout middleware ([a075602](https://github.com/keq-request/keq/commit/a075602ed868812955001df7ed15f2351f899f33))
|
|
24
|
+
* retry timeout and flowControll not triggered ([846c884](https://github.com/keq-request/keq/commit/846c8845334f61fdca7a6cd3b718e135d23bfb18))
|
|
25
|
+
|
|
5
26
|
## [2.5.4](https://github.com/keq-request/keq/compare/v2.5.3...v2.5.4) (2024-05-23)
|
|
6
27
|
|
|
7
28
|
|
package/dist/esm/src/constant.js
CHANGED
package/dist/esm/src/core.d.ts
CHANGED
|
@@ -2,12 +2,14 @@ import { URL } from 'whatwg-url';
|
|
|
2
2
|
import type { KeqContextOptions, KeqRequestContext } from './types/keq-context.js';
|
|
3
3
|
import type { KeqMiddleware } from './types/keq-middleware.js';
|
|
4
4
|
import type { KeqRequestInit } from './types/keq-request-init.js';
|
|
5
|
+
import { KeqEvents, KeqListeners } from './types/keq-events.js';
|
|
5
6
|
/**
|
|
6
7
|
* @description Keq 核心 API,发送请求必要的原子化的API
|
|
7
8
|
*/
|
|
8
9
|
export declare class Core<T> {
|
|
9
10
|
private requestPromise?;
|
|
10
|
-
protected requestContext: KeqRequestContext
|
|
11
|
+
protected requestContext: Omit<KeqRequestContext, 'abort'>;
|
|
12
|
+
protected __listeners__: KeqListeners;
|
|
11
13
|
protected __global__: Record<string, any>;
|
|
12
14
|
protected __prepend_middlewares__: KeqMiddleware[];
|
|
13
15
|
protected __append_middlewares__: KeqMiddleware[];
|
|
@@ -15,6 +17,7 @@ export declare class Core<T> {
|
|
|
15
17
|
constructor(url: (URL | globalThis.URL), init: KeqRequestInit, global?: Record<string, any>);
|
|
16
18
|
prependMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
17
19
|
appendMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
20
|
+
on<K extends keyof KeqEvents>(event: K, listener: (data: KeqEvents[K]) => void): this;
|
|
18
21
|
private run;
|
|
19
22
|
end(): Promise<T>;
|
|
20
23
|
/**
|
package/dist/esm/src/core.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { URL } from 'whatwg-url';
|
|
2
2
|
import { Exception } from "./exception/exception.js";
|
|
3
3
|
import { clone } from "./util/clone.js";
|
|
4
|
-
import { NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from './constant.js';
|
|
4
|
+
import { ABORT_PROPERTY, NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from './constant.js';
|
|
5
5
|
import { composeMiddleware } from './util/compose-middleware.js';
|
|
6
6
|
import { shadowClone } from './util/shadow-clone.js';
|
|
7
|
+
import mitt from 'mitt';
|
|
7
8
|
/**
|
|
8
9
|
* @description Keq 核心 API,发送请求必要的原子化的API
|
|
9
10
|
*/
|
|
10
11
|
export class Core {
|
|
11
12
|
requestPromise;
|
|
12
13
|
requestContext;
|
|
14
|
+
__listeners__ = {};
|
|
13
15
|
__global__;
|
|
14
16
|
__prepend_middlewares__ = [];
|
|
15
17
|
__append_middlewares__ = [];
|
|
@@ -36,6 +38,11 @@ export class Core {
|
|
|
36
38
|
this.__append_middlewares__.unshift(...middlewares);
|
|
37
39
|
return this;
|
|
38
40
|
}
|
|
41
|
+
on(event, listener) {
|
|
42
|
+
this.__listeners__[event] = this.__listeners__[event] || [];
|
|
43
|
+
this.__listeners__[event].push(listener);
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
39
46
|
async run() {
|
|
40
47
|
const headers = new Headers();
|
|
41
48
|
for (const [key, value] of this.requestContext.headers.entries()) {
|
|
@@ -55,15 +62,22 @@ export class Core {
|
|
|
55
62
|
redirect: this.requestContext.redirect,
|
|
56
63
|
referrer: this.requestContext.referrer,
|
|
57
64
|
referrerPolicy: this.requestContext.referrerPolicy,
|
|
58
|
-
signal: this.requestContext.signal,
|
|
59
65
|
};
|
|
60
66
|
const options = shadowClone(this.__options__);
|
|
67
|
+
const emitter = mitt();
|
|
68
|
+
for (const eventName in this.__listeners__) {
|
|
69
|
+
const listeners = this.__listeners__[eventName];
|
|
70
|
+
for (const listener of listeners) {
|
|
71
|
+
emitter.on(eventName, listener);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
61
74
|
const ctx = {
|
|
62
75
|
[NEXT_INVOKED_PROPERTY]: {
|
|
63
76
|
finished: false,
|
|
64
77
|
entryNextTimes: 0,
|
|
65
78
|
outNextTimes: 0,
|
|
66
79
|
},
|
|
80
|
+
emitter,
|
|
67
81
|
request: requestContext,
|
|
68
82
|
options,
|
|
69
83
|
global: this.__global__,
|
|
@@ -73,6 +87,13 @@ export class Core {
|
|
|
73
87
|
set output(value) {
|
|
74
88
|
this[OUTPUT_PROPERTY] = value;
|
|
75
89
|
},
|
|
90
|
+
[ABORT_PROPERTY]: undefined,
|
|
91
|
+
abort(reason) {
|
|
92
|
+
const abortController = this[ABORT_PROPERTY];
|
|
93
|
+
if (abortController) {
|
|
94
|
+
abortController.abort(reason);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
76
97
|
};
|
|
77
98
|
const middleware = composeMiddleware([...this.__prepend_middlewares__, ...this.__append_middlewares__]);
|
|
78
99
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
@@ -21,12 +21,12 @@ export function createRequest(options) {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
const appendMiddlewares = options?.initMiddlewares ? [...options.initMiddlewares] : [
|
|
24
|
+
retryMiddleware(),
|
|
24
25
|
serialFlowControlMiddleware(),
|
|
25
26
|
abortFlowControlMiddleware(),
|
|
26
27
|
timeoutMiddleware(),
|
|
27
28
|
proxyResponseMiddleware(),
|
|
28
29
|
fetchArgumentsMiddleware(),
|
|
29
|
-
retryMiddleware(),
|
|
30
30
|
fetchMiddleware(),
|
|
31
31
|
];
|
|
32
32
|
const prependMiddlewares = [];
|
package/dist/esm/src/index.d.ts
CHANGED
|
@@ -3,16 +3,18 @@ export { Keq } from './keq.js';
|
|
|
3
3
|
export { request } from './request.js';
|
|
4
4
|
export { composeMiddleware } from './util/compose-middleware.js';
|
|
5
5
|
export { composeRoute } from './util/compose-route.js';
|
|
6
|
-
export { KeqContext, KeqContextOptions } from './types/keq-context.js';
|
|
7
|
-
export { KeqMiddleware } from './types/keq-middleware.js';
|
|
8
|
-
export { KeqNext } from './types/keq-next.js';
|
|
9
|
-
export { KeqOptions } from './types/keq-options.js';
|
|
10
|
-
export { KeqRequestBody } from './types/keq-request-body.js';
|
|
11
|
-
export { KeqRequestInit } from './types/keq-request-init.js';
|
|
12
|
-
export { KeqRequest } from './types/keq-request.js';
|
|
13
|
-
export { KeqRetryDelay } from './types/keq-retry-delay.js';
|
|
14
|
-
export { KeqRetryOn } from './types/keq-retry-on.js';
|
|
15
|
-
export { KeqRoute } from './types/keq-route.js';
|
|
6
|
+
export type { KeqContext, KeqContextOptions } from './types/keq-context.js';
|
|
7
|
+
export type { KeqMiddleware } from './types/keq-middleware.js';
|
|
8
|
+
export type { KeqNext } from './types/keq-next.js';
|
|
9
|
+
export type { KeqOptions } from './types/keq-options.js';
|
|
10
|
+
export type { KeqRequestBody } from './types/keq-request-body.js';
|
|
11
|
+
export type { KeqRequestInit } from './types/keq-request-init.js';
|
|
12
|
+
export type { KeqRequest } from './types/keq-request.js';
|
|
13
|
+
export type { KeqRetryDelay } from './types/keq-retry-delay.js';
|
|
14
|
+
export type { KeqRetryOn } from './types/keq-retry-on.js';
|
|
15
|
+
export type { KeqRoute } from './types/keq-route.js';
|
|
16
|
+
export type { KeqGlobal } from './types/keq-global.js';
|
|
17
|
+
export type { KeqEvents } from './types/keq-events.js';
|
|
16
18
|
export { keqHostRoute } from './router/keq-host-route.js';
|
|
17
19
|
export { keqLocationRoute } from './router/keq-location-route.js';
|
|
18
20
|
export { keqMethodRoute } from './router/keq-method-route.js';
|
|
@@ -3,10 +3,10 @@ import { isObject } from './is-object.js';
|
|
|
3
3
|
export function isUrlSearchParams(obj) {
|
|
4
4
|
if (obj instanceof URLSearchParams)
|
|
5
5
|
return true;
|
|
6
|
-
|
|
6
|
+
return (isObject(obj) &&
|
|
7
7
|
isFunction(obj.append) &&
|
|
8
8
|
isFunction(obj.delete) &&
|
|
9
|
-
isFunction(obj.
|
|
9
|
+
isFunction(obj.entries) &&
|
|
10
10
|
isFunction(obj.forEac) &&
|
|
11
11
|
isFunction(obj.get) &&
|
|
12
12
|
isFunction(obj.getAll) &&
|
|
@@ -15,8 +15,5 @@ export function isUrlSearchParams(obj) {
|
|
|
15
15
|
isFunction(obj.set) &&
|
|
16
16
|
isFunction(obj.values) &&
|
|
17
17
|
isFunction(obj.sort) &&
|
|
18
|
-
isFunction(obj.
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
return false;
|
|
18
|
+
isFunction(obj.toString));
|
|
22
19
|
}
|
package/dist/esm/src/keq.js
CHANGED
|
@@ -168,12 +168,10 @@ export class Keq extends Core {
|
|
|
168
168
|
* @param retryDelay Initial value used to calculate the retry in milliseconds (This is still randomized following the randomization factor)
|
|
169
169
|
* @param retryCallback Will be called after request failed
|
|
170
170
|
*/
|
|
171
|
-
retry(retryTimes, retryDelay, retryOn) {
|
|
171
|
+
retry(retryTimes, retryDelay = 0, retryOn = (attempt, error) => !!error) {
|
|
172
172
|
this.option('retryTimes', retryTimes);
|
|
173
173
|
this.option('retryDelay', retryDelay);
|
|
174
|
-
|
|
175
|
-
this.option('retryOn', retryOn);
|
|
176
|
-
}
|
|
174
|
+
this.option('retryOn', retryOn);
|
|
177
175
|
return this;
|
|
178
176
|
}
|
|
179
177
|
redirect(mod) {
|
|
@@ -4,23 +4,21 @@ export function abortFlowControlMiddleware() {
|
|
|
4
4
|
await next();
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
if (ctx.request.signal) {
|
|
8
|
-
console.warn('[keq] request signal had be set manual, abort follow control will not take effect');
|
|
9
|
-
await next();
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
7
|
const { signal } = ctx.options.flowControl;
|
|
13
8
|
const key = typeof signal === 'string' ? signal : signal(ctx);
|
|
14
9
|
if (!ctx.global.abortFlowControl)
|
|
15
10
|
ctx.global.abortFlowControl = {};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
const abort = ctx.global.abortFlowControl[key];
|
|
12
|
+
if (abort) {
|
|
13
|
+
const reason = new DOMException('The previous request was not completed, so keq flowControl abort this request.', 'AbortError');
|
|
14
|
+
abort(reason);
|
|
15
|
+
}
|
|
16
|
+
ctx.global.abortFlowControl[key] = ctx.abort.bind(ctx);
|
|
17
|
+
try {
|
|
18
|
+
await next();
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
ctx.global.abortFlowControl[key] = undefined;
|
|
19
22
|
}
|
|
20
|
-
const abortController = new AbortController();
|
|
21
|
-
ctx.global.abortFlowControl[key] = abortController;
|
|
22
|
-
ctx.request.signal = abortController.signal;
|
|
23
|
-
await next();
|
|
24
|
-
ctx.global.abortFlowControl[key] = undefined;
|
|
25
23
|
};
|
|
26
24
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { URL } from 'whatwg-url';
|
|
2
2
|
import { Exception } from "../exception/exception.js";
|
|
3
3
|
import { compilePathnameTemplate } from "../util/compile-pathname-template.js";
|
|
4
|
+
import { ABORT_PROPERTY } from "../constant.js";
|
|
4
5
|
function compileUrl(obj, routeParams) {
|
|
5
6
|
const url = new URL(typeof obj === 'string' ? obj : obj.href);
|
|
6
7
|
try {
|
|
@@ -62,6 +63,9 @@ function compileBody(ctx) {
|
|
|
62
63
|
request.headers.delete('content-type');
|
|
63
64
|
return form;
|
|
64
65
|
}
|
|
66
|
+
if (body instanceof Buffer)
|
|
67
|
+
return body;
|
|
68
|
+
return String(body);
|
|
65
69
|
}
|
|
66
70
|
export function fetchArgumentsMiddleware() {
|
|
67
71
|
return async function fetchArgumentsMiddleware(ctx, next) {
|
|
@@ -70,6 +74,8 @@ export function fetchArgumentsMiddleware() {
|
|
|
70
74
|
if (!request.headers.has('Content-Type') && request.body) {
|
|
71
75
|
request.headers.set('Content-Type', inferContentTypeByBody(ctx.request.body));
|
|
72
76
|
}
|
|
77
|
+
const abortController = new AbortController();
|
|
78
|
+
ctx[ABORT_PROPERTY] = abortController;
|
|
73
79
|
const requestInit = {
|
|
74
80
|
method: request.method.toUpperCase(),
|
|
75
81
|
headers: request.headers,
|
|
@@ -82,7 +88,7 @@ export function fetchArgumentsMiddleware() {
|
|
|
82
88
|
redirect: request.redirect,
|
|
83
89
|
referrer: request.referrer,
|
|
84
90
|
referrerPolicy: request.referrerPolicy,
|
|
85
|
-
signal:
|
|
91
|
+
signal: abortController.signal,
|
|
86
92
|
};
|
|
87
93
|
ctx.fetchArguments = [url, requestInit];
|
|
88
94
|
await next();
|
|
@@ -8,6 +8,7 @@ export function fetchMiddleware() {
|
|
|
8
8
|
if (!fetchArguments) {
|
|
9
9
|
throw new Exception('fetchArguments is required');
|
|
10
10
|
}
|
|
11
|
+
ctx.emitter.emit('fetch', ctx);
|
|
11
12
|
const fetch = ctx.options.fetchAPI || globalThis.fetch;
|
|
12
13
|
const response = await fetch(...fetchArguments);
|
|
13
14
|
ctx.res = response;
|
|
@@ -2,7 +2,7 @@ export function proxyResponseMiddleware() {
|
|
|
2
2
|
return async function proxyResponseMiddleware(ctx, next) {
|
|
3
3
|
await next();
|
|
4
4
|
const res = ctx.res;
|
|
5
|
-
if (res
|
|
5
|
+
if (res) {
|
|
6
6
|
ctx.response = new Proxy(res, {
|
|
7
7
|
get(res, prop) {
|
|
8
8
|
if (typeof prop === 'string') {
|
|
@@ -29,6 +29,9 @@ export function retryMiddleware() {
|
|
|
29
29
|
for (let i = 0; i < retryTimes; i++) {
|
|
30
30
|
let err = null;
|
|
31
31
|
try {
|
|
32
|
+
ctx.fetchArguments = undefined;
|
|
33
|
+
ctx.response = undefined;
|
|
34
|
+
ctx.req = undefined;
|
|
32
35
|
ctx[NEXT_INVOKED_PROPERTY].entryNextTimes = 0;
|
|
33
36
|
ctx[NEXT_INVOKED_PROPERTY].outNextTimes = 0;
|
|
34
37
|
await next();
|
|
@@ -47,6 +50,8 @@ export function retryMiddleware() {
|
|
|
47
50
|
break;
|
|
48
51
|
}
|
|
49
52
|
const delay = await retryDelay(i, err, ctx);
|
|
53
|
+
ctx.retry = { attempt: i, error: err, delay };
|
|
54
|
+
ctx.emitter.emit('retry', ctx);
|
|
50
55
|
if (delay > 0)
|
|
51
56
|
await sleep(delay);
|
|
52
57
|
}
|
|
@@ -4,18 +4,13 @@ export function timeoutMiddleware() {
|
|
|
4
4
|
await next();
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
if (ctx.request.signal) {
|
|
8
|
-
console.warn('[keq] request signal had be set manual, abort follow control will not take effect');
|
|
9
|
-
await next();
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
const timeoutSignal = new AbortController();
|
|
13
|
-
ctx.request.signal = timeoutSignal.signal;
|
|
14
7
|
const millisecond = ctx.options.timeout.millisecond;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
ctx.emitter.on('fetch', (ctx) => {
|
|
9
|
+
setTimeout(() => {
|
|
10
|
+
const err = new DOMException(`keq request timeout(${millisecond}ms)`, 'AbortError');
|
|
11
|
+
ctx.abort(err);
|
|
12
|
+
}, millisecond);
|
|
13
|
+
});
|
|
19
14
|
await next();
|
|
20
15
|
};
|
|
21
16
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { Emitter } from 'mitt';
|
|
1
2
|
import { URL } from 'whatwg-url';
|
|
2
|
-
import { NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from "../constant";
|
|
3
|
-
import { KeqRequestBody } from './keq-request-body';
|
|
4
|
-
import { KeqRequestMethod } from './keq-request-method';
|
|
5
|
-
import { KeqOptionsParameter } from './keq-options.js';
|
|
3
|
+
import { ABORT_PROPERTY, NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from "../constant.js";
|
|
4
|
+
import type { KeqRequestBody } from './keq-request-body.js';
|
|
5
|
+
import type { KeqRequestMethod } from './keq-request-method.js';
|
|
6
|
+
import type { KeqOptionsParameter } from './keq-options.js';
|
|
7
|
+
import type { KeqEvents } from './keq-events.js';
|
|
8
|
+
import type { KeqGlobal } from './keq-global.js';
|
|
6
9
|
export interface KeqContextOptions extends KeqOptionsParameter {
|
|
7
10
|
[key: string]: any;
|
|
8
11
|
}
|
|
@@ -20,7 +23,6 @@ export interface KeqRequestContext {
|
|
|
20
23
|
redirect?: RequestRedirect;
|
|
21
24
|
referrer?: string;
|
|
22
25
|
referrerPolicy?: ReferrerPolicy;
|
|
23
|
-
signal?: AbortSignal | null;
|
|
24
26
|
}
|
|
25
27
|
export interface KeqContext {
|
|
26
28
|
/**
|
|
@@ -34,6 +36,9 @@ export interface KeqContext {
|
|
|
34
36
|
entryNextTimes: number;
|
|
35
37
|
outNextTimes: number;
|
|
36
38
|
};
|
|
39
|
+
[ABORT_PROPERTY]?: AbortController;
|
|
40
|
+
abort: (reason: any) => void;
|
|
41
|
+
emitter: Emitter<Omit<KeqEvents, never>>;
|
|
37
42
|
options: KeqContextOptions;
|
|
38
43
|
/**
|
|
39
44
|
* Fetch API Arguments
|
|
@@ -51,7 +56,13 @@ export interface KeqContext {
|
|
|
51
56
|
output: any;
|
|
52
57
|
[OUTPUT_PROPERTY]?: any;
|
|
53
58
|
/** share data between requests */
|
|
54
|
-
global:
|
|
59
|
+
global: KeqGlobal;
|
|
60
|
+
/** retry information, undefined is no retry */
|
|
61
|
+
retry?: {
|
|
62
|
+
attempt: number;
|
|
63
|
+
error: unknown | null;
|
|
64
|
+
delay: number;
|
|
65
|
+
};
|
|
55
66
|
/** extends by middleware */
|
|
56
67
|
[key: string]: any;
|
|
57
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from "../constant";
|
|
1
|
+
import { ABORT_PROPERTY, NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from "../constant.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { queueAsPromised } from 'fastq';
|
|
2
|
+
import type { KeqNext } from './keq-next.js';
|
|
3
|
+
export interface KeqGlobal {
|
|
4
|
+
abortFlowControl?: Record<string, ((reason: any) => void) | undefined>;
|
|
5
|
+
serialFlowControl?: Record<string, queueAsPromised<KeqNext, void>>;
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context';
|
|
2
|
-
import { KeqNext } from './keq-next';
|
|
1
|
+
import type { KeqContext } from './keq-context.js';
|
|
2
|
+
import type { KeqNext } from './keq-next.js';
|
|
3
3
|
export type KeqMiddleware = (ctx: KeqContext, next: KeqNext) => Promise<void>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Keq } from "../keq.js";
|
|
2
|
-
import { KeqFlowControl } from './keq-flow-control.js';
|
|
3
|
-
import { KeqResolveMethod } from './keq-resolve-with-mode.js';
|
|
4
|
-
import { KeqRetryDelay } from './keq-retry-delay';
|
|
5
|
-
import { KeqRetryOn } from './keq-retry-on';
|
|
6
|
-
import { KeqTimeout } from './keq-timeout.js';
|
|
1
|
+
import type { Keq } from "../keq.js";
|
|
2
|
+
import type { KeqFlowControl } from './keq-flow-control.js';
|
|
3
|
+
import type { KeqResolveMethod } from './keq-resolve-with-mode.js';
|
|
4
|
+
import type { KeqRetryDelay } from './keq-retry-delay.js';
|
|
5
|
+
import type { KeqRetryOn } from './keq-retry-on.js';
|
|
6
|
+
import type { KeqTimeout } from './keq-timeout.js';
|
|
7
7
|
export interface KeqOptions<T> {
|
|
8
8
|
/**
|
|
9
9
|
* replace the default fetch api
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqRequestContext } from './keq-context';
|
|
1
|
+
import type { KeqRequestContext } from './keq-context.js';
|
|
2
2
|
export type KeqRequestInit = Partial<Omit<KeqRequestContext, 'url'>>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { URL } from 'whatwg-url';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { KeqMiddleware } from './keq-middleware';
|
|
5
|
-
import { KeqRequestInit } from './keq-request-init';
|
|
1
|
+
import type { URL } from 'whatwg-url';
|
|
2
|
+
import type { KeqRouter } from "../router/keq-router.js";
|
|
3
|
+
import type { Keq } from "../keq.js";
|
|
4
|
+
import type { KeqMiddleware } from './keq-middleware.js';
|
|
5
|
+
import type { KeqRequestInit } from './keq-request-init.js';
|
|
6
6
|
type KeqRequestFn = <T = any>(url: string | URL | globalThis.URL) => Keq<T>;
|
|
7
7
|
type GlobalURL = globalThis.URL;
|
|
8
8
|
export interface KeqRequest {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context';
|
|
1
|
+
import type { KeqContext } from './keq-context';
|
|
2
2
|
export type KeqRetryDelay = number | ((attempt: number, error: unknown | null, ctx: KeqContext) => number | Promise<number>);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context';
|
|
1
|
+
import type { KeqContext } from './keq-context.js';
|
|
2
2
|
export type KeqRetryOn = (attempt: number, error: unknown | null, ctx: KeqContext) => (boolean | Promise<boolean>);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context.js';
|
|
1
|
+
import type { KeqContext } from './keq-context.js';
|
|
2
2
|
export type KeqRoute = (ctx: KeqContext) => Promise<boolean> | boolean;
|
package/dist/umd/src/constant.js
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
})(function (require, exports) {
|
|
10
10
|
"use strict";
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.NEXT_INVOKED_PROPERTY = exports.OUTPUT_PROPERTY = void 0;
|
|
12
|
+
exports.ABORT_PROPERTY = exports.NEXT_INVOKED_PROPERTY = exports.OUTPUT_PROPERTY = void 0;
|
|
13
13
|
exports.OUTPUT_PROPERTY = Symbol('outputProperty');
|
|
14
14
|
exports.NEXT_INVOKED_PROPERTY = Symbol('nextInvokedProperty');
|
|
15
|
+
exports.ABORT_PROPERTY = Symbol('abortProperty');
|
|
15
16
|
});
|
package/dist/umd/src/core.d.ts
CHANGED
|
@@ -2,12 +2,14 @@ import { URL } from 'whatwg-url';
|
|
|
2
2
|
import type { KeqContextOptions, KeqRequestContext } from './types/keq-context.js';
|
|
3
3
|
import type { KeqMiddleware } from './types/keq-middleware.js';
|
|
4
4
|
import type { KeqRequestInit } from './types/keq-request-init.js';
|
|
5
|
+
import { KeqEvents, KeqListeners } from './types/keq-events.js';
|
|
5
6
|
/**
|
|
6
7
|
* @description Keq 核心 API,发送请求必要的原子化的API
|
|
7
8
|
*/
|
|
8
9
|
export declare class Core<T> {
|
|
9
10
|
private requestPromise?;
|
|
10
|
-
protected requestContext: KeqRequestContext
|
|
11
|
+
protected requestContext: Omit<KeqRequestContext, 'abort'>;
|
|
12
|
+
protected __listeners__: KeqListeners;
|
|
11
13
|
protected __global__: Record<string, any>;
|
|
12
14
|
protected __prepend_middlewares__: KeqMiddleware[];
|
|
13
15
|
protected __append_middlewares__: KeqMiddleware[];
|
|
@@ -15,6 +17,7 @@ export declare class Core<T> {
|
|
|
15
17
|
constructor(url: (URL | globalThis.URL), init: KeqRequestInit, global?: Record<string, any>);
|
|
16
18
|
prependMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
17
19
|
appendMiddlewares(...middlewares: KeqMiddleware[]): this;
|
|
20
|
+
on<K extends keyof KeqEvents>(event: K, listener: (data: KeqEvents[K]) => void): this;
|
|
18
21
|
private run;
|
|
19
22
|
end(): Promise<T>;
|
|
20
23
|
/**
|
package/dist/umd/src/core.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
2
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
3
|
+
};
|
|
1
4
|
(function (factory) {
|
|
2
5
|
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
6
|
var v = factory(require, exports);
|
|
4
7
|
if (v !== undefined) module.exports = v;
|
|
5
8
|
}
|
|
6
9
|
else if (typeof define === "function" && define.amd) {
|
|
7
|
-
define(["require", "exports", "whatwg-url", "./exception/exception.js", "./util/clone.js", "./constant.js", "./util/compose-middleware.js", "./util/shadow-clone.js"], factory);
|
|
10
|
+
define(["require", "exports", "whatwg-url", "./exception/exception.js", "./util/clone.js", "./constant.js", "./util/compose-middleware.js", "./util/shadow-clone.js", "mitt"], factory);
|
|
8
11
|
}
|
|
9
12
|
})(function (require, exports) {
|
|
10
13
|
"use strict";
|
|
@@ -16,12 +19,14 @@
|
|
|
16
19
|
const constant_js_1 = require("./constant.js");
|
|
17
20
|
const compose_middleware_js_1 = require("./util/compose-middleware.js");
|
|
18
21
|
const shadow_clone_js_1 = require("./util/shadow-clone.js");
|
|
22
|
+
const mitt_1 = __importDefault(require("mitt"));
|
|
19
23
|
/**
|
|
20
24
|
* @description Keq 核心 API,发送请求必要的原子化的API
|
|
21
25
|
*/
|
|
22
26
|
class Core {
|
|
23
27
|
requestPromise;
|
|
24
28
|
requestContext;
|
|
29
|
+
__listeners__ = {};
|
|
25
30
|
__global__;
|
|
26
31
|
__prepend_middlewares__ = [];
|
|
27
32
|
__append_middlewares__ = [];
|
|
@@ -48,6 +53,11 @@
|
|
|
48
53
|
this.__append_middlewares__.unshift(...middlewares);
|
|
49
54
|
return this;
|
|
50
55
|
}
|
|
56
|
+
on(event, listener) {
|
|
57
|
+
this.__listeners__[event] = this.__listeners__[event] || [];
|
|
58
|
+
this.__listeners__[event].push(listener);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
51
61
|
async run() {
|
|
52
62
|
const headers = new Headers();
|
|
53
63
|
for (const [key, value] of this.requestContext.headers.entries()) {
|
|
@@ -67,15 +77,22 @@
|
|
|
67
77
|
redirect: this.requestContext.redirect,
|
|
68
78
|
referrer: this.requestContext.referrer,
|
|
69
79
|
referrerPolicy: this.requestContext.referrerPolicy,
|
|
70
|
-
signal: this.requestContext.signal,
|
|
71
80
|
};
|
|
72
81
|
const options = (0, shadow_clone_js_1.shadowClone)(this.__options__);
|
|
82
|
+
const emitter = (0, mitt_1.default)();
|
|
83
|
+
for (const eventName in this.__listeners__) {
|
|
84
|
+
const listeners = this.__listeners__[eventName];
|
|
85
|
+
for (const listener of listeners) {
|
|
86
|
+
emitter.on(eventName, listener);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
73
89
|
const ctx = {
|
|
74
90
|
[constant_js_1.NEXT_INVOKED_PROPERTY]: {
|
|
75
91
|
finished: false,
|
|
76
92
|
entryNextTimes: 0,
|
|
77
93
|
outNextTimes: 0,
|
|
78
94
|
},
|
|
95
|
+
emitter,
|
|
79
96
|
request: requestContext,
|
|
80
97
|
options,
|
|
81
98
|
global: this.__global__,
|
|
@@ -85,6 +102,13 @@
|
|
|
85
102
|
set output(value) {
|
|
86
103
|
this[constant_js_1.OUTPUT_PROPERTY] = value;
|
|
87
104
|
},
|
|
105
|
+
[constant_js_1.ABORT_PROPERTY]: undefined,
|
|
106
|
+
abort(reason) {
|
|
107
|
+
const abortController = this[constant_js_1.ABORT_PROPERTY];
|
|
108
|
+
if (abortController) {
|
|
109
|
+
abortController.abort(reason);
|
|
110
|
+
}
|
|
111
|
+
},
|
|
88
112
|
};
|
|
89
113
|
const middleware = (0, compose_middleware_js_1.composeMiddleware)([...this.__prepend_middlewares__, ...this.__append_middlewares__]);
|
|
90
114
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
const appendMiddlewares = options?.initMiddlewares ? [...options.initMiddlewares] : [
|
|
36
|
+
(0, retry_middleware_js_1.retryMiddleware)(),
|
|
36
37
|
(0, serial_flow_control_middleware_js_1.serialFlowControlMiddleware)(),
|
|
37
38
|
(0, abort_flow_control_middleware_js_1.abortFlowControlMiddleware)(),
|
|
38
39
|
(0, timeout_middleware_js_1.timeoutMiddleware)(),
|
|
39
40
|
(0, proxy_response_middleware_js_1.proxyResponseMiddleware)(),
|
|
40
41
|
(0, fetch_arguments_middleware_js_1.fetchArgumentsMiddleware)(),
|
|
41
|
-
(0, retry_middleware_js_1.retryMiddleware)(),
|
|
42
42
|
(0, fetch_middleware_js_1.fetchMiddleware)(),
|
|
43
43
|
];
|
|
44
44
|
const prependMiddlewares = [];
|
package/dist/umd/src/index.d.ts
CHANGED
|
@@ -3,16 +3,18 @@ export { Keq } from './keq.js';
|
|
|
3
3
|
export { request } from './request.js';
|
|
4
4
|
export { composeMiddleware } from './util/compose-middleware.js';
|
|
5
5
|
export { composeRoute } from './util/compose-route.js';
|
|
6
|
-
export { KeqContext, KeqContextOptions } from './types/keq-context.js';
|
|
7
|
-
export { KeqMiddleware } from './types/keq-middleware.js';
|
|
8
|
-
export { KeqNext } from './types/keq-next.js';
|
|
9
|
-
export { KeqOptions } from './types/keq-options.js';
|
|
10
|
-
export { KeqRequestBody } from './types/keq-request-body.js';
|
|
11
|
-
export { KeqRequestInit } from './types/keq-request-init.js';
|
|
12
|
-
export { KeqRequest } from './types/keq-request.js';
|
|
13
|
-
export { KeqRetryDelay } from './types/keq-retry-delay.js';
|
|
14
|
-
export { KeqRetryOn } from './types/keq-retry-on.js';
|
|
15
|
-
export { KeqRoute } from './types/keq-route.js';
|
|
6
|
+
export type { KeqContext, KeqContextOptions } from './types/keq-context.js';
|
|
7
|
+
export type { KeqMiddleware } from './types/keq-middleware.js';
|
|
8
|
+
export type { KeqNext } from './types/keq-next.js';
|
|
9
|
+
export type { KeqOptions } from './types/keq-options.js';
|
|
10
|
+
export type { KeqRequestBody } from './types/keq-request-body.js';
|
|
11
|
+
export type { KeqRequestInit } from './types/keq-request-init.js';
|
|
12
|
+
export type { KeqRequest } from './types/keq-request.js';
|
|
13
|
+
export type { KeqRetryDelay } from './types/keq-retry-delay.js';
|
|
14
|
+
export type { KeqRetryOn } from './types/keq-retry-on.js';
|
|
15
|
+
export type { KeqRoute } from './types/keq-route.js';
|
|
16
|
+
export type { KeqGlobal } from './types/keq-global.js';
|
|
17
|
+
export type { KeqEvents } from './types/keq-events.js';
|
|
16
18
|
export { keqHostRoute } from './router/keq-host-route.js';
|
|
17
19
|
export { keqLocationRoute } from './router/keq-location-route.js';
|
|
18
20
|
export { keqMethodRoute } from './router/keq-method-route.js';
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
function isUrlSearchParams(obj) {
|
|
16
16
|
if (obj instanceof URLSearchParams)
|
|
17
17
|
return true;
|
|
18
|
-
|
|
18
|
+
return ((0, is_object_js_1.isObject)(obj) &&
|
|
19
19
|
(0, is_function_js_1.isFunction)(obj.append) &&
|
|
20
20
|
(0, is_function_js_1.isFunction)(obj.delete) &&
|
|
21
|
-
(0, is_function_js_1.isFunction)(obj.
|
|
21
|
+
(0, is_function_js_1.isFunction)(obj.entries) &&
|
|
22
22
|
(0, is_function_js_1.isFunction)(obj.forEac) &&
|
|
23
23
|
(0, is_function_js_1.isFunction)(obj.get) &&
|
|
24
24
|
(0, is_function_js_1.isFunction)(obj.getAll) &&
|
|
@@ -27,10 +27,7 @@
|
|
|
27
27
|
(0, is_function_js_1.isFunction)(obj.set) &&
|
|
28
28
|
(0, is_function_js_1.isFunction)(obj.values) &&
|
|
29
29
|
(0, is_function_js_1.isFunction)(obj.sort) &&
|
|
30
|
-
(0, is_function_js_1.isFunction)(obj.
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
30
|
+
(0, is_function_js_1.isFunction)(obj.toString));
|
|
34
31
|
}
|
|
35
32
|
exports.isUrlSearchParams = isUrlSearchParams;
|
|
36
33
|
});
|
package/dist/umd/src/keq.js
CHANGED
|
@@ -180,12 +180,10 @@
|
|
|
180
180
|
* @param retryDelay Initial value used to calculate the retry in milliseconds (This is still randomized following the randomization factor)
|
|
181
181
|
* @param retryCallback Will be called after request failed
|
|
182
182
|
*/
|
|
183
|
-
retry(retryTimes, retryDelay, retryOn) {
|
|
183
|
+
retry(retryTimes, retryDelay = 0, retryOn = (attempt, error) => !!error) {
|
|
184
184
|
this.option('retryTimes', retryTimes);
|
|
185
185
|
this.option('retryDelay', retryDelay);
|
|
186
|
-
|
|
187
|
-
this.option('retryOn', retryOn);
|
|
188
|
-
}
|
|
186
|
+
this.option('retryOn', retryOn);
|
|
189
187
|
return this;
|
|
190
188
|
}
|
|
191
189
|
redirect(mod) {
|
|
@@ -16,24 +16,22 @@
|
|
|
16
16
|
await next();
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
if (ctx.request.signal) {
|
|
20
|
-
console.warn('[keq] request signal had be set manual, abort follow control will not take effect');
|
|
21
|
-
await next();
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
19
|
const { signal } = ctx.options.flowControl;
|
|
25
20
|
const key = typeof signal === 'string' ? signal : signal(ctx);
|
|
26
21
|
if (!ctx.global.abortFlowControl)
|
|
27
22
|
ctx.global.abortFlowControl = {};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
const abort = ctx.global.abortFlowControl[key];
|
|
24
|
+
if (abort) {
|
|
25
|
+
const reason = new DOMException('The previous request was not completed, so keq flowControl abort this request.', 'AbortError');
|
|
26
|
+
abort(reason);
|
|
27
|
+
}
|
|
28
|
+
ctx.global.abortFlowControl[key] = ctx.abort.bind(ctx);
|
|
29
|
+
try {
|
|
30
|
+
await next();
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
ctx.global.abortFlowControl[key] = undefined;
|
|
31
34
|
}
|
|
32
|
-
const abortController = new AbortController();
|
|
33
|
-
ctx.global.abortFlowControl[key] = abortController;
|
|
34
|
-
ctx.request.signal = abortController.signal;
|
|
35
|
-
await next();
|
|
36
|
-
ctx.global.abortFlowControl[key] = undefined;
|
|
37
35
|
};
|
|
38
36
|
}
|
|
39
37
|
exports.abortFlowControlMiddleware = abortFlowControlMiddleware;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
if (v !== undefined) module.exports = v;
|
|
5
5
|
}
|
|
6
6
|
else if (typeof define === "function" && define.amd) {
|
|
7
|
-
define(["require", "exports", "whatwg-url", "../exception/exception.js", "../util/compile-pathname-template.js"], factory);
|
|
7
|
+
define(["require", "exports", "whatwg-url", "../exception/exception.js", "../util/compile-pathname-template.js", "../constant.js"], factory);
|
|
8
8
|
}
|
|
9
9
|
})(function (require, exports) {
|
|
10
10
|
"use strict";
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
const whatwg_url_1 = require("whatwg-url");
|
|
14
14
|
const exception_js_1 = require("../exception/exception.js");
|
|
15
15
|
const compile_pathname_template_js_1 = require("../util/compile-pathname-template.js");
|
|
16
|
+
const constant_js_1 = require("../constant.js");
|
|
16
17
|
function compileUrl(obj, routeParams) {
|
|
17
18
|
const url = new whatwg_url_1.URL(typeof obj === 'string' ? obj : obj.href);
|
|
18
19
|
try {
|
|
@@ -74,6 +75,9 @@
|
|
|
74
75
|
request.headers.delete('content-type');
|
|
75
76
|
return form;
|
|
76
77
|
}
|
|
78
|
+
if (body instanceof Buffer)
|
|
79
|
+
return body;
|
|
80
|
+
return String(body);
|
|
77
81
|
}
|
|
78
82
|
function fetchArgumentsMiddleware() {
|
|
79
83
|
return async function fetchArgumentsMiddleware(ctx, next) {
|
|
@@ -82,6 +86,8 @@
|
|
|
82
86
|
if (!request.headers.has('Content-Type') && request.body) {
|
|
83
87
|
request.headers.set('Content-Type', inferContentTypeByBody(ctx.request.body));
|
|
84
88
|
}
|
|
89
|
+
const abortController = new AbortController();
|
|
90
|
+
ctx[constant_js_1.ABORT_PROPERTY] = abortController;
|
|
85
91
|
const requestInit = {
|
|
86
92
|
method: request.method.toUpperCase(),
|
|
87
93
|
headers: request.headers,
|
|
@@ -94,7 +100,7 @@
|
|
|
94
100
|
redirect: request.redirect,
|
|
95
101
|
referrer: request.referrer,
|
|
96
102
|
referrerPolicy: request.referrerPolicy,
|
|
97
|
-
signal:
|
|
103
|
+
signal: abortController.signal,
|
|
98
104
|
};
|
|
99
105
|
ctx.fetchArguments = [url, requestInit];
|
|
100
106
|
await next();
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
if (!fetchArguments) {
|
|
21
21
|
throw new exception_js_1.Exception('fetchArguments is required');
|
|
22
22
|
}
|
|
23
|
+
ctx.emitter.emit('fetch', ctx);
|
|
23
24
|
const fetch = ctx.options.fetchAPI || globalThis.fetch;
|
|
24
25
|
const response = await fetch(...fetchArguments);
|
|
25
26
|
ctx.res = response;
|
|
@@ -41,6 +41,9 @@
|
|
|
41
41
|
for (let i = 0; i < retryTimes; i++) {
|
|
42
42
|
let err = null;
|
|
43
43
|
try {
|
|
44
|
+
ctx.fetchArguments = undefined;
|
|
45
|
+
ctx.response = undefined;
|
|
46
|
+
ctx.req = undefined;
|
|
44
47
|
ctx[constant_js_1.NEXT_INVOKED_PROPERTY].entryNextTimes = 0;
|
|
45
48
|
ctx[constant_js_1.NEXT_INVOKED_PROPERTY].outNextTimes = 0;
|
|
46
49
|
await next();
|
|
@@ -59,6 +62,8 @@
|
|
|
59
62
|
break;
|
|
60
63
|
}
|
|
61
64
|
const delay = await retryDelay(i, err, ctx);
|
|
65
|
+
ctx.retry = { attempt: i, error: err, delay };
|
|
66
|
+
ctx.emitter.emit('retry', ctx);
|
|
62
67
|
if (delay > 0)
|
|
63
68
|
await sleep(delay);
|
|
64
69
|
}
|
|
@@ -16,18 +16,13 @@
|
|
|
16
16
|
await next();
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
if (ctx.request.signal) {
|
|
20
|
-
console.warn('[keq] request signal had be set manual, abort follow control will not take effect');
|
|
21
|
-
await next();
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const timeoutSignal = new AbortController();
|
|
25
|
-
ctx.request.signal = timeoutSignal.signal;
|
|
26
19
|
const millisecond = ctx.options.timeout.millisecond;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
ctx.emitter.on('fetch', (ctx) => {
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
const err = new DOMException(`keq request timeout(${millisecond}ms)`, 'AbortError');
|
|
23
|
+
ctx.abort(err);
|
|
24
|
+
}, millisecond);
|
|
25
|
+
});
|
|
31
26
|
await next();
|
|
32
27
|
};
|
|
33
28
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { Emitter } from 'mitt';
|
|
1
2
|
import { URL } from 'whatwg-url';
|
|
2
|
-
import { NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from "../constant";
|
|
3
|
-
import { KeqRequestBody } from './keq-request-body';
|
|
4
|
-
import { KeqRequestMethod } from './keq-request-method';
|
|
5
|
-
import { KeqOptionsParameter } from './keq-options.js';
|
|
3
|
+
import { ABORT_PROPERTY, NEXT_INVOKED_PROPERTY, OUTPUT_PROPERTY } from "../constant.js";
|
|
4
|
+
import type { KeqRequestBody } from './keq-request-body.js';
|
|
5
|
+
import type { KeqRequestMethod } from './keq-request-method.js';
|
|
6
|
+
import type { KeqOptionsParameter } from './keq-options.js';
|
|
7
|
+
import type { KeqEvents } from './keq-events.js';
|
|
8
|
+
import type { KeqGlobal } from './keq-global.js';
|
|
6
9
|
export interface KeqContextOptions extends KeqOptionsParameter {
|
|
7
10
|
[key: string]: any;
|
|
8
11
|
}
|
|
@@ -20,7 +23,6 @@ export interface KeqRequestContext {
|
|
|
20
23
|
redirect?: RequestRedirect;
|
|
21
24
|
referrer?: string;
|
|
22
25
|
referrerPolicy?: ReferrerPolicy;
|
|
23
|
-
signal?: AbortSignal | null;
|
|
24
26
|
}
|
|
25
27
|
export interface KeqContext {
|
|
26
28
|
/**
|
|
@@ -34,6 +36,9 @@ export interface KeqContext {
|
|
|
34
36
|
entryNextTimes: number;
|
|
35
37
|
outNextTimes: number;
|
|
36
38
|
};
|
|
39
|
+
[ABORT_PROPERTY]?: AbortController;
|
|
40
|
+
abort: (reason: any) => void;
|
|
41
|
+
emitter: Emitter<Omit<KeqEvents, never>>;
|
|
37
42
|
options: KeqContextOptions;
|
|
38
43
|
/**
|
|
39
44
|
* Fetch API Arguments
|
|
@@ -51,7 +56,13 @@ export interface KeqContext {
|
|
|
51
56
|
output: any;
|
|
52
57
|
[OUTPUT_PROPERTY]?: any;
|
|
53
58
|
/** share data between requests */
|
|
54
|
-
global:
|
|
59
|
+
global: KeqGlobal;
|
|
60
|
+
/** retry information, undefined is no retry */
|
|
61
|
+
retry?: {
|
|
62
|
+
attempt: number;
|
|
63
|
+
error: unknown | null;
|
|
64
|
+
delay: number;
|
|
65
|
+
};
|
|
55
66
|
/** extends by middleware */
|
|
56
67
|
[key: string]: any;
|
|
57
68
|
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
if (v !== undefined) module.exports = v;
|
|
5
5
|
}
|
|
6
6
|
else if (typeof define === "function" && define.amd) {
|
|
7
|
-
define(["require", "exports", "../constant"], factory);
|
|
7
|
+
define(["require", "exports", "../constant.js"], factory);
|
|
8
8
|
}
|
|
9
9
|
})(function (require, exports) {
|
|
10
10
|
"use strict";
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const
|
|
12
|
+
const constant_js_1 = require("../constant.js");
|
|
13
13
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { queueAsPromised } from 'fastq';
|
|
2
|
+
import type { KeqNext } from './keq-next.js';
|
|
3
|
+
export interface KeqGlobal {
|
|
4
|
+
abortFlowControl?: Record<string, ((reason: any) => void) | undefined>;
|
|
5
|
+
serialFlowControl?: Record<string, queueAsPromised<KeqNext, void>>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context';
|
|
2
|
-
import { KeqNext } from './keq-next';
|
|
1
|
+
import type { KeqContext } from './keq-context.js';
|
|
2
|
+
import type { KeqNext } from './keq-next.js';
|
|
3
3
|
export type KeqMiddleware = (ctx: KeqContext, next: KeqNext) => Promise<void>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Keq } from "../keq.js";
|
|
2
|
-
import { KeqFlowControl } from './keq-flow-control.js';
|
|
3
|
-
import { KeqResolveMethod } from './keq-resolve-with-mode.js';
|
|
4
|
-
import { KeqRetryDelay } from './keq-retry-delay';
|
|
5
|
-
import { KeqRetryOn } from './keq-retry-on';
|
|
6
|
-
import { KeqTimeout } from './keq-timeout.js';
|
|
1
|
+
import type { Keq } from "../keq.js";
|
|
2
|
+
import type { KeqFlowControl } from './keq-flow-control.js';
|
|
3
|
+
import type { KeqResolveMethod } from './keq-resolve-with-mode.js';
|
|
4
|
+
import type { KeqRetryDelay } from './keq-retry-delay.js';
|
|
5
|
+
import type { KeqRetryOn } from './keq-retry-on.js';
|
|
6
|
+
import type { KeqTimeout } from './keq-timeout.js';
|
|
7
7
|
export interface KeqOptions<T> {
|
|
8
8
|
/**
|
|
9
9
|
* replace the default fetch api
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqRequestContext } from './keq-context';
|
|
1
|
+
import type { KeqRequestContext } from './keq-context.js';
|
|
2
2
|
export type KeqRequestInit = Partial<Omit<KeqRequestContext, 'url'>>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { URL } from 'whatwg-url';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { KeqMiddleware } from './keq-middleware';
|
|
5
|
-
import { KeqRequestInit } from './keq-request-init';
|
|
1
|
+
import type { URL } from 'whatwg-url';
|
|
2
|
+
import type { KeqRouter } from "../router/keq-router.js";
|
|
3
|
+
import type { Keq } from "../keq.js";
|
|
4
|
+
import type { KeqMiddleware } from './keq-middleware.js';
|
|
5
|
+
import type { KeqRequestInit } from './keq-request-init.js';
|
|
6
6
|
type KeqRequestFn = <T = any>(url: string | URL | globalThis.URL) => Keq<T>;
|
|
7
7
|
type GlobalURL = globalThis.URL;
|
|
8
8
|
export interface KeqRequest {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context';
|
|
1
|
+
import type { KeqContext } from './keq-context';
|
|
2
2
|
export type KeqRetryDelay = number | ((attempt: number, error: unknown | null, ctx: KeqContext) => number | Promise<number>);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context';
|
|
1
|
+
import type { KeqContext } from './keq-context.js';
|
|
2
2
|
export type KeqRetryOn = (attempt: number, error: unknown | null, ctx: KeqContext) => (boolean | Promise<boolean>);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { KeqContext } from './keq-context.js';
|
|
1
|
+
import type { KeqContext } from './keq-context.js';
|
|
2
2
|
export type KeqRoute = (ctx: KeqContext) => Promise<boolean> | boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keq",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Request API write by Typescript for flexibility, readability, and a low learning curve.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"request",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"clone": "^2.1.2",
|
|
45
45
|
"fastq": "^1.17.1",
|
|
46
46
|
"minimatch": "^9.0.4",
|
|
47
|
+
"mitt": "^3.0.1",
|
|
47
48
|
"object.fromentries": "^2.0.8",
|
|
48
49
|
"ts-custom-error": "^3.3.1",
|
|
49
50
|
"whatwg-url": "^14.0.0"
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
(function (factory) {
|
|
2
|
-
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
-
var v = factory(require, exports);
|
|
4
|
-
if (v !== undefined) module.exports = v;
|
|
5
|
-
}
|
|
6
|
-
else if (typeof define === "function" && define.amd) {
|
|
7
|
-
define(["require", "exports", "./exception.js"], factory);
|
|
8
|
-
}
|
|
9
|
-
})(function (require, exports) {
|
|
10
|
-
"use strict";
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.FileExpectedException = void 0;
|
|
13
|
-
const exception_js_1 = require("./exception.js");
|
|
14
|
-
class FileExpectedException extends exception_js_1.Exception {
|
|
15
|
-
constructor() {
|
|
16
|
-
super('File/Blob (Browser) or Buffer (NodeJS) expected');
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
exports.FileExpectedException = FileExpectedException;
|
|
20
|
-
});
|