undici 4.7.0 → 4.8.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/docs/api/BalancedPool.md +98 -0
- package/docs/api/DiagnosticsChannel.md +9 -8
- package/docs/best-practices/mocking-request.md +101 -0
- package/index.d.ts +13 -11
- package/index.js +2 -0
- package/lib/api/readable.js +5 -1
- package/lib/balanced-pool.js +119 -0
- package/lib/client.js +3 -1
- package/lib/core/errors.js +12 -1
- package/lib/core/request.js +3 -1
- package/lib/fetch/index.js +1 -0
- package/lib/llhttp/llhttp.wasm +0 -0
- package/lib/llhttp/llhttp_simd.wasm +0 -0
- package/package.json +1 -1
- package/types/agent.d.ts +2 -2
- package/types/api.d.ts +1 -1
- package/types/balanced-pool.d.ts +19 -0
- package/types/client.d.ts +3 -2
- package/types/global-dispatcher.d.ts +1 -1
- package/types/mock-agent.d.ts +2 -2
- package/types/mock-client.d.ts +3 -3
- package/types/mock-pool.d.ts +3 -3
- package/types/pool.d.ts +2 -2
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Class: BalancedPool
|
|
2
|
+
|
|
3
|
+
Extends: `undici.Dispatcher`
|
|
4
|
+
|
|
5
|
+
A pool of [Pool](docs/api/Pool.md) instances connected to multiple upstreams.
|
|
6
|
+
|
|
7
|
+
Requests are not guaranteed to be dispatched in order of invocation.
|
|
8
|
+
|
|
9
|
+
## `new BalancedPool(upstreams [, options])`
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
|
|
13
|
+
* **upstreams** `URL | string | string[]` - It should only include the **protocol, hostname, and port**.
|
|
14
|
+
* **options** `PoolOptions` (optional)
|
|
15
|
+
|
|
16
|
+
### Parameter: `PoolOptions`
|
|
17
|
+
|
|
18
|
+
The `PoolOptions` are passed to each of the `Pool` instances being created.
|
|
19
|
+
|
|
20
|
+
See: [`PoolOptions`](docs/api/Pool.md#parameter-pooloptions)
|
|
21
|
+
|
|
22
|
+
## Instance Properties
|
|
23
|
+
|
|
24
|
+
### `BalancedPool.upstreams`
|
|
25
|
+
|
|
26
|
+
Returns an array of upstreams that were previously added.
|
|
27
|
+
|
|
28
|
+
### `BalancedPool.busy`
|
|
29
|
+
|
|
30
|
+
Implements [Client.busy](docs/api/Client.md#clientbusy)
|
|
31
|
+
|
|
32
|
+
### `BalancedPool.closed`
|
|
33
|
+
|
|
34
|
+
Implements [Client.closed](docs/api/Client.md#clientclosed)
|
|
35
|
+
|
|
36
|
+
### `BalancedPool.destroyed`
|
|
37
|
+
|
|
38
|
+
Implements [Client.destroyed](docs/api/Client.md#clientdestroyed)
|
|
39
|
+
|
|
40
|
+
## Instance Methods
|
|
41
|
+
|
|
42
|
+
### `BalancedPool.addUpstream(upstream)`
|
|
43
|
+
|
|
44
|
+
Add an upstream.
|
|
45
|
+
|
|
46
|
+
Arguments:
|
|
47
|
+
|
|
48
|
+
* **upstream** `string` - It should only include the **protocol, hostname, and port**.
|
|
49
|
+
|
|
50
|
+
### `BalancedPool.removeUpstream(upstream)`
|
|
51
|
+
|
|
52
|
+
Removes an upstream that was previously addded.
|
|
53
|
+
|
|
54
|
+
### `BalancedPool.close([callback])`
|
|
55
|
+
|
|
56
|
+
Implements [`Dispatcher.close([callback])`](docs/api/Dispatcher.md#clientclose-callback-).
|
|
57
|
+
|
|
58
|
+
### `BalancedPool.destroy([error, callback])`
|
|
59
|
+
|
|
60
|
+
Implements [`Dispatcher.destroy([error, callback])`](docs/api/Dispatcher.md#dispatcher-callback-).
|
|
61
|
+
|
|
62
|
+
### `BalancedPool.connect(options[, callback])`
|
|
63
|
+
|
|
64
|
+
See [`Dispatcher.connect(options[, callback])`](docs/api/Dispatcher.md#clientconnectoptions--callback).
|
|
65
|
+
|
|
66
|
+
### `BalancedPool.dispatch(options, handlers)`
|
|
67
|
+
|
|
68
|
+
Implements [`Dispatcher.dispatch(options, handlers)`](docs/api/Dispatcher.md#clientdispatchoptions-handlers).
|
|
69
|
+
|
|
70
|
+
### `BalancedPool.pipeline(options, handler)`
|
|
71
|
+
|
|
72
|
+
See [`Dispatcher.pipeline(options, handler)`](docs/api/Dispatcher.md#clientpipelineoptions-handler).
|
|
73
|
+
|
|
74
|
+
### `BalancedPool.request(options[, callback])`
|
|
75
|
+
|
|
76
|
+
See [`Dispatcher.request(options [, callback])`](docs/api/Dispatcher.md#clientrequestoptions--callback).
|
|
77
|
+
|
|
78
|
+
### `BalancedPool.stream(options, factory[, callback])`
|
|
79
|
+
|
|
80
|
+
See [`Dispatcher.stream(options, factory[, callback])`](docs/api/Dispatcher.md#clientstreamoptions-factory--callback).
|
|
81
|
+
|
|
82
|
+
### `BalancedPool.upgrade(options[, callback])`
|
|
83
|
+
|
|
84
|
+
See [`Dispatcher.upgrade(options[, callback])`](docs/api/Dispatcher.md#clientupgradeoptions-callback).
|
|
85
|
+
|
|
86
|
+
## Instance Events
|
|
87
|
+
|
|
88
|
+
### Event: `'connect'`
|
|
89
|
+
|
|
90
|
+
See [Dispatcher Event: `'connect'`](docs/api/Dispatcher.md#event-connect).
|
|
91
|
+
|
|
92
|
+
### Event: `'disconnect'`
|
|
93
|
+
|
|
94
|
+
See [Dispatcher Event: `'disconnect'`](docs/api/Dispatcher.md#event-connect).
|
|
95
|
+
|
|
96
|
+
### Event: `'drain'`
|
|
97
|
+
|
|
98
|
+
See [Dispatcher Event: `'drain'`](docs/api/Dispatcher.md#event-connect).
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Stability: Experimental.
|
|
4
4
|
|
|
5
|
-
Undici
|
|
6
|
-
It is the preferred way to instrument Undici and retrieve internal
|
|
5
|
+
Undici supports the [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html) (currently available only on Node.js v16+).
|
|
6
|
+
It is the preferred way to instrument Undici and retrieve internal information.
|
|
7
7
|
|
|
8
8
|
The channels available are the following.
|
|
9
9
|
|
|
@@ -15,6 +15,7 @@ This message is published when a new outgoing request is created.
|
|
|
15
15
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
16
16
|
|
|
17
17
|
diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {
|
|
18
|
+
console.log('origin', request.origin)
|
|
18
19
|
console.log('completed', request.completed)
|
|
19
20
|
console.log('method', request.method)
|
|
20
21
|
console.log('path', request.path)
|
|
@@ -39,7 +40,7 @@ diagnosticsChannel.channel('undici:request:bodySent').subscribe(({ request }) =>
|
|
|
39
40
|
|
|
40
41
|
## `undici:request:headers`
|
|
41
42
|
|
|
42
|
-
This message is published after the response headers have been received, i.e. the
|
|
43
|
+
This message is published after the response headers have been received, i.e. the response has been completed.
|
|
43
44
|
|
|
44
45
|
```js
|
|
45
46
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
@@ -55,7 +56,7 @@ diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, respo
|
|
|
55
56
|
|
|
56
57
|
## `undici:request:trailers`
|
|
57
58
|
|
|
58
|
-
This message is published after the response body and trailers have been received, i.e. the
|
|
59
|
+
This message is published after the response body and trailers have been received, i.e. the response has been completed.
|
|
59
60
|
|
|
60
61
|
```js
|
|
61
62
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
@@ -82,9 +83,9 @@ diagnosticsChannel.channel('undici:request:error').subscribe(({ request, error }
|
|
|
82
83
|
|
|
83
84
|
## `undici:client:sendHeaders`
|
|
84
85
|
|
|
85
|
-
This message is published right before first byte of the request is written to the socket.
|
|
86
|
+
This message is published right before the first byte of the request is written to the socket.
|
|
86
87
|
|
|
87
|
-
*Note*: It will publish the exact headers that will be sent to the server in raw
|
|
88
|
+
*Note*: It will publish the exact headers that will be sent to the server in raw format.
|
|
88
89
|
|
|
89
90
|
```js
|
|
90
91
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
@@ -97,7 +98,7 @@ diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(({ request, he
|
|
|
97
98
|
|
|
98
99
|
## `undici:client:beforeConnect`
|
|
99
100
|
|
|
100
|
-
This message is published before creating a new connection for **any** request.
|
|
101
|
+
This message is published before creating a new connection for **any** request.
|
|
101
102
|
You can not assume that this event is related to any specific request.
|
|
102
103
|
|
|
103
104
|
```js
|
|
@@ -111,7 +112,7 @@ diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectPa
|
|
|
111
112
|
|
|
112
113
|
## `undici:client:connected`
|
|
113
114
|
|
|
114
|
-
This message is published after connection established.
|
|
115
|
+
This message is published after a connection is established.
|
|
115
116
|
|
|
116
117
|
```js
|
|
117
118
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Mocking Request
|
|
2
|
+
|
|
3
|
+
Undici have its own mocking [utility](docs/api/MockAgent.md). It allow us to intercept undici HTTP request and return mocked value instead. It can be useful for testing purposes.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
// index.mjs
|
|
9
|
+
import { request } from 'undici'
|
|
10
|
+
|
|
11
|
+
export async function bankTransfer(recepient, ammount) {
|
|
12
|
+
const { body } = await request('http://localhost:3000/bank-transfer',
|
|
13
|
+
{
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'X-TOKEN-SECRET': 'SuperSecretToken',
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify({ recepient })
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
return await body.json()
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
And this is what the test file looks like:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
// index.test.mjs
|
|
29
|
+
import { strict as assert } from 'assert'
|
|
30
|
+
import { MockAgent, setGlobalDispatcher, } from 'undici'
|
|
31
|
+
import { bankTransfer } from './undici.mjs'
|
|
32
|
+
|
|
33
|
+
const mockAgent = new MockAgent();
|
|
34
|
+
|
|
35
|
+
setGlobalDispatcher(mockAgent);
|
|
36
|
+
|
|
37
|
+
// Provide the base url to the request
|
|
38
|
+
const mockPool = mockAgent.get('http://localhost:3000');
|
|
39
|
+
|
|
40
|
+
// intercept the request
|
|
41
|
+
mockPool.intercept({
|
|
42
|
+
path: '/bank-transfer',
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: {
|
|
45
|
+
'X-TOKEN-SECRET': 'SuperSecretToken',
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify({
|
|
48
|
+
recepient: '1234567890',
|
|
49
|
+
ammount: '100'
|
|
50
|
+
})
|
|
51
|
+
}).reply(200, {
|
|
52
|
+
message: 'transaction processed'
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const success = await bankTransfer('1234567890', '100')
|
|
56
|
+
|
|
57
|
+
assert.deepEqual(success, { message: 'transaction processed' })
|
|
58
|
+
|
|
59
|
+
// if you dont want to check whether the body or the headers contain the same value
|
|
60
|
+
// just remove it from interceptor
|
|
61
|
+
mockPool.intercept({
|
|
62
|
+
path: '/bank-transfer',
|
|
63
|
+
method: 'POST',
|
|
64
|
+
}).reply(400, {
|
|
65
|
+
message: 'bank account not found'
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const badRequest = await bankTransfer('1234567890', '100')
|
|
69
|
+
|
|
70
|
+
assert.deepEqual(badRequest, { message: 'bank account not found' })
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Explore other MockAgent functionality [here](docs/api/MockAgent.md)
|
|
74
|
+
|
|
75
|
+
## Debug Mock Value
|
|
76
|
+
|
|
77
|
+
When the interceptor we wrote are not the same undici will automatically call real HTTP request. To debug our mock value use `mockAgent.disableNetConnect()`
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
const mockAgent = new MockAgent();
|
|
81
|
+
|
|
82
|
+
setGlobalDispatcher(mockAgent);
|
|
83
|
+
mockAgent.disableNetConnect()
|
|
84
|
+
|
|
85
|
+
// Provide the base url to the request
|
|
86
|
+
const mockPool = mockAgent.get('http://localhost:3000');
|
|
87
|
+
|
|
88
|
+
mockPool.intercept({
|
|
89
|
+
path: '/bank-tanfer',
|
|
90
|
+
method: 'POST',
|
|
91
|
+
}).reply(200, {
|
|
92
|
+
message: 'transaction processed'
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const badRequest = await bankTransfer('1234567890', '100')
|
|
96
|
+
// Will throw an error
|
|
97
|
+
// MockNotMatchedError: Mock dispatch not matched for path '/bank-transfer':
|
|
98
|
+
// subsequent request to origin http://localhost:3000 was not allowed (net.connect disabled)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
|
package/index.d.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import Dispatcher
|
|
1
|
+
import Dispatcher = require('./types/dispatcher')
|
|
2
2
|
import { setGlobalDispatcher, getGlobalDispatcher } from './types/global-dispatcher'
|
|
3
|
-
import Pool
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
3
|
+
import Pool = require('./types/pool')
|
|
4
|
+
import BalancedPool = require('./types/balanced-pool')
|
|
5
|
+
import Client = require('./types/client')
|
|
6
|
+
import buildConnector = require('./types/connector')
|
|
7
|
+
import errors = require('./types/errors')
|
|
8
|
+
import Agent = require('./types/agent')
|
|
9
|
+
import MockClient = require('./types/mock-client')
|
|
10
|
+
import MockPool = require('./types/mock-pool')
|
|
11
|
+
import MockAgent = require('./types/mock-agent')
|
|
12
|
+
import mockErrors = require('./types/mock-errors')
|
|
12
13
|
import { request, pipeline, stream, connect, upgrade } from './types/api'
|
|
13
14
|
|
|
14
15
|
export * from './types/fetch'
|
|
15
16
|
export * from './types/file'
|
|
16
17
|
export * from './types/formdata'
|
|
17
18
|
|
|
18
|
-
export { Dispatcher, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, MockClient, MockPool, MockAgent, mockErrors }
|
|
19
|
+
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, MockClient, MockPool, MockAgent, mockErrors }
|
|
19
20
|
export default Undici
|
|
20
21
|
|
|
21
22
|
declare function Undici(url: string, opts: Pool.Options): Pool
|
|
@@ -23,6 +24,7 @@ declare function Undici(url: string, opts: Pool.Options): Pool
|
|
|
23
24
|
declare namespace Undici {
|
|
24
25
|
var Dispatcher: typeof import('./types/dispatcher')
|
|
25
26
|
var Pool: typeof import('./types/pool');
|
|
27
|
+
var BalancedPool: typeof import('./types/balanced-pool');
|
|
26
28
|
var Client: typeof import('./types/client');
|
|
27
29
|
var buildConnector: typeof import('./types/connector');
|
|
28
30
|
var errors: typeof import('./types/errors');
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const Client = require('./lib/client')
|
|
|
4
4
|
const Dispatcher = require('./lib/dispatcher')
|
|
5
5
|
const errors = require('./lib/core/errors')
|
|
6
6
|
const Pool = require('./lib/pool')
|
|
7
|
+
const BalancedPool = require('./lib/balanced-pool')
|
|
7
8
|
const Agent = require('./lib/agent')
|
|
8
9
|
const util = require('./lib/core/util')
|
|
9
10
|
const { InvalidArgumentError } = errors
|
|
@@ -23,6 +24,7 @@ Object.assign(Dispatcher.prototype, api)
|
|
|
23
24
|
module.exports.Dispatcher = Dispatcher
|
|
24
25
|
module.exports.Client = Client
|
|
25
26
|
module.exports.Pool = Pool
|
|
27
|
+
module.exports.BalancedPool = BalancedPool
|
|
26
28
|
module.exports.Agent = Agent
|
|
27
29
|
|
|
28
30
|
module.exports.buildConnector = buildConnector
|
package/lib/api/readable.js
CHANGED
|
@@ -18,7 +18,11 @@ const kContentType = Symbol('kContentType')
|
|
|
18
18
|
|
|
19
19
|
module.exports = class BodyReadable extends Readable {
|
|
20
20
|
constructor (resume, abort, contentType = '') {
|
|
21
|
-
super({
|
|
21
|
+
super({
|
|
22
|
+
autoDestroy: true,
|
|
23
|
+
read: resume,
|
|
24
|
+
highWaterMark: 64 * 1024 // Same as nodejs fs streams.
|
|
25
|
+
})
|
|
22
26
|
|
|
23
27
|
this._readableState.dataEmitted = false
|
|
24
28
|
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { BalancedPoolMissingUpstreamError } = require('./core/errors')
|
|
4
|
+
const Dispatcher = require('./dispatcher')
|
|
5
|
+
const Pool = require('./pool')
|
|
6
|
+
|
|
7
|
+
const kPools = Symbol('kPools')
|
|
8
|
+
const kPoolOpts = Symbol('kPoolOpts')
|
|
9
|
+
const kUpstream = Symbol('kUpstream')
|
|
10
|
+
const kNeedDrain = Symbol('kNeedDrain')
|
|
11
|
+
|
|
12
|
+
class BalancedPool extends Dispatcher {
|
|
13
|
+
constructor (upstreams = [], opts = {}) {
|
|
14
|
+
super()
|
|
15
|
+
|
|
16
|
+
this[kPools] = []
|
|
17
|
+
this[kPoolOpts] = opts
|
|
18
|
+
this[kNeedDrain] = false
|
|
19
|
+
|
|
20
|
+
if (!Array.isArray(upstreams)) {
|
|
21
|
+
upstreams = [upstreams]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for (const upstream of upstreams) {
|
|
25
|
+
this.addUpstream(upstream)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
addUpstream (upstream) {
|
|
30
|
+
if (this[kPools].find((pool) => pool[kUpstream] === upstream)) {
|
|
31
|
+
return this
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const pool = new Pool(upstream, Object.assign({}, this[kPoolOpts]))
|
|
35
|
+
|
|
36
|
+
pool[kUpstream] = upstream
|
|
37
|
+
|
|
38
|
+
pool.on('connect', (...args) => {
|
|
39
|
+
this.emit('connect', ...args)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
pool.on('disconnect', (...args) => {
|
|
43
|
+
this.emit('disconnect', ...args)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
pool.on('drain', (...args) => {
|
|
47
|
+
if (this[kNeedDrain]) {
|
|
48
|
+
this[kNeedDrain] = false
|
|
49
|
+
this.emit('drain', ...args)
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
this[kPools].push(pool)
|
|
54
|
+
return this
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
dispatch (opts, handler) {
|
|
58
|
+
// We validate that pools is greater than 0,
|
|
59
|
+
// otherwise we would have to wait until an upstream
|
|
60
|
+
// is added, which might never happen.
|
|
61
|
+
if (this[kPools].length === 0) {
|
|
62
|
+
throw new BalancedPoolMissingUpstreamError()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let pool = this[kPools].shift()
|
|
66
|
+
this[kPools].push(pool)
|
|
67
|
+
if (pool.busy) {
|
|
68
|
+
pool = this[kPools].find(pool => !pool.busy) || pool
|
|
69
|
+
}
|
|
70
|
+
this[kNeedDrain] = !pool.dispatch(opts, handler)
|
|
71
|
+
return !this[kNeedDrain]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
removeUpstream (upstream) {
|
|
75
|
+
const pool = this[kPools].find((pool) => pool[kUpstream] === upstream)
|
|
76
|
+
const idx = this[kPools].indexOf(pool)
|
|
77
|
+
this[kPools].splice(idx, 1)
|
|
78
|
+
pool.close()
|
|
79
|
+
return this
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get upstreams () {
|
|
83
|
+
return this[kPools].map((p) => p[kUpstream])
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get destroyed () {
|
|
87
|
+
return this[kPools].reduce((acc, pool) => acc && pool.destroyed, true)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get busy () {
|
|
91
|
+
return this[kPools].reduce((acc, pool) => acc && pool.busy, true) || false
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get closed () {
|
|
95
|
+
return this[kPools].reduce((acc, pool) => acc && pool.closed, true)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
close (cb) {
|
|
99
|
+
const p = Promise.all(this[kPools].map((p) => p.close()))
|
|
100
|
+
|
|
101
|
+
if (!cb) {
|
|
102
|
+
return p
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
p.then(() => process.nextTick(cb), (err) => process.nextTick(cb, err))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
destroy (err, cb) {
|
|
109
|
+
const p = Promise.all(this[kPools].map((p) => p.destroy(err)))
|
|
110
|
+
|
|
111
|
+
if (!cb) {
|
|
112
|
+
return p
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
p.then(() => process.nextTick(cb))
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = BalancedPool
|
package/lib/client.js
CHANGED
|
@@ -282,7 +282,9 @@ class Client extends Dispatcher {
|
|
|
282
282
|
handler = new RedirectHandler(this, maxRedirections, opts, handler)
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
const
|
|
285
|
+
const origin = opts.origin || this[kUrl].origin
|
|
286
|
+
|
|
287
|
+
const request = new Request(origin, opts, handler)
|
|
286
288
|
|
|
287
289
|
this[kQueue].push(request)
|
|
288
290
|
if (this[kResuming]) {
|
package/lib/core/errors.js
CHANGED
|
@@ -167,6 +167,16 @@ class NotSupportedError extends UndiciError {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
class BalancedPoolMissingUpstreamError extends UndiciError {
|
|
171
|
+
constructor (message) {
|
|
172
|
+
super(message)
|
|
173
|
+
Error.captureStackTrace(this, NotSupportedError)
|
|
174
|
+
this.name = 'MissingUpstreamError'
|
|
175
|
+
this.message = message || 'No upstream has been added to the BalancedPool'
|
|
176
|
+
this.code = 'UND_ERR_BPL_MISSING_UPSTREAM'
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
170
180
|
class HTTPParserError extends Error {
|
|
171
181
|
constructor (message, code, data) {
|
|
172
182
|
super(message)
|
|
@@ -195,5 +205,6 @@ module.exports = {
|
|
|
195
205
|
InformationalError,
|
|
196
206
|
SocketError,
|
|
197
207
|
NotSupportedError,
|
|
198
|
-
ResponseContentLengthMismatchError
|
|
208
|
+
ResponseContentLengthMismatchError,
|
|
209
|
+
BalancedPoolMissingUpstreamError
|
|
199
210
|
}
|
package/lib/core/request.js
CHANGED
|
@@ -27,7 +27,7 @@ try {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
class Request {
|
|
30
|
-
constructor ({
|
|
30
|
+
constructor (origin, {
|
|
31
31
|
path,
|
|
32
32
|
method,
|
|
33
33
|
body,
|
|
@@ -93,6 +93,8 @@ class Request {
|
|
|
93
93
|
|
|
94
94
|
this.path = path
|
|
95
95
|
|
|
96
|
+
this.origin = origin
|
|
97
|
+
|
|
96
98
|
this.idempotent = idempotent == null
|
|
97
99
|
? method === 'HEAD' || method === 'GET'
|
|
98
100
|
: idempotent
|
package/lib/fetch/index.js
CHANGED
|
@@ -1685,6 +1685,7 @@ function httpNetworkFetch (
|
|
|
1685
1685
|
if (decoders.length > 1) {
|
|
1686
1686
|
if (compose) {
|
|
1687
1687
|
this.decoder = compose(...decoders)
|
|
1688
|
+
iterator = this.decoder[Symbol.asyncIterator]()
|
|
1688
1689
|
} else {
|
|
1689
1690
|
this.decoder = new PassThrough()
|
|
1690
1691
|
iterator = pipeline(this.decoder, ...decoders, () => {})[
|
package/lib/llhttp/llhttp.wasm
CHANGED
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/types/agent.d.ts
CHANGED
package/types/api.d.ts
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Client = require('./client')
|
|
2
|
+
import Pool = require('./pool')
|
|
3
|
+
import Dispatcher = require('./dispatcher')
|
|
4
|
+
import { URL } from 'url'
|
|
5
|
+
|
|
6
|
+
export = BalancedPool
|
|
7
|
+
|
|
8
|
+
declare class BalancedPool extends Dispatcher {
|
|
9
|
+
constructor(url: string | URL | string[], options?: Pool.Options);
|
|
10
|
+
|
|
11
|
+
addUpstream(upstream: string): BalancedPool;
|
|
12
|
+
removeUpstream(upstream: string): BalancedPool;
|
|
13
|
+
upstreams: Array<string>;
|
|
14
|
+
|
|
15
|
+
/** `true` after `pool.close()` has been called. */
|
|
16
|
+
closed: boolean;
|
|
17
|
+
/** `true` after `pool.destroyed()` has been called or `pool.close()` has been called and the pool shutdown has completed. */
|
|
18
|
+
destroyed: boolean;
|
|
19
|
+
}
|
package/types/client.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { URL } from 'url'
|
|
2
2
|
import { TlsOptions } from 'tls'
|
|
3
|
-
import Dispatcher
|
|
4
|
-
import
|
|
3
|
+
import Dispatcher = require('./dispatcher')
|
|
4
|
+
import { DispatchOptions, RequestOptions } from './dispatcher'
|
|
5
|
+
import buildConnector = require('./connector')
|
|
5
6
|
|
|
6
7
|
export = Client
|
|
7
8
|
|
package/types/mock-agent.d.ts
CHANGED
package/types/mock-client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import Client
|
|
2
|
-
import Dispatcher
|
|
3
|
-
import MockAgent
|
|
1
|
+
import Client = require('./client')
|
|
2
|
+
import Dispatcher = require('./dispatcher')
|
|
3
|
+
import MockAgent = require('./mock-agent')
|
|
4
4
|
import { MockInterceptor, Interceptable } from './mock-interceptor'
|
|
5
5
|
|
|
6
6
|
export = MockClient
|
package/types/mock-pool.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import Pool
|
|
2
|
-
import MockAgent
|
|
1
|
+
import Pool = require('./pool')
|
|
2
|
+
import MockAgent = require('./mock-agent')
|
|
3
3
|
import { Interceptable, MockInterceptor } from './mock-interceptor'
|
|
4
|
-
import Dispatcher
|
|
4
|
+
import Dispatcher = require('./dispatcher')
|
|
5
5
|
|
|
6
6
|
export = MockPool
|
|
7
7
|
|
package/types/pool.d.ts
CHANGED