keq 2.1.2 → 2.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/CHANGELOG.md +14 -0
- package/README.md +42 -19
- package/dist/esm/src/core.js +51 -29
- package/dist/esm/src/create-request.js +2 -0
- package/dist/esm/src/keq.d.ts +6 -0
- package/dist/esm/src/keq.js +9 -0
- package/dist/esm/src/middlewares/timeout-middleware.d.ts +2 -0
- package/dist/esm/src/middlewares/timeout-middleware.js +19 -0
- package/dist/esm/src/types/keq-options.d.ts +13 -1
- package/dist/esm/src/types/keq-resolve-with-mode.d.ts +1 -0
- package/dist/esm/src/types/keq-resolve-with-mode.js +1 -0
- package/dist/esm/src/types/keq-timeout.d.ts +3 -0
- package/dist/esm/src/types/keq-timeout.js +1 -0
- package/dist/umd/src/core.js +51 -29
- package/dist/umd/src/create-request.js +3 -1
- package/dist/umd/src/keq.d.ts +6 -0
- package/dist/umd/src/keq.js +9 -0
- package/dist/umd/src/middlewares/timeout-middleware.d.ts +2 -0
- package/dist/umd/src/middlewares/timeout-middleware.js +33 -0
- package/dist/umd/src/types/keq-options.d.ts +13 -1
- package/dist/umd/src/types/keq-resolve-with-mode.d.ts +1 -0
- package/dist/umd/src/types/keq-resolve-with-mode.js +12 -0
- package/dist/umd/src/types/keq-timeout.d.ts +3 -0
- package/dist/umd/src/types/keq-timeout.js +12 -0
- package/package.json +18 -18
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
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.3.0](https://github.com/keq-request/keq/compare/v2.2.0...v2.3.0) (2024-02-24)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* add .resolveWith method add deprecated resolveWithFullResponse ([1e01e7f](https://github.com/keq-request/keq/commit/1e01e7fe07c146d9f122f0f52778b45258797c68))
|
|
11
|
+
|
|
12
|
+
## [2.2.0](https://github.com/keq-request/keq/compare/v2.1.2...v2.2.0) (2024-02-04)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* add .timeout(millisecond) ([b99009b](https://github.com/keq-request/keq/commit/b99009b6eb4a017d648a29a8b34b478dc22320ee))
|
|
18
|
+
|
|
5
19
|
## [2.1.2](https://github.com/keq-request/keq/compare/v2.1.1...v2.1.2) (2024-01-17)
|
|
6
20
|
|
|
7
21
|
|
package/README.md
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
<h1 align="center" style="text-align: center">KEQ</h1>
|
|
7
7
|
<!-- title -->
|
|
8
8
|
|
|
9
|
-
[
|
|
10
|
-
|
|
11
|
-
[![
|
|
12
|
-
[![
|
|
9
|
+
[npm]: https://www.npmjs.com/package/keq
|
|
10
|
+
|
|
11
|
+
[][npm]
|
|
12
|
+
[][npm]
|
|
13
|
+
[][npm]
|
|
14
|
+
[][npm]
|
|
13
15
|
[](https://codecov.io/gh/keq-request/keq)
|
|
14
16
|
|
|
15
17
|
<!-- description -->
|
|
@@ -80,20 +82,22 @@ await request.del("https://example.com/search");
|
|
|
80
82
|
> `.del()` is the alias of `.delete()`.
|
|
81
83
|
|
|
82
84
|
`Keq` will parse `body` according to the `Content-Type` of [`Response`][Response MDN]
|
|
83
|
-
and return `
|
|
84
|
-
Add
|
|
85
|
+
and return `undefined` if `Content-Type` not found.
|
|
86
|
+
Add invoke `.resolveWith('response')` to get the origin [`Response`][Response MDN] Object.
|
|
85
87
|
|
|
86
88
|
```javascript
|
|
87
89
|
import { request } from "keq";
|
|
88
90
|
|
|
89
91
|
const response = await request
|
|
90
92
|
.get("http://test.com")
|
|
91
|
-
.
|
|
93
|
+
.resolve('response')
|
|
92
94
|
|
|
93
95
|
const body = await response.json();
|
|
94
96
|
```
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
We will introduce `resolveWith` in more detail later.
|
|
99
|
+
|
|
100
|
+
###### `Keq` won't auto parse body, if response.status is 204. The HTTP 204 No Content success status response code indicates that server has fulfilled the request but does not need to return an entity-body, and might want to return updated meta information
|
|
97
101
|
|
|
98
102
|
### Setting header fields
|
|
99
103
|
|
|
@@ -267,6 +271,22 @@ await request
|
|
|
267
271
|
| jpeg, bmp, apng, gif, x-icon, png, webp, tiff | image/jpeg, image/bmp, image/apng, image/gif, image/x-icon, image/png, image/webp, image/tiff |
|
|
268
272
|
| svg | image/svg+xml |
|
|
269
273
|
|
|
274
|
+
### resolve responseBody
|
|
275
|
+
|
|
276
|
+
It was mentioned before that `Keq` will automatically parses the response body.
|
|
277
|
+
And we can control the parsing behavior by calling `.resolveWith(method)`.
|
|
278
|
+
There are multiple parsing methods for us to choose from
|
|
279
|
+
|
|
280
|
+
| method | description |
|
|
281
|
+
| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
282
|
+
| `.resolveWith('intelligent')` | It is the default method of `Keq`. This will returned `context.output` first if it exists. Otherwise return undefined when the response status is 204. Or return parsed response body according to the `Content-Type` of [`Response`][Response MDN]. |
|
|
283
|
+
| `.resolveWith('response')` | Return [`Response`][Response MDN]. |
|
|
284
|
+
| `.resolveWith('text')` | Return `response.text()`. |
|
|
285
|
+
| `.resolveWith('json')` | Return `response.json()`. |
|
|
286
|
+
| `.resolveWith('form-data')` | Return `response.formData()`. |
|
|
287
|
+
| `.resolveWith('blob')` | Return `response.blob()`. |
|
|
288
|
+
| `.resolveWith('array-buffer')` | Return `response.arrayBuffer()` |
|
|
289
|
+
|
|
270
290
|
### Request Retry
|
|
271
291
|
|
|
272
292
|
No retry by default, invoke `.retry(retryTimes[, retryDelay[, retryOn]])` to set retry parameters
|
|
@@ -326,11 +346,6 @@ import { request } from "keq";
|
|
|
326
346
|
|
|
327
347
|
const response = await request
|
|
328
348
|
.get("http://test.com")
|
|
329
|
-
/**
|
|
330
|
-
* keq will return Response rather than parsed body
|
|
331
|
-
* when set resolveWithFullResponse
|
|
332
|
-
*/
|
|
333
|
-
.option("resolveWithFullResponse")
|
|
334
349
|
.option("middlewareOption", "value");
|
|
335
350
|
```
|
|
336
351
|
|
|
@@ -342,17 +357,26 @@ import { request } from "keq";
|
|
|
342
357
|
await request
|
|
343
358
|
.get("http://test.com")
|
|
344
359
|
.options({
|
|
345
|
-
resolveWithFullResponse: true,
|
|
346
360
|
middlewareOption: "value",
|
|
347
361
|
});
|
|
348
362
|
```
|
|
349
363
|
|
|
350
364
|
| **Option** | **Description** |
|
|
351
365
|
| :------------------------ | :------------------------------------------------------------------------------------------------------ |
|
|
352
|
-
| `resolveWithFullResponse` | Get the [`Response`][Response MDN] Class. This is the `.clone()` of original [`Response`][Response MDN] |
|
|
353
366
|
| `fetchAPI` | Replace the defaulted `fetch` function used by `Keq`. |
|
|
354
367
|
|
|
355
368
|
<!-- ###### The options with **DEPRECATED** will be removed in next major version -->
|
|
369
|
+
|
|
370
|
+
### Timeout
|
|
371
|
+
|
|
372
|
+
Keq has built-in timeout function.
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
await request
|
|
376
|
+
.get("http://test.com")
|
|
377
|
+
// 5000 milliseconds
|
|
378
|
+
.timeout(5000)
|
|
379
|
+
```
|
|
356
380
|
|
|
357
381
|
### Flow Control
|
|
358
382
|
|
|
@@ -399,7 +423,6 @@ request
|
|
|
399
423
|
.followControl("serial", 'animal')
|
|
400
424
|
.end()
|
|
401
425
|
```
|
|
402
|
-
|
|
403
426
|
|
|
404
427
|
### Middleware
|
|
405
428
|
|
|
@@ -419,7 +442,7 @@ const middleware = async (context, next) => {
|
|
|
419
442
|
const body = await response.json()
|
|
420
443
|
|
|
421
444
|
// custom keq return type
|
|
422
|
-
|
|
445
|
+
context.output = JSON.stringify(body)
|
|
423
446
|
}
|
|
424
447
|
|
|
425
448
|
// Global Middleware
|
|
@@ -498,10 +521,10 @@ Keq's context object has many parameters. The following lists all the built-in c
|
|
|
498
521
|
| `context.request.referrer` | `referrer` arguments in [Fetch API][Fetch MDN] |
|
|
499
522
|
| `context.request.referrerPolicy` | `referrerPolicy` arguments in [Fetch API][Fetch MDN] |
|
|
500
523
|
| `context.request.signal` | `signal` arguments in [Fetch API][Fetch MDN] |
|
|
501
|
-
| `context.options` | It is an object includes request options.(example: `context.options.
|
|
524
|
+
| `context.options` | It is an object includes request options.(example: `context.options.fetchAPI`). Middleware can get custom options from here. |
|
|
502
525
|
| `context.res` | The origin [`Response`][Response MDN] Class. It will be undefined before run `await next()` or error throwed. |
|
|
503
526
|
| `context.response` | Cloned from `ctx.res`. |
|
|
504
|
-
| `context.output` |
|
|
527
|
+
| `context.output` | Custom return value of `await request()`。 It only take effect when `resolveWith` is not set or set to 'intelligent'. **This property is writeonly.** |
|
|
505
528
|
|
|
506
529
|
#### .useRouter()
|
|
507
530
|
|
package/dist/esm/src/core.js
CHANGED
|
@@ -13,7 +13,10 @@ export class Core {
|
|
|
13
13
|
__global__;
|
|
14
14
|
__prepend_middlewares__ = [];
|
|
15
15
|
__append_middlewares__ = [];
|
|
16
|
-
__options__ = {
|
|
16
|
+
__options__ = {
|
|
17
|
+
resolveWithFullResponse: false,
|
|
18
|
+
resolveWith: 'intelligent',
|
|
19
|
+
};
|
|
17
20
|
constructor(url, init, global = {}) {
|
|
18
21
|
this.__global__ = global;
|
|
19
22
|
this.requestContext = {
|
|
@@ -69,39 +72,58 @@ export class Core {
|
|
|
69
72
|
const middleware = composeMiddleware([...this.__prepend_middlewares__, ...this.__append_middlewares__]);
|
|
70
73
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
71
74
|
await middleware(ctx, async () => { });
|
|
72
|
-
|
|
73
|
-
if (ctx.options.resolveWithFullResponse) {
|
|
75
|
+
const output = ctx[OUTPUT_PROPERTY];
|
|
76
|
+
if (ctx.options.resolveWithFullResponse || ctx.options.resolveWith === 'response') {
|
|
74
77
|
return ctx.response;
|
|
75
78
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
const response = ctx.response;
|
|
80
|
+
if (!response) {
|
|
81
|
+
return (OUTPUT_PROPERTY in ctx) ? output : undefined;
|
|
82
|
+
}
|
|
83
|
+
if (ctx.options.resolveWith === 'text') {
|
|
84
|
+
return await response.text();
|
|
85
|
+
}
|
|
86
|
+
else if (ctx.options.resolveWith === 'json') {
|
|
87
|
+
return await response.json();
|
|
88
|
+
}
|
|
89
|
+
else if (ctx.options.resolveWith === 'form-data') {
|
|
90
|
+
return await response.formData();
|
|
91
|
+
}
|
|
92
|
+
else if (ctx.options.resolveWith === 'blob') {
|
|
93
|
+
return await response.blob();
|
|
94
|
+
}
|
|
95
|
+
else if (ctx.options.resolveWith === 'array-buffer') {
|
|
96
|
+
return await response.arrayBuffer();
|
|
97
|
+
}
|
|
98
|
+
if (OUTPUT_PROPERTY in ctx) {
|
|
99
|
+
return output;
|
|
100
|
+
}
|
|
101
|
+
if (response.status === 204) {
|
|
102
|
+
// 204: NO CONTENT
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
const contentType = response.headers.get('content-type') || '';
|
|
106
|
+
try {
|
|
107
|
+
if (contentType.includes('application/json')) {
|
|
108
|
+
return await response.json();
|
|
81
109
|
}
|
|
82
|
-
else {
|
|
83
|
-
|
|
84
|
-
const contentType = headers?.get('content-type') || '';
|
|
85
|
-
try {
|
|
86
|
-
if (contentType.includes('application/json')) {
|
|
87
|
-
output = ctx.response && await ctx.response.json();
|
|
88
|
-
}
|
|
89
|
-
else if (contentType.includes('multipart/form-data')) {
|
|
90
|
-
output = ctx.response && await ctx.response.formData();
|
|
91
|
-
}
|
|
92
|
-
else if (contentType.includes('plain/text')) {
|
|
93
|
-
output = ctx.response && await ctx.response.text();
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
output = ctx.response && ctx.response.body;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
catch (e) {
|
|
100
|
-
console.warn('Failed to auto parse response body', e);
|
|
101
|
-
}
|
|
110
|
+
else if (contentType.includes('multipart/form-data')) {
|
|
111
|
+
return await response.formData();
|
|
102
112
|
}
|
|
113
|
+
else if (contentType.includes('plain/text')) {
|
|
114
|
+
return await response.text();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
console.warn('Failed to auto parse response body', e);
|
|
103
119
|
}
|
|
104
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Unable to parse response body
|
|
122
|
+
* Return undefined
|
|
123
|
+
* Enable users to discover the problem
|
|
124
|
+
* And modify the method of parsing response
|
|
125
|
+
*/
|
|
126
|
+
return undefined;
|
|
105
127
|
}
|
|
106
128
|
async end() {
|
|
107
129
|
return this.run();
|
|
@@ -9,6 +9,7 @@ import { proxyResponseMiddleware } from './middlewares/proxy-response-middleware
|
|
|
9
9
|
import { retryMiddleware } from './middlewares/retry-middleware';
|
|
10
10
|
import { serialFlowControlMiddleware } from './middlewares/serial-flow-control-middleware.js';
|
|
11
11
|
import { KeqRouter } from './router/keq-router.js';
|
|
12
|
+
import { timeoutMiddleware } from './middlewares/timeout-middleware.js';
|
|
12
13
|
export function createRequest(options) {
|
|
13
14
|
let baseOrigin = options?.baseOrigin;
|
|
14
15
|
if (isBrowser() && !baseOrigin)
|
|
@@ -16,6 +17,7 @@ export function createRequest(options) {
|
|
|
16
17
|
const appendMiddlewares = options?.initMiddlewares ? [...options.initMiddlewares] : [
|
|
17
18
|
serialFlowControlMiddleware(),
|
|
18
19
|
abortFlowControlMiddleware(),
|
|
20
|
+
timeoutMiddleware(),
|
|
19
21
|
proxyResponseMiddleware(),
|
|
20
22
|
fetchArgumentsMiddleware(),
|
|
21
23
|
retryMiddleware(),
|
package/dist/esm/src/keq.d.ts
CHANGED
|
@@ -70,4 +70,10 @@ export declare class Keq<T> extends Core<T> {
|
|
|
70
70
|
credentials(mod: RequestCredentials): this;
|
|
71
71
|
mode(mod: RequestMode): this;
|
|
72
72
|
flowControl(mode: KeqFlowControlMode, signal?: KeqFlowControlSignal): this;
|
|
73
|
+
timeout(milliseconds: number): this;
|
|
74
|
+
resolveWith(m: 'response'): Keq<Response>;
|
|
75
|
+
resolveWith(m: 'array-buffer'): Keq<ArrayBuffer>;
|
|
76
|
+
resolveWith(m: 'blob'): Keq<Blob>;
|
|
77
|
+
resolveWith(m: 'text'): Keq<string>;
|
|
78
|
+
resolveWith<U = any>(m: 'json' | 'form-data'): Keq<U>;
|
|
73
79
|
}
|
package/dist/esm/src/keq.js
CHANGED
|
@@ -196,4 +196,13 @@ export class Keq extends Core {
|
|
|
196
196
|
this.option('flowControl', flowControl);
|
|
197
197
|
return this;
|
|
198
198
|
}
|
|
199
|
+
timeout(milliseconds) {
|
|
200
|
+
this.option('timeout', { millisecond: milliseconds });
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
resolveWith(m) {
|
|
204
|
+
this.option('resolveWith', m);
|
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
206
|
+
return this;
|
|
207
|
+
}
|
|
199
208
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function timeoutMiddleware() {
|
|
2
|
+
return async (ctx, next) => {
|
|
3
|
+
if (!ctx.options.timeout || ctx.options.timeout.millisecond <= 0) {
|
|
4
|
+
await next();
|
|
5
|
+
return;
|
|
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
|
+
setTimeout(() => {
|
|
15
|
+
timeoutSignal.abort('timeout');
|
|
16
|
+
}, ctx.options.timeout.millisecond);
|
|
17
|
+
await next();
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { KeqFlowControl } from './keq-flow-control.js';
|
|
2
|
+
import { KeqResolveMethod } from './keq-resolve-with-mode.js';
|
|
2
3
|
import { KeqRetryDelay } from './keq-retry-delay';
|
|
3
4
|
import { KeqRetryOn } from './keq-retry-on';
|
|
5
|
+
import { KeqTimeout } from './keq-timeout.js';
|
|
4
6
|
export interface KeqBuildInOptions {
|
|
5
7
|
/**
|
|
6
8
|
* replace the default fetch api
|
|
7
9
|
* default use node-fetch@2 in node and window.fetch in browser
|
|
8
10
|
*/
|
|
9
11
|
fetchAPI?: typeof fetch;
|
|
10
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* get response object, defaulted `false`
|
|
14
|
+
* @deprecated use `resolveWith` instead
|
|
15
|
+
* */
|
|
11
16
|
resolveWithFullResponse?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* how to resolve the response body
|
|
19
|
+
* @description 如何解析响应体
|
|
20
|
+
* @default 'intelligent'
|
|
21
|
+
*/
|
|
22
|
+
resolveWith?: KeqResolveMethod;
|
|
12
23
|
/**
|
|
13
24
|
* The request retry times
|
|
14
25
|
* @description 重试次数
|
|
@@ -29,6 +40,7 @@ export interface KeqBuildInOptions {
|
|
|
29
40
|
pathname: string;
|
|
30
41
|
};
|
|
31
42
|
flowControl?: KeqFlowControl;
|
|
43
|
+
timeout?: KeqTimeout;
|
|
32
44
|
}
|
|
33
45
|
export interface KeqOptionsWithFullResponse extends KeqBuildInOptions {
|
|
34
46
|
resolveWithFullResponse: true;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type KeqResolveMethod = 'intelligent' | 'response' | 'text' | 'json' | 'form-data' | 'blob' | 'array-buffer';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/umd/src/core.js
CHANGED
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
__global__;
|
|
26
26
|
__prepend_middlewares__ = [];
|
|
27
27
|
__append_middlewares__ = [];
|
|
28
|
-
__options__ = {
|
|
28
|
+
__options__ = {
|
|
29
|
+
resolveWithFullResponse: false,
|
|
30
|
+
resolveWith: 'intelligent',
|
|
31
|
+
};
|
|
29
32
|
constructor(url, init, global = {}) {
|
|
30
33
|
this.__global__ = global;
|
|
31
34
|
this.requestContext = {
|
|
@@ -81,39 +84,58 @@
|
|
|
81
84
|
const middleware = (0, compose_middleware_1.composeMiddleware)([...this.__prepend_middlewares__, ...this.__append_middlewares__]);
|
|
82
85
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
83
86
|
await middleware(ctx, async () => { });
|
|
84
|
-
|
|
85
|
-
if (ctx.options.resolveWithFullResponse) {
|
|
87
|
+
const output = ctx[constant_1.OUTPUT_PROPERTY];
|
|
88
|
+
if (ctx.options.resolveWithFullResponse || ctx.options.resolveWith === 'response') {
|
|
86
89
|
return ctx.response;
|
|
87
90
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
const response = ctx.response;
|
|
92
|
+
if (!response) {
|
|
93
|
+
return (constant_1.OUTPUT_PROPERTY in ctx) ? output : undefined;
|
|
94
|
+
}
|
|
95
|
+
if (ctx.options.resolveWith === 'text') {
|
|
96
|
+
return await response.text();
|
|
97
|
+
}
|
|
98
|
+
else if (ctx.options.resolveWith === 'json') {
|
|
99
|
+
return await response.json();
|
|
100
|
+
}
|
|
101
|
+
else if (ctx.options.resolveWith === 'form-data') {
|
|
102
|
+
return await response.formData();
|
|
103
|
+
}
|
|
104
|
+
else if (ctx.options.resolveWith === 'blob') {
|
|
105
|
+
return await response.blob();
|
|
106
|
+
}
|
|
107
|
+
else if (ctx.options.resolveWith === 'array-buffer') {
|
|
108
|
+
return await response.arrayBuffer();
|
|
109
|
+
}
|
|
110
|
+
if (constant_1.OUTPUT_PROPERTY in ctx) {
|
|
111
|
+
return output;
|
|
112
|
+
}
|
|
113
|
+
if (response.status === 204) {
|
|
114
|
+
// 204: NO CONTENT
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
const contentType = response.headers.get('content-type') || '';
|
|
118
|
+
try {
|
|
119
|
+
if (contentType.includes('application/json')) {
|
|
120
|
+
return await response.json();
|
|
93
121
|
}
|
|
94
|
-
else {
|
|
95
|
-
|
|
96
|
-
const contentType = headers?.get('content-type') || '';
|
|
97
|
-
try {
|
|
98
|
-
if (contentType.includes('application/json')) {
|
|
99
|
-
output = ctx.response && await ctx.response.json();
|
|
100
|
-
}
|
|
101
|
-
else if (contentType.includes('multipart/form-data')) {
|
|
102
|
-
output = ctx.response && await ctx.response.formData();
|
|
103
|
-
}
|
|
104
|
-
else if (contentType.includes('plain/text')) {
|
|
105
|
-
output = ctx.response && await ctx.response.text();
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
output = ctx.response && ctx.response.body;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch (e) {
|
|
112
|
-
console.warn('Failed to auto parse response body', e);
|
|
113
|
-
}
|
|
122
|
+
else if (contentType.includes('multipart/form-data')) {
|
|
123
|
+
return await response.formData();
|
|
114
124
|
}
|
|
125
|
+
else if (contentType.includes('plain/text')) {
|
|
126
|
+
return await response.text();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
console.warn('Failed to auto parse response body', e);
|
|
115
131
|
}
|
|
116
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Unable to parse response body
|
|
134
|
+
* Return undefined
|
|
135
|
+
* Enable users to discover the problem
|
|
136
|
+
* And modify the method of parsing response
|
|
137
|
+
*/
|
|
138
|
+
return undefined;
|
|
117
139
|
}
|
|
118
140
|
async end() {
|
|
119
141
|
return this.run();
|
|
@@ -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", "./is/is-browser", "./keq", "./middlewares/abort-flow-control-middleware.js", "./middlewares/fetch-arguments-middleware", "./middlewares/fetch-middleware", "./middlewares/proxy-response-middleware", "./middlewares/retry-middleware", "./middlewares/serial-flow-control-middleware.js", "./router/keq-router.js"], factory);
|
|
7
|
+
define(["require", "exports", "whatwg-url", "./is/is-browser", "./keq", "./middlewares/abort-flow-control-middleware.js", "./middlewares/fetch-arguments-middleware", "./middlewares/fetch-middleware", "./middlewares/proxy-response-middleware", "./middlewares/retry-middleware", "./middlewares/serial-flow-control-middleware.js", "./router/keq-router.js", "./middlewares/timeout-middleware.js"], factory);
|
|
8
8
|
}
|
|
9
9
|
})(function (require, exports) {
|
|
10
10
|
"use strict";
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
const retry_middleware_1 = require("./middlewares/retry-middleware");
|
|
22
22
|
const serial_flow_control_middleware_js_1 = require("./middlewares/serial-flow-control-middleware.js");
|
|
23
23
|
const keq_router_js_1 = require("./router/keq-router.js");
|
|
24
|
+
const timeout_middleware_js_1 = require("./middlewares/timeout-middleware.js");
|
|
24
25
|
function createRequest(options) {
|
|
25
26
|
let baseOrigin = options?.baseOrigin;
|
|
26
27
|
if ((0, is_browser_1.isBrowser)() && !baseOrigin)
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
const appendMiddlewares = options?.initMiddlewares ? [...options.initMiddlewares] : [
|
|
29
30
|
(0, serial_flow_control_middleware_js_1.serialFlowControlMiddleware)(),
|
|
30
31
|
(0, abort_flow_control_middleware_js_1.abortFlowControlMiddleware)(),
|
|
32
|
+
(0, timeout_middleware_js_1.timeoutMiddleware)(),
|
|
31
33
|
(0, proxy_response_middleware_1.proxyResponseMiddleware)(),
|
|
32
34
|
(0, fetch_arguments_middleware_1.fetchArgumentsMiddleware)(),
|
|
33
35
|
(0, retry_middleware_1.retryMiddleware)(),
|
package/dist/umd/src/keq.d.ts
CHANGED
|
@@ -70,4 +70,10 @@ export declare class Keq<T> extends Core<T> {
|
|
|
70
70
|
credentials(mod: RequestCredentials): this;
|
|
71
71
|
mode(mod: RequestMode): this;
|
|
72
72
|
flowControl(mode: KeqFlowControlMode, signal?: KeqFlowControlSignal): this;
|
|
73
|
+
timeout(milliseconds: number): this;
|
|
74
|
+
resolveWith(m: 'response'): Keq<Response>;
|
|
75
|
+
resolveWith(m: 'array-buffer'): Keq<ArrayBuffer>;
|
|
76
|
+
resolveWith(m: 'blob'): Keq<Blob>;
|
|
77
|
+
resolveWith(m: 'text'): Keq<string>;
|
|
78
|
+
resolveWith<U = any>(m: 'json' | 'form-data'): Keq<U>;
|
|
73
79
|
}
|
package/dist/umd/src/keq.js
CHANGED
|
@@ -208,6 +208,15 @@
|
|
|
208
208
|
this.option('flowControl', flowControl);
|
|
209
209
|
return this;
|
|
210
210
|
}
|
|
211
|
+
timeout(milliseconds) {
|
|
212
|
+
this.option('timeout', { millisecond: milliseconds });
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
resolveWith(m) {
|
|
216
|
+
this.option('resolveWith', m);
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
211
220
|
}
|
|
212
221
|
exports.Keq = Keq;
|
|
213
222
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
exports.timeoutMiddleware = void 0;
|
|
13
|
+
function timeoutMiddleware() {
|
|
14
|
+
return async (ctx, next) => {
|
|
15
|
+
if (!ctx.options.timeout || ctx.options.timeout.millisecond <= 0) {
|
|
16
|
+
await next();
|
|
17
|
+
return;
|
|
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
|
+
setTimeout(() => {
|
|
27
|
+
timeoutSignal.abort('timeout');
|
|
28
|
+
}, ctx.options.timeout.millisecond);
|
|
29
|
+
await next();
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
exports.timeoutMiddleware = timeoutMiddleware;
|
|
33
|
+
});
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { KeqFlowControl } from './keq-flow-control.js';
|
|
2
|
+
import { KeqResolveMethod } from './keq-resolve-with-mode.js';
|
|
2
3
|
import { KeqRetryDelay } from './keq-retry-delay';
|
|
3
4
|
import { KeqRetryOn } from './keq-retry-on';
|
|
5
|
+
import { KeqTimeout } from './keq-timeout.js';
|
|
4
6
|
export interface KeqBuildInOptions {
|
|
5
7
|
/**
|
|
6
8
|
* replace the default fetch api
|
|
7
9
|
* default use node-fetch@2 in node and window.fetch in browser
|
|
8
10
|
*/
|
|
9
11
|
fetchAPI?: typeof fetch;
|
|
10
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* get response object, defaulted `false`
|
|
14
|
+
* @deprecated use `resolveWith` instead
|
|
15
|
+
* */
|
|
11
16
|
resolveWithFullResponse?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* how to resolve the response body
|
|
19
|
+
* @description 如何解析响应体
|
|
20
|
+
* @default 'intelligent'
|
|
21
|
+
*/
|
|
22
|
+
resolveWith?: KeqResolveMethod;
|
|
12
23
|
/**
|
|
13
24
|
* The request retry times
|
|
14
25
|
* @description 重试次数
|
|
@@ -29,6 +40,7 @@ export interface KeqBuildInOptions {
|
|
|
29
40
|
pathname: string;
|
|
30
41
|
};
|
|
31
42
|
flowControl?: KeqFlowControl;
|
|
43
|
+
timeout?: KeqTimeout;
|
|
32
44
|
}
|
|
33
45
|
export interface KeqOptionsWithFullResponse extends KeqBuildInOptions {
|
|
34
46
|
resolveWithFullResponse: true;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type KeqResolveMethod = 'intelligent' | 'response' | 'text' | 'json' | 'form-data' | 'blob' | 'array-buffer';
|
|
@@ -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,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
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keq",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Request API write by Typescript for flexibility, readability, and a low learning curve.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"request",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"build": "npm run clean && ./build/build.sh",
|
|
34
34
|
"clean": "rm -rf ./dist/*",
|
|
35
35
|
"dev": "npm run clean && ./build/watch.sh",
|
|
36
|
-
"prepare": "ts-patch install -s && is-ci || husky
|
|
36
|
+
"prepare": "ts-patch install -s && is-ci || husky",
|
|
37
37
|
"prepublishOnly": "npm run build",
|
|
38
38
|
"release": "standard-version",
|
|
39
39
|
"release:alpha": "standard-version --prerelease alpha",
|
|
@@ -41,35 +41,35 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"clone": "^2.1.2",
|
|
44
|
-
"fastq": "^1.
|
|
44
|
+
"fastq": "^1.17.1",
|
|
45
45
|
"minimatch": "^9.0.3",
|
|
46
46
|
"object.fromentries": "^2.0.7",
|
|
47
47
|
"ts-custom-error": "^3.3.1",
|
|
48
48
|
"whatwg-url": "^14.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@buka/eslint-config": "^1.
|
|
52
|
-
"@commitlint/cli": "^18.
|
|
53
|
-
"@commitlint/config-conventional": "^18.
|
|
51
|
+
"@buka/eslint-config": "^1.6.0",
|
|
52
|
+
"@commitlint/cli": "^18.6.1",
|
|
53
|
+
"@commitlint/config-conventional": "^18.6.2",
|
|
54
54
|
"@jest/globals": "^29.7.0",
|
|
55
|
-
"@rushstack/eslint-patch": "^1.
|
|
55
|
+
"@rushstack/eslint-patch": "^1.7.2",
|
|
56
56
|
"@types/clone": "^2.1.4",
|
|
57
57
|
"@types/minimatch": "^5.1.2",
|
|
58
|
-
"@types/node": "^20.
|
|
59
|
-
"@types/whatwg-url": "^11.0.
|
|
60
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
61
|
-
"@typescript-eslint/parser": "^
|
|
62
|
-
"eslint": "^8.
|
|
63
|
-
"husky": "^
|
|
58
|
+
"@types/node": "^20.11.20",
|
|
59
|
+
"@types/whatwg-url": "^11.0.4",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
|
61
|
+
"@typescript-eslint/parser": "^7.0.2",
|
|
62
|
+
"eslint": "^8.57.0",
|
|
63
|
+
"husky": "^9.0.11",
|
|
64
64
|
"is-ci": "^3.0.1",
|
|
65
65
|
"jest": "^29.7.0",
|
|
66
66
|
"jest-mock": "^29.7.0",
|
|
67
67
|
"standard-version": "^9.5.0",
|
|
68
|
-
"ts-jest": "^29.1.
|
|
69
|
-
"ts-node": "^10.9.
|
|
70
|
-
"ts-patch": "^3.
|
|
71
|
-
"typescript": "^5.
|
|
72
|
-
"typescript-transform-paths": "^3.4.
|
|
68
|
+
"ts-jest": "^29.1.2",
|
|
69
|
+
"ts-node": "^10.9.2",
|
|
70
|
+
"ts-patch": "^3.1.2",
|
|
71
|
+
"typescript": "^5.3.3",
|
|
72
|
+
"typescript-transform-paths": "^3.4.7"
|
|
73
73
|
},
|
|
74
74
|
"packageManager": "pnpm@8.6.4",
|
|
75
75
|
"engines": {
|