undici 7.15.0 → 7.17.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/README.md +48 -2
- package/docs/docs/api/Agent.md +1 -0
- package/docs/docs/api/Client.md +1 -0
- package/docs/docs/api/DiagnosticsChannel.md +57 -0
- package/docs/docs/api/Dispatcher.md +86 -0
- package/docs/docs/api/Errors.md +0 -1
- package/docs/docs/api/RoundRobinPool.md +145 -0
- package/docs/docs/api/WebSocket.md +21 -0
- package/docs/docs/best-practices/crawling.md +58 -0
- package/index-fetch.js +2 -2
- package/index.js +8 -9
- package/lib/api/api-request.js +22 -8
- package/lib/api/api-upgrade.js +2 -1
- package/lib/api/readable.js +7 -5
- package/lib/core/connect.js +4 -1
- package/lib/core/diagnostics.js +28 -1
- package/lib/core/errors.js +217 -13
- package/lib/core/request.js +5 -1
- package/lib/core/symbols.js +3 -0
- package/lib/core/util.js +61 -41
- package/lib/dispatcher/agent.js +19 -7
- package/lib/dispatcher/balanced-pool.js +10 -0
- package/lib/dispatcher/client-h1.js +18 -23
- package/lib/dispatcher/client-h2.js +166 -26
- package/lib/dispatcher/client.js +64 -59
- package/lib/dispatcher/dispatcher-base.js +20 -16
- package/lib/dispatcher/env-http-proxy-agent.js +12 -16
- package/lib/dispatcher/fixed-queue.js +15 -39
- package/lib/dispatcher/h2c-client.js +7 -78
- package/lib/dispatcher/pool-base.js +60 -43
- package/lib/dispatcher/pool.js +2 -2
- package/lib/dispatcher/proxy-agent.js +27 -11
- package/lib/dispatcher/round-robin-pool.js +137 -0
- package/lib/encoding/index.js +33 -0
- package/lib/global.js +19 -1
- package/lib/handler/cache-handler.js +84 -27
- package/lib/handler/deduplication-handler.js +216 -0
- package/lib/handler/retry-handler.js +0 -2
- package/lib/interceptor/cache.js +94 -15
- package/lib/interceptor/decompress.js +2 -1
- package/lib/interceptor/deduplicate.js +109 -0
- package/lib/interceptor/dns.js +55 -13
- package/lib/mock/mock-agent.js +4 -4
- package/lib/mock/mock-errors.js +10 -0
- package/lib/mock/mock-utils.js +13 -12
- package/lib/mock/snapshot-agent.js +11 -5
- package/lib/mock/snapshot-recorder.js +12 -4
- package/lib/mock/snapshot-utils.js +4 -4
- package/lib/util/cache.js +29 -1
- package/lib/util/date.js +534 -140
- package/lib/util/runtime-features.js +124 -0
- package/lib/web/cookies/index.js +1 -1
- package/lib/web/cookies/parse.js +1 -1
- package/lib/web/eventsource/eventsource-stream.js +2 -2
- package/lib/web/eventsource/eventsource.js +34 -29
- package/lib/web/eventsource/util.js +1 -9
- package/lib/web/fetch/body.js +45 -61
- package/lib/web/fetch/data-url.js +12 -160
- package/lib/web/fetch/formdata-parser.js +204 -127
- package/lib/web/fetch/index.js +21 -19
- package/lib/web/fetch/request.js +6 -0
- package/lib/web/fetch/response.js +4 -7
- package/lib/web/fetch/util.js +10 -79
- package/lib/web/infra/index.js +229 -0
- package/lib/web/subresource-integrity/subresource-integrity.js +6 -5
- package/lib/web/webidl/index.js +207 -44
- package/lib/web/websocket/connection.js +33 -22
- package/lib/web/websocket/events.js +1 -1
- package/lib/web/websocket/frame.js +9 -15
- package/lib/web/websocket/stream/websocketerror.js +22 -1
- package/lib/web/websocket/stream/websocketstream.js +17 -8
- package/lib/web/websocket/util.js +2 -1
- package/lib/web/websocket/websocket.js +32 -42
- package/package.json +9 -7
- package/types/agent.d.ts +2 -1
- package/types/api.d.ts +2 -2
- package/types/balanced-pool.d.ts +2 -1
- package/types/cache-interceptor.d.ts +1 -0
- package/types/client.d.ts +1 -1
- package/types/connector.d.ts +2 -2
- package/types/diagnostics-channel.d.ts +2 -2
- package/types/dispatcher.d.ts +12 -12
- package/types/errors.d.ts +5 -15
- package/types/fetch.d.ts +4 -4
- package/types/formdata.d.ts +1 -1
- package/types/h2c-client.d.ts +1 -1
- package/types/index.d.ts +9 -1
- package/types/interceptors.d.ts +36 -2
- package/types/pool.d.ts +1 -1
- package/types/readable.d.ts +2 -2
- package/types/round-robin-pool.d.ts +41 -0
- package/types/webidl.d.ts +82 -21
- package/types/websocket.d.ts +9 -9
|
@@ -6,13 +6,12 @@ const { states, opcodes, sentCloseFrameState } = require('../constants')
|
|
|
6
6
|
const { webidl } = require('../../webidl')
|
|
7
7
|
const { getURLRecord, isValidSubprotocol, isEstablished, utf8Decode } = require('../util')
|
|
8
8
|
const { establishWebSocketConnection, failWebsocketConnection, closeWebSocketConnection } = require('../connection')
|
|
9
|
-
const { isArrayBuffer } = require('node:util/types')
|
|
10
9
|
const { channels } = require('../../../core/diagnostics')
|
|
11
10
|
const { WebsocketFrameSend } = require('../frame')
|
|
12
11
|
const { ByteParser } = require('../receiver')
|
|
13
12
|
const { WebSocketError, createUnvalidatedWebSocketError } = require('./websocketerror')
|
|
14
|
-
const { utf8DecodeBytes } = require('../../fetch/util')
|
|
15
13
|
const { kEnumerableProperty } = require('../../../core/util')
|
|
14
|
+
const { utf8DecodeBytes } = require('../../../encoding')
|
|
16
15
|
|
|
17
16
|
let emittedExperimentalWarning = false
|
|
18
17
|
|
|
@@ -46,7 +45,6 @@ class WebSocketStream {
|
|
|
46
45
|
#handler = {
|
|
47
46
|
// https://whatpr.org/websockets/48/7b748d3...d5570f3.html#feedback-to-websocket-stream-from-the-protocol
|
|
48
47
|
onConnectionEstablished: (response, extensions) => this.#onConnectionEstablished(response, extensions),
|
|
49
|
-
onFail: (_code, _reason) => {},
|
|
50
48
|
onMessage: (opcode, data) => this.#onMessage(opcode, data),
|
|
51
49
|
onParserError: (err) => failWebsocketConnection(this.#handler, null, err.message),
|
|
52
50
|
onParserDrain: () => this.#handler.socket.resume(),
|
|
@@ -200,6 +198,9 @@ class WebSocketStream {
|
|
|
200
198
|
}
|
|
201
199
|
|
|
202
200
|
#write (chunk) {
|
|
201
|
+
// See /websockets/stream/tentative/write.any.html
|
|
202
|
+
chunk = webidl.converters.WebSocketStreamWrite(chunk)
|
|
203
|
+
|
|
203
204
|
// 1. Let promise be a new promise created in stream ’s relevant realm .
|
|
204
205
|
const promise = createDeferredPromise()
|
|
205
206
|
|
|
@@ -210,9 +211,9 @@ class WebSocketStream {
|
|
|
210
211
|
let opcode = null
|
|
211
212
|
|
|
212
213
|
// 4. If chunk is a BufferSource ,
|
|
213
|
-
if (
|
|
214
|
+
if (webidl.is.BufferSource(chunk)) {
|
|
214
215
|
// 4.1. Set data to a copy of the bytes given chunk .
|
|
215
|
-
data = new Uint8Array(ArrayBuffer.isView(chunk) ? new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength) : chunk)
|
|
216
|
+
data = new Uint8Array(ArrayBuffer.isView(chunk) ? new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength) : chunk.slice())
|
|
216
217
|
|
|
217
218
|
// 4.2. Set opcode to a binary frame opcode.
|
|
218
219
|
opcode = opcodes.BINARY
|
|
@@ -227,7 +228,7 @@ class WebSocketStream {
|
|
|
227
228
|
string = webidl.converters.DOMString(chunk)
|
|
228
229
|
} catch (e) {
|
|
229
230
|
promise.reject(e)
|
|
230
|
-
return
|
|
231
|
+
return promise.promise
|
|
231
232
|
}
|
|
232
233
|
|
|
233
234
|
// 5.2. Set data to the result of UTF-8 encoding string .
|
|
@@ -250,7 +251,7 @@ class WebSocketStream {
|
|
|
250
251
|
}
|
|
251
252
|
|
|
252
253
|
// 6.3. Queue a global task on the WebSocket task source given stream ’s relevant global object to resolve promise with undefined.
|
|
253
|
-
return promise
|
|
254
|
+
return promise.promise
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
/** @type {import('../websocket').Handler['onConnectionEstablished']} */
|
|
@@ -476,7 +477,7 @@ webidl.converters.WebSocketStreamOptions = webidl.dictionaryConverter([
|
|
|
476
477
|
webidl.converters.WebSocketCloseInfo = webidl.dictionaryConverter([
|
|
477
478
|
{
|
|
478
479
|
key: 'closeCode',
|
|
479
|
-
converter: (V) => webidl.converters['unsigned short'](V,
|
|
480
|
+
converter: (V) => webidl.converters['unsigned short'](V, webidl.attributes.EnforceRange)
|
|
480
481
|
},
|
|
481
482
|
{
|
|
482
483
|
key: 'reason',
|
|
@@ -485,4 +486,12 @@ webidl.converters.WebSocketCloseInfo = webidl.dictionaryConverter([
|
|
|
485
486
|
}
|
|
486
487
|
])
|
|
487
488
|
|
|
489
|
+
webidl.converters.WebSocketStreamWrite = function (V) {
|
|
490
|
+
if (typeof V === 'string') {
|
|
491
|
+
return webidl.converters.USVString(V)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return webidl.converters.BufferSource(V)
|
|
495
|
+
}
|
|
496
|
+
|
|
488
497
|
module.exports = { WebSocketStream }
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { states, opcodes } = require('./constants')
|
|
4
4
|
const { isUtf8 } = require('node:buffer')
|
|
5
|
-
const {
|
|
5
|
+
const { removeHTTPWhitespace } = require('../fetch/data-url')
|
|
6
|
+
const { collectASequenceOfCodePointsFast } = require('../infra')
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @param {number} readyState
|
|
@@ -28,7 +28,6 @@ const { channels } = require('../../core/diagnostics')
|
|
|
28
28
|
/**
|
|
29
29
|
* @typedef {object} Handler
|
|
30
30
|
* @property {(response: any, extensions?: string[]) => void} onConnectionEstablished
|
|
31
|
-
* @property {(code: number, reason: any) => void} onFail
|
|
32
31
|
* @property {(opcode: number, data: Buffer) => void} onMessage
|
|
33
32
|
* @property {(error: Error) => void} onParserError
|
|
34
33
|
* @property {() => void} onParserDrain
|
|
@@ -64,7 +63,6 @@ class WebSocket extends EventTarget {
|
|
|
64
63
|
/** @type {Handler} */
|
|
65
64
|
#handler = {
|
|
66
65
|
onConnectionEstablished: (response, extensions) => this.#onConnectionEstablished(response, extensions),
|
|
67
|
-
onFail: (code, reason, cause) => this.#onFail(code, reason, cause),
|
|
68
66
|
onMessage: (opcode, data) => this.#onMessage(opcode, data),
|
|
69
67
|
onParserError: (err) => failWebsocketConnection(this.#handler, null, err.message),
|
|
70
68
|
onParserDrain: () => this.#onParserDrain(),
|
|
@@ -195,7 +193,7 @@ class WebSocket extends EventTarget {
|
|
|
195
193
|
const prefix = 'WebSocket.close'
|
|
196
194
|
|
|
197
195
|
if (code !== undefined) {
|
|
198
|
-
code = webidl.converters['unsigned short'](code, prefix, 'code',
|
|
196
|
+
code = webidl.converters['unsigned short'](code, prefix, 'code', webidl.attributes.Clamp)
|
|
199
197
|
}
|
|
200
198
|
|
|
201
199
|
if (reason !== undefined) {
|
|
@@ -355,9 +353,11 @@ class WebSocket extends EventTarget {
|
|
|
355
353
|
this.removeEventListener('open', this.#events.open)
|
|
356
354
|
}
|
|
357
355
|
|
|
358
|
-
|
|
356
|
+
const listener = webidl.converters.EventHandlerNonNull(fn)
|
|
357
|
+
|
|
358
|
+
if (listener !== null) {
|
|
359
|
+
this.addEventListener('open', listener)
|
|
359
360
|
this.#events.open = fn
|
|
360
|
-
this.addEventListener('open', fn)
|
|
361
361
|
} else {
|
|
362
362
|
this.#events.open = null
|
|
363
363
|
}
|
|
@@ -376,9 +376,11 @@ class WebSocket extends EventTarget {
|
|
|
376
376
|
this.removeEventListener('error', this.#events.error)
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
|
|
379
|
+
const listener = webidl.converters.EventHandlerNonNull(fn)
|
|
380
|
+
|
|
381
|
+
if (listener !== null) {
|
|
382
|
+
this.addEventListener('error', listener)
|
|
380
383
|
this.#events.error = fn
|
|
381
|
-
this.addEventListener('error', fn)
|
|
382
384
|
} else {
|
|
383
385
|
this.#events.error = null
|
|
384
386
|
}
|
|
@@ -397,9 +399,11 @@ class WebSocket extends EventTarget {
|
|
|
397
399
|
this.removeEventListener('close', this.#events.close)
|
|
398
400
|
}
|
|
399
401
|
|
|
400
|
-
|
|
402
|
+
const listener = webidl.converters.EventHandlerNonNull(fn)
|
|
403
|
+
|
|
404
|
+
if (listener !== null) {
|
|
405
|
+
this.addEventListener('close', listener)
|
|
401
406
|
this.#events.close = fn
|
|
402
|
-
this.addEventListener('close', fn)
|
|
403
407
|
} else {
|
|
404
408
|
this.#events.close = null
|
|
405
409
|
}
|
|
@@ -418,9 +422,11 @@ class WebSocket extends EventTarget {
|
|
|
418
422
|
this.removeEventListener('message', this.#events.message)
|
|
419
423
|
}
|
|
420
424
|
|
|
421
|
-
|
|
425
|
+
const listener = webidl.converters.EventHandlerNonNull(fn)
|
|
426
|
+
|
|
427
|
+
if (listener !== null) {
|
|
428
|
+
this.addEventListener('message', listener)
|
|
422
429
|
this.#events.message = fn
|
|
423
|
-
this.addEventListener('message', fn)
|
|
424
430
|
} else {
|
|
425
431
|
this.#events.message = null
|
|
426
432
|
}
|
|
@@ -498,26 +504,6 @@ class WebSocket extends EventTarget {
|
|
|
498
504
|
}
|
|
499
505
|
}
|
|
500
506
|
|
|
501
|
-
#onFail (code, reason, cause) {
|
|
502
|
-
if (reason) {
|
|
503
|
-
// TODO: process.nextTick
|
|
504
|
-
fireEvent('error', this, (type, init) => new ErrorEvent(type, init), {
|
|
505
|
-
error: new Error(reason, cause ? { cause } : undefined),
|
|
506
|
-
message: reason
|
|
507
|
-
})
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
if (!this.#handler.wasEverConnected) {
|
|
511
|
-
this.#handler.readyState = states.CLOSED
|
|
512
|
-
|
|
513
|
-
// If the WebSocket connection could not be established, it is also said
|
|
514
|
-
// that _The WebSocket Connection is Closed_, but not _cleanly_.
|
|
515
|
-
fireEvent('close', this, (type, init) => new CloseEvent(type, init), {
|
|
516
|
-
wasClean: false, code, reason
|
|
517
|
-
})
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
507
|
#onMessage (type, data) {
|
|
522
508
|
// 1. If ready state is not OPEN (1), then return.
|
|
523
509
|
if (this.#handler.readyState !== states.OPEN) {
|
|
@@ -578,18 +564,11 @@ class WebSocket extends EventTarget {
|
|
|
578
564
|
let code = 1005
|
|
579
565
|
let reason = ''
|
|
580
566
|
|
|
581
|
-
const result = this.#parser
|
|
567
|
+
const result = this.#parser?.closingInfo
|
|
582
568
|
|
|
583
569
|
if (result && !result.error) {
|
|
584
570
|
code = result.code ?? 1005
|
|
585
571
|
reason = result.reason
|
|
586
|
-
} else if (!this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
|
|
587
|
-
// If _The WebSocket
|
|
588
|
-
// Connection is Closed_ and no Close control frame was received by the
|
|
589
|
-
// endpoint (such as could occur if the underlying transport connection
|
|
590
|
-
// is lost), _The WebSocket Connection Close Code_ is considered to be
|
|
591
|
-
// 1006.
|
|
592
|
-
code = 1006
|
|
593
572
|
}
|
|
594
573
|
|
|
595
574
|
// 1. Change the ready state to CLOSED (3).
|
|
@@ -599,7 +578,18 @@ class WebSocket extends EventTarget {
|
|
|
599
578
|
// connection, or if the WebSocket connection was closed
|
|
600
579
|
// after being flagged as full, fire an event named error
|
|
601
580
|
// at the WebSocket object.
|
|
602
|
-
|
|
581
|
+
if (!this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
|
|
582
|
+
// If _The WebSocket
|
|
583
|
+
// Connection is Closed_ and no Close control frame was received by the
|
|
584
|
+
// endpoint (such as could occur if the underlying transport connection
|
|
585
|
+
// is lost), _The WebSocket Connection Close Code_ is considered to be
|
|
586
|
+
// 1006.
|
|
587
|
+
code = 1006
|
|
588
|
+
|
|
589
|
+
fireEvent('error', this, (type, init) => new ErrorEvent(type, init), {
|
|
590
|
+
error: new TypeError(reason)
|
|
591
|
+
})
|
|
592
|
+
}
|
|
603
593
|
|
|
604
594
|
// 3. Fire an event named close at the WebSocket object,
|
|
605
595
|
// using CloseEvent, with the wasClean attribute
|
|
@@ -708,7 +698,7 @@ webidl.converters.WebSocketInit = webidl.dictionaryConverter([
|
|
|
708
698
|
{
|
|
709
699
|
key: 'protocols',
|
|
710
700
|
converter: webidl.converters['DOMString or sequence<DOMString>'],
|
|
711
|
-
defaultValue: () =>
|
|
701
|
+
defaultValue: () => []
|
|
712
702
|
},
|
|
713
703
|
{
|
|
714
704
|
key: 'dispatcher',
|
|
@@ -735,7 +725,7 @@ webidl.converters.WebSocketSendData = function (V) {
|
|
|
735
725
|
return V
|
|
736
726
|
}
|
|
737
727
|
|
|
738
|
-
if (
|
|
728
|
+
if (webidl.is.BufferSource(V)) {
|
|
739
729
|
return V
|
|
740
730
|
}
|
|
741
731
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "undici",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.17.0",
|
|
4
4
|
"description": "An HTTP/1.1 client, written from scratch for Node.js",
|
|
5
5
|
"homepage": "https://undici.nodejs.org",
|
|
6
6
|
"bugs": {
|
|
@@ -67,14 +67,14 @@
|
|
|
67
67
|
"generate-pem": "node scripts/generate-pem.js",
|
|
68
68
|
"lint": "eslint --cache",
|
|
69
69
|
"lint:fix": "eslint --fix --cache",
|
|
70
|
-
"test": "npm run test:javascript && cross-env NODE_V8_COVERAGE=
|
|
70
|
+
"test": "npm run test:javascript && cross-env NODE_V8_COVERAGE= npm run test:typescript",
|
|
71
71
|
"test:javascript": "npm run test:javascript:no-jest && npm run test:jest",
|
|
72
|
-
"test:javascript:no-jest": "npm run generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:
|
|
72
|
+
"test:javascript:no-jest": "npm run generate-pem && npm run test:unit && npm run test:fetch && npm run test:node-fetch && npm run test:infra && npm run test:cache && npm run test:cache-interceptor && npm run test:interceptors && npm run test:cookies && npm run test:eventsource && npm run test:subresource-integrity && npm run test:wpt && npm run test:websocket && npm run test:node-test && npm run test:cache-tests",
|
|
73
73
|
"test:javascript:without-intl": "npm run test:javascript:no-jest",
|
|
74
74
|
"test:busboy": "borp -p \"test/busboy/*.js\"",
|
|
75
75
|
"test:cache": "borp -p \"test/cache/*.js\"",
|
|
76
|
-
"test:sqlite": "NODE_OPTIONS=--experimental-sqlite borp -p \"test/cache-interceptor/*.js\"",
|
|
77
76
|
"test:cache-interceptor": "borp -p \"test/cache-interceptor/*.js\"",
|
|
77
|
+
"test:cache-interceptor:sqlite": "cross-env NODE_OPTIONS=--experimental-sqlite npm run test:cache-interceptor",
|
|
78
78
|
"test:cookies": "borp -p \"test/cookie/*.js\"",
|
|
79
79
|
"test:eventsource": "npm run build:node && borp --expose-gc -p \"test/eventsource/*.js\"",
|
|
80
80
|
"test:fuzzing": "node test/fuzzing/fuzzing.test.js",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"test:h2": "npm run test:h2:core && npm run test:h2:fetch",
|
|
84
84
|
"test:h2:core": "borp -p \"test/+(http2|h2)*.js\"",
|
|
85
85
|
"test:h2:fetch": "npm run build:node && borp -p \"test/fetch/http2*.js\"",
|
|
86
|
+
"test:infra": "borp -p \"test/infra/*.js\"",
|
|
86
87
|
"test:interceptors": "borp -p \"test/interceptors/*.js\"",
|
|
87
88
|
"test:jest": "cross-env NODE_V8_COVERAGE= jest",
|
|
88
89
|
"test:unit": "borp --expose-gc -p \"test/*.js\"",
|
|
@@ -95,8 +96,8 @@
|
|
|
95
96
|
"test:websocket": "borp -p \"test/websocket/**/*.js\"",
|
|
96
97
|
"test:websocket:autobahn": "node test/autobahn/client.js",
|
|
97
98
|
"test:websocket:autobahn:report": "node test/autobahn/report.js",
|
|
98
|
-
"test:wpt": "node test/
|
|
99
|
-
"test:wpt
|
|
99
|
+
"test:wpt:setup": "node test/web-platform-tests/wpt-runner.mjs setup",
|
|
100
|
+
"test:wpt": "npm run test:wpt:setup && node test/web-platform-tests/wpt-runner.mjs run /fetch /mimesniff /xhr /websockets /serviceWorkers /eventsource",
|
|
100
101
|
"test:cache-tests": "node test/cache-interceptor/cache-tests.mjs --ci",
|
|
101
102
|
"coverage": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report",
|
|
102
103
|
"coverage:ci": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report:ci",
|
|
@@ -112,7 +113,7 @@
|
|
|
112
113
|
"@matteo.collina/tspl": "^0.2.0",
|
|
113
114
|
"@metcoder95/https-pem": "^1.0.0",
|
|
114
115
|
"@sinonjs/fake-timers": "^12.0.0",
|
|
115
|
-
"@types/node": "^
|
|
116
|
+
"@types/node": "^20.19.22",
|
|
116
117
|
"abort-controller": "^3.0.0",
|
|
117
118
|
"borp": "^0.20.0",
|
|
118
119
|
"c8": "^10.0.0",
|
|
@@ -123,6 +124,7 @@
|
|
|
123
124
|
"fast-check": "^4.1.1",
|
|
124
125
|
"husky": "^9.0.7",
|
|
125
126
|
"jest": "^30.0.5",
|
|
127
|
+
"jsondiffpatch": "^0.7.3",
|
|
126
128
|
"neostandard": "^0.12.0",
|
|
127
129
|
"node-forge": "^1.3.1",
|
|
128
130
|
"proxy": "^2.1.1",
|
package/types/agent.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { URL } from 'url'
|
|
1
|
+
import { URL } from 'node:url'
|
|
2
2
|
import Pool from './pool'
|
|
3
3
|
import Dispatcher from './dispatcher'
|
|
4
4
|
import TClientStats from './client-stats'
|
|
@@ -24,6 +24,7 @@ declare namespace Agent {
|
|
|
24
24
|
factory?(origin: string | URL, opts: Object): Dispatcher;
|
|
25
25
|
|
|
26
26
|
interceptors?: { Agent?: readonly Dispatcher.DispatchInterceptor[] } & Pool.Options['interceptors']
|
|
27
|
+
maxOrigins?: number
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export interface DispatchOptions extends Dispatcher.DispatchOptions {
|
package/types/api.d.ts
CHANGED
package/types/balanced-pool.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Pool from './pool'
|
|
2
2
|
import Dispatcher from './dispatcher'
|
|
3
|
-
import { URL } from 'url'
|
|
3
|
+
import { URL } from 'node:url'
|
|
4
4
|
|
|
5
5
|
export default BalancedPool
|
|
6
6
|
|
|
@@ -11,6 +11,7 @@ declare class BalancedPool extends Dispatcher {
|
|
|
11
11
|
|
|
12
12
|
addUpstream (upstream: string | URL): BalancedPool
|
|
13
13
|
removeUpstream (upstream: string | URL): BalancedPool
|
|
14
|
+
getUpstream (upstream: string | URL): Pool | undefined
|
|
14
15
|
upstreams: Array<string>
|
|
15
16
|
|
|
16
17
|
/** `true` after `pool.close()` has been called. */
|
package/types/client.d.ts
CHANGED
package/types/connector.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TLSSocket, ConnectionOptions } from 'tls'
|
|
2
|
-
import { IpcNetConnectOpts, Socket, TcpNetConnectOpts } from 'net'
|
|
1
|
+
import { TLSSocket, ConnectionOptions } from 'node:tls'
|
|
2
|
+
import { IpcNetConnectOpts, Socket, TcpNetConnectOpts } from 'node:net'
|
|
3
3
|
|
|
4
4
|
export default buildConnector
|
|
5
5
|
declare function buildConnector (options?: buildConnector.BuildOptions): buildConnector.connector
|
package/types/dispatcher.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { URL } from 'url'
|
|
2
|
-
import { Duplex, Readable, Writable } from 'stream'
|
|
3
|
-
import { EventEmitter } from 'events'
|
|
4
|
-
import { Blob } from 'buffer'
|
|
1
|
+
import { URL } from 'node:url'
|
|
2
|
+
import { Duplex, Readable, Writable } from 'node:stream'
|
|
3
|
+
import { EventEmitter } from 'node:events'
|
|
4
|
+
import { Blob } from 'node:buffer'
|
|
5
5
|
import { IncomingHttpHeaders } from './header'
|
|
6
6
|
import BodyReadable from './readable'
|
|
7
7
|
import { FormData } from './formdata'
|
|
@@ -19,30 +19,30 @@ declare class Dispatcher extends EventEmitter {
|
|
|
19
19
|
/** Dispatches a request. This API is expected to evolve through semver-major versions and is less stable than the preceding higher level APIs. It is primarily intended for library developers who implement higher level APIs on top of this. */
|
|
20
20
|
dispatch (options: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandler): boolean
|
|
21
21
|
/** Starts two-way communications with the requested resource. */
|
|
22
|
-
connect<TOpaque = null>(options: Dispatcher.ConnectOptions<TOpaque>): Promise<Dispatcher.ConnectData<TOpaque>>
|
|
23
22
|
connect<TOpaque = null>(options: Dispatcher.ConnectOptions<TOpaque>, callback: (err: Error | null, data: Dispatcher.ConnectData<TOpaque>) => void): void
|
|
23
|
+
connect<TOpaque = null>(options: Dispatcher.ConnectOptions<TOpaque>): Promise<Dispatcher.ConnectData<TOpaque>>
|
|
24
24
|
/** Compose a chain of dispatchers */
|
|
25
25
|
compose (dispatchers: Dispatcher.DispatcherComposeInterceptor[]): Dispatcher.ComposedDispatcher
|
|
26
26
|
compose (...dispatchers: Dispatcher.DispatcherComposeInterceptor[]): Dispatcher.ComposedDispatcher
|
|
27
27
|
/** Performs an HTTP request. */
|
|
28
|
-
request<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>): Promise<Dispatcher.ResponseData<TOpaque>>
|
|
29
28
|
request<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, callback: (err: Error | null, data: Dispatcher.ResponseData<TOpaque>) => void): void
|
|
29
|
+
request<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>): Promise<Dispatcher.ResponseData<TOpaque>>
|
|
30
30
|
/** For easy use with `stream.pipeline`. */
|
|
31
31
|
pipeline<TOpaque = null>(options: Dispatcher.PipelineOptions<TOpaque>, handler: Dispatcher.PipelineHandler<TOpaque>): Duplex
|
|
32
32
|
/** A faster version of `Dispatcher.request`. */
|
|
33
|
-
stream<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, factory: Dispatcher.StreamFactory<TOpaque>): Promise<Dispatcher.StreamData<TOpaque>>
|
|
34
33
|
stream<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, factory: Dispatcher.StreamFactory<TOpaque>, callback: (err: Error | null, data: Dispatcher.StreamData<TOpaque>) => void): void
|
|
34
|
+
stream<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, factory: Dispatcher.StreamFactory<TOpaque>): Promise<Dispatcher.StreamData<TOpaque>>
|
|
35
35
|
/** Upgrade to a different protocol. */
|
|
36
|
-
upgrade (options: Dispatcher.UpgradeOptions): Promise<Dispatcher.UpgradeData>
|
|
37
36
|
upgrade (options: Dispatcher.UpgradeOptions, callback: (err: Error | null, data: Dispatcher.UpgradeData) => void): void
|
|
37
|
+
upgrade (options: Dispatcher.UpgradeOptions): Promise<Dispatcher.UpgradeData>
|
|
38
38
|
/** Closes the client and gracefully waits for enqueued requests to complete before invoking the callback (or returning a promise if no callback is provided). */
|
|
39
|
-
close (): Promise<void>
|
|
40
39
|
close (callback: () => void): void
|
|
40
|
+
close (): Promise<void>
|
|
41
41
|
/** Destroy the client abruptly with the given err. All the pending and running requests will be asynchronously aborted and error. Waits until socket is closed before invoking the callback (or returning a promise if no callback is provided). Since this operation is asynchronously dispatched there might still be some progress on dispatched requests. */
|
|
42
|
-
destroy (): Promise<void>
|
|
43
|
-
destroy (err: Error | null): Promise<void>
|
|
44
|
-
destroy (callback: () => void): void
|
|
45
42
|
destroy (err: Error | null, callback: () => void): void
|
|
43
|
+
destroy (callback: () => void): void
|
|
44
|
+
destroy (err: Error | null): Promise<void>
|
|
45
|
+
destroy (): Promise<void>
|
|
46
46
|
|
|
47
47
|
on (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
|
48
48
|
on (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
package/types/errors.d.ts
CHANGED
|
@@ -49,21 +49,6 @@ declare namespace Errors {
|
|
|
49
49
|
headers: IncomingHttpHeaders | string[] | null
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export class ResponseStatusCodeError extends UndiciError {
|
|
53
|
-
constructor (
|
|
54
|
-
message?: string,
|
|
55
|
-
statusCode?: number,
|
|
56
|
-
headers?: IncomingHttpHeaders | string[] | null,
|
|
57
|
-
body?: null | Record<string, any> | string
|
|
58
|
-
)
|
|
59
|
-
name: 'ResponseStatusCodeError'
|
|
60
|
-
code: 'UND_ERR_RESPONSE_STATUS_CODE'
|
|
61
|
-
body: null | Record<string, any> | string
|
|
62
|
-
status: number
|
|
63
|
-
statusCode: number
|
|
64
|
-
headers: IncomingHttpHeaders | string[] | null
|
|
65
|
-
}
|
|
66
|
-
|
|
67
52
|
/** Passed an invalid argument. */
|
|
68
53
|
export class InvalidArgumentError extends UndiciError {
|
|
69
54
|
name: 'InvalidArgumentError'
|
|
@@ -168,4 +153,9 @@ declare namespace Errors {
|
|
|
168
153
|
name: 'SecureProxyConnectionError'
|
|
169
154
|
code: 'UND_ERR_PRX_TLS'
|
|
170
155
|
}
|
|
156
|
+
|
|
157
|
+
class MaxOriginsReachedError extends UndiciError {
|
|
158
|
+
name: 'MaxOriginsReachedError'
|
|
159
|
+
code: 'UND_ERR_MAX_ORIGINS_REACHED'
|
|
160
|
+
}
|
|
171
161
|
}
|
package/types/fetch.d.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// and https://github.com/node-fetch/node-fetch/blob/914ce6be5ec67a8bab63d68510aabf07cb818b6d/index.d.ts (MIT license)
|
|
3
3
|
/// <reference types="node" />
|
|
4
4
|
|
|
5
|
-
import { Blob } from 'buffer'
|
|
6
|
-
import { URL, URLSearchParams } from 'url'
|
|
7
|
-
import { ReadableStream } from 'stream/web'
|
|
5
|
+
import { Blob } from 'node:buffer'
|
|
6
|
+
import { URL, URLSearchParams } from 'node:url'
|
|
7
|
+
import { ReadableStream } from 'node:stream/web'
|
|
8
8
|
import { FormData } from './formdata'
|
|
9
9
|
import { HeaderRecord } from './header'
|
|
10
10
|
import Dispatcher from './dispatcher'
|
|
@@ -207,5 +207,5 @@ export declare class Response extends BodyMixin {
|
|
|
207
207
|
|
|
208
208
|
static error (): Response
|
|
209
209
|
static json (data: any, init?: ResponseInit): Response
|
|
210
|
-
static redirect (url: string | URL, status
|
|
210
|
+
static redirect (url: string | URL, status?: ResponseRedirectStatus): Response
|
|
211
211
|
}
|
package/types/formdata.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Based on https://github.com/octet-stream/form-data/blob/2d0f0dc371517444ce1f22cdde13f51995d0953a/lib/FormData.ts (MIT)
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
|
|
4
|
-
import { File } from 'buffer'
|
|
4
|
+
import { File } from 'node:buffer'
|
|
5
5
|
import { SpecIterableIterator } from './fetch'
|
|
6
6
|
|
|
7
7
|
/**
|
package/types/h2c-client.d.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import Pool from './pool'
|
|
|
5
5
|
import { RedirectHandler, DecoratorHandler } from './handlers'
|
|
6
6
|
|
|
7
7
|
import BalancedPool from './balanced-pool'
|
|
8
|
+
import RoundRobinPool from './round-robin-pool'
|
|
8
9
|
import Client from './client'
|
|
9
10
|
import H2CClient from './h2c-client'
|
|
10
11
|
import buildConnector from './connector'
|
|
@@ -23,6 +24,12 @@ import RetryAgent from './retry-agent'
|
|
|
23
24
|
import { request, pipeline, stream, connect, upgrade } from './api'
|
|
24
25
|
import interceptors from './interceptors'
|
|
25
26
|
|
|
27
|
+
import CacheInterceptor from './cache-interceptor'
|
|
28
|
+
declare const cacheStores: {
|
|
29
|
+
MemoryCacheStore: typeof CacheInterceptor.MemoryCacheStore;
|
|
30
|
+
SqliteCacheStore: typeof CacheInterceptor.SqliteCacheStore;
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
export * from './util'
|
|
27
34
|
export * from './cookies'
|
|
28
35
|
export * from './eventsource'
|
|
@@ -36,7 +43,7 @@ export { Interceptable } from './mock-interceptor'
|
|
|
36
43
|
|
|
37
44
|
declare function globalThisInstall (): void
|
|
38
45
|
|
|
39
|
-
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, interceptors, MockClient, MockPool, MockAgent, SnapshotAgent, MockCallHistory, MockCallHistoryLog, mockErrors, ProxyAgent, EnvHttpProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent, H2CClient, globalThisInstall as install }
|
|
46
|
+
export { Dispatcher, BalancedPool, RoundRobinPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, interceptors, cacheStores, MockClient, MockPool, MockAgent, SnapshotAgent, MockCallHistory, MockCallHistoryLog, mockErrors, ProxyAgent, EnvHttpProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent, H2CClient, globalThisInstall as install }
|
|
40
47
|
export default Undici
|
|
41
48
|
|
|
42
49
|
declare namespace Undici {
|
|
@@ -46,6 +53,7 @@ declare namespace Undici {
|
|
|
46
53
|
const DecoratorHandler: typeof import ('./handlers').DecoratorHandler
|
|
47
54
|
const RetryHandler: typeof import ('./retry-handler').default
|
|
48
55
|
const BalancedPool: typeof import('./balanced-pool').default
|
|
56
|
+
const RoundRobinPool: typeof import('./round-robin-pool').default
|
|
49
57
|
const Client: typeof import('./client').default
|
|
50
58
|
const H2CClient: typeof import('./h2c-client').default
|
|
51
59
|
const buildConnector: typeof import('./connector').default
|
package/types/interceptors.d.ts
CHANGED
|
@@ -19,14 +19,47 @@ declare namespace Interceptors {
|
|
|
19
19
|
|
|
20
20
|
// DNS interceptor
|
|
21
21
|
export type DNSInterceptorRecord = { address: string, ttl: number, family: 4 | 6 }
|
|
22
|
-
export type DNSInterceptorOriginRecords = { 4: { ips: DNSInterceptorRecord[] } | null, 6: { ips: DNSInterceptorRecord[] } | null }
|
|
22
|
+
export type DNSInterceptorOriginRecords = { records: { 4: { ips: DNSInterceptorRecord[] } | null, 6: { ips: DNSInterceptorRecord[] } | null } }
|
|
23
|
+
export type DNSStorage = {
|
|
24
|
+
size: number
|
|
25
|
+
get(origin: string): DNSInterceptorOriginRecords | null
|
|
26
|
+
set(origin: string, records: DNSInterceptorOriginRecords | null, options: { ttl: number }): void
|
|
27
|
+
delete(origin: string): void
|
|
28
|
+
full(): boolean
|
|
29
|
+
}
|
|
23
30
|
export type DNSInterceptorOpts = {
|
|
24
31
|
maxTTL?: number
|
|
25
32
|
maxItems?: number
|
|
26
|
-
lookup?: (
|
|
33
|
+
lookup?: (origin: URL, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void
|
|
27
34
|
pick?: (origin: URL, records: DNSInterceptorOriginRecords, affinity: 4 | 6) => DNSInterceptorRecord
|
|
28
35
|
dualStack?: boolean
|
|
29
36
|
affinity?: 4 | 6
|
|
37
|
+
storage?: DNSStorage
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Deduplicate interceptor
|
|
41
|
+
export type DeduplicateMethods = 'GET' | 'HEAD' | 'OPTIONS' | 'TRACE'
|
|
42
|
+
export type DeduplicateInterceptorOpts = {
|
|
43
|
+
/**
|
|
44
|
+
* The HTTP methods to deduplicate.
|
|
45
|
+
* Note: Only safe HTTP methods can be deduplicated.
|
|
46
|
+
* @default ['GET']
|
|
47
|
+
*/
|
|
48
|
+
methods?: DeduplicateMethods[]
|
|
49
|
+
/**
|
|
50
|
+
* Header names that, if present in a request, will cause the request to skip deduplication.
|
|
51
|
+
* Header name matching is case-insensitive.
|
|
52
|
+
* @default []
|
|
53
|
+
*/
|
|
54
|
+
skipHeaderNames?: string[]
|
|
55
|
+
/**
|
|
56
|
+
* Header names to exclude from the deduplication key.
|
|
57
|
+
* Requests with different values for these headers will still be deduplicated together.
|
|
58
|
+
* Useful for headers like `x-request-id` that vary per request but shouldn't affect deduplication.
|
|
59
|
+
* Header name matching is case-insensitive.
|
|
60
|
+
* @default []
|
|
61
|
+
*/
|
|
62
|
+
excludeHeaderNames?: string[]
|
|
30
63
|
}
|
|
31
64
|
|
|
32
65
|
export function dump (opts?: DumpInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
@@ -36,4 +69,5 @@ declare namespace Interceptors {
|
|
|
36
69
|
export function responseError (opts?: ResponseErrorInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
37
70
|
export function dns (opts?: DNSInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
38
71
|
export function cache (opts?: CacheInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
72
|
+
export function deduplicate (opts?: DeduplicateInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
39
73
|
}
|
package/types/pool.d.ts
CHANGED
package/types/readable.d.ts
CHANGED