undici 6.6.2 → 6.7.1

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.
Files changed (117) hide show
  1. package/README.md +49 -27
  2. package/docs/{api → docs/api}/DiagnosticsChannel.md +2 -2
  3. package/docs/{api → docs/api}/Dispatcher.md +39 -3
  4. package/docs/docs/api/Fetch.md +57 -0
  5. package/docs/{api → docs/api}/ProxyAgent.md +5 -1
  6. package/docs/docs/api/RetryAgent.md +45 -0
  7. package/docs/{api → docs/api}/RetryHandler.md +1 -1
  8. package/docs/{api → docs/api}/api-lifecycle.md +33 -4
  9. package/docs/{best-practices → docs/best-practices}/proxy.md +6 -6
  10. package/index-fetch.js +9 -8
  11. package/index.js +31 -25
  12. package/lib/api/api-request.js +1 -1
  13. package/lib/api/readable.js +12 -9
  14. package/lib/api/util.js +8 -6
  15. package/lib/core/request.js +72 -135
  16. package/lib/core/symbols.js +6 -5
  17. package/lib/core/tree.js +46 -26
  18. package/lib/core/util.js +41 -20
  19. package/lib/{agent.js → dispatcher/agent.js} +4 -4
  20. package/lib/{balanced-pool.js → dispatcher/balanced-pool.js} +3 -3
  21. package/lib/dispatcher/client-h1.js +1352 -0
  22. package/lib/dispatcher/client-h2.js +639 -0
  23. package/lib/dispatcher/client.js +611 -0
  24. package/lib/{dispatcher-base.js → dispatcher/dispatcher-base.js} +2 -2
  25. package/lib/{pool-base.js → dispatcher/pool-base.js} +3 -3
  26. package/lib/{pool-stats.js → dispatcher/pool-stats.js} +1 -1
  27. package/lib/{pool.js → dispatcher/pool.js} +4 -4
  28. package/lib/{proxy-agent.js → dispatcher/proxy-agent.js} +29 -35
  29. package/lib/dispatcher/retry-agent.js +35 -0
  30. package/lib/global.js +1 -1
  31. package/lib/handler/{RetryHandler.js → retry-handler.js} +2 -2
  32. package/lib/interceptor/{redirectInterceptor.js → redirect-interceptor.js} +1 -1
  33. package/lib/mock/mock-agent.js +2 -2
  34. package/lib/mock/mock-client.js +1 -1
  35. package/lib/mock/mock-interceptor.js +2 -2
  36. package/lib/mock/mock-pool.js +1 -1
  37. package/lib/mock/mock-utils.js +6 -4
  38. package/lib/{cache → web/cache}/cache.js +2 -4
  39. package/lib/{cache → web/cache}/cachestorage.js +1 -1
  40. package/lib/web/cache/symbols.js +5 -0
  41. package/lib/{cache → web/cache}/util.js +5 -9
  42. package/lib/{cookies → web/cookies}/parse.js +1 -1
  43. package/lib/{cookies → web/cookies}/util.js +76 -60
  44. package/lib/{eventsource → web/eventsource}/eventsource.js +2 -6
  45. package/lib/{fetch → web/fetch}/body.js +56 -175
  46. package/lib/{fetch/dataURL.js → web/fetch/data-url.js} +5 -2
  47. package/lib/{compat → web/fetch}/dispatcher-weakref.js +1 -1
  48. package/lib/{fetch → web/fetch}/file.js +7 -8
  49. package/lib/web/fetch/formdata-parser.js +488 -0
  50. package/lib/{fetch → web/fetch}/formdata.js +7 -68
  51. package/lib/{fetch → web/fetch}/headers.js +99 -71
  52. package/lib/{fetch → web/fetch}/index.js +33 -25
  53. package/lib/{fetch → web/fetch}/request.js +15 -7
  54. package/lib/{fetch → web/fetch}/response.js +3 -3
  55. package/lib/{fetch → web/fetch}/symbols.js +2 -1
  56. package/lib/{fetch → web/fetch}/util.js +171 -48
  57. package/lib/{fetch → web/fetch}/webidl.js +46 -16
  58. package/lib/{fileapi → web/fileapi}/filereader.js +1 -1
  59. package/lib/{fileapi → web/fileapi}/util.js +1 -1
  60. package/lib/{websocket → web/websocket}/connection.js +20 -10
  61. package/lib/{websocket → web/websocket}/constants.js +7 -0
  62. package/lib/{websocket → web/websocket}/events.js +1 -1
  63. package/lib/{websocket → web/websocket}/frame.js +1 -0
  64. package/lib/{websocket → web/websocket}/receiver.js +9 -16
  65. package/lib/{websocket → web/websocket}/util.js +37 -23
  66. package/lib/{websocket → web/websocket}/websocket.js +21 -9
  67. package/package.json +26 -54
  68. package/types/dispatcher.d.ts +1 -1
  69. package/types/fetch.d.ts +20 -21
  70. package/types/index.d.ts +2 -1
  71. package/types/retry-agent.d.ts +11 -0
  72. package/types/webidl.d.ts +6 -1
  73. package/docs/api/Fetch.md +0 -27
  74. package/docs/assets/lifecycle-diagram.png +0 -0
  75. package/lib/cache/symbols.js +0 -5
  76. package/lib/client.js +0 -2295
  77. package/lib/llhttp/llhttp.wasm +0 -0
  78. package/lib/llhttp/llhttp_simd.wasm +0 -0
  79. /package/docs/{api → docs/api}/Agent.md +0 -0
  80. /package/docs/{api → docs/api}/BalancedPool.md +0 -0
  81. /package/docs/{api → docs/api}/CacheStorage.md +0 -0
  82. /package/docs/{api → docs/api}/Client.md +0 -0
  83. /package/docs/{api → docs/api}/Connector.md +0 -0
  84. /package/docs/{api → docs/api}/ContentType.md +0 -0
  85. /package/docs/{api → docs/api}/Cookies.md +0 -0
  86. /package/docs/{api → docs/api}/Debug.md +0 -0
  87. /package/docs/{api → docs/api}/DispatchInterceptor.md +0 -0
  88. /package/docs/{api → docs/api}/Errors.md +0 -0
  89. /package/docs/{api → docs/api}/EventSource.md +0 -0
  90. /package/docs/{api → docs/api}/MockAgent.md +0 -0
  91. /package/docs/{api → docs/api}/MockClient.md +0 -0
  92. /package/docs/{api → docs/api}/MockErrors.md +0 -0
  93. /package/docs/{api → docs/api}/MockPool.md +0 -0
  94. /package/docs/{api → docs/api}/Pool.md +0 -0
  95. /package/docs/{api → docs/api}/PoolStats.md +0 -0
  96. /package/docs/{api → docs/api}/RedirectHandler.md +0 -0
  97. /package/docs/{api → docs/api}/Util.md +0 -0
  98. /package/docs/{api → docs/api}/WebSocket.md +0 -0
  99. /package/docs/{best-practices → docs/best-practices}/client-certificate.md +0 -0
  100. /package/docs/{best-practices → docs/best-practices}/mocking-request.md +0 -0
  101. /package/docs/{best-practices → docs/best-practices}/writing-tests.md +0 -0
  102. /package/lib/{dispatcher.js → dispatcher/dispatcher.js} +0 -0
  103. /package/lib/{node → dispatcher}/fixed-queue.js +0 -0
  104. /package/lib/handler/{DecoratorHandler.js → decorator-handler.js} +0 -0
  105. /package/lib/handler/{RedirectHandler.js → redirect-handler.js} +0 -0
  106. /package/lib/{timers.js → util/timers.js} +0 -0
  107. /package/lib/{cookies → web/cookies}/constants.js +0 -0
  108. /package/lib/{cookies → web/cookies}/index.js +0 -0
  109. /package/lib/{eventsource → web/eventsource}/eventsource-stream.js +0 -0
  110. /package/lib/{eventsource → web/eventsource}/util.js +0 -0
  111. /package/lib/{fetch → web/fetch}/LICENSE +0 -0
  112. /package/lib/{fetch → web/fetch}/constants.js +0 -0
  113. /package/lib/{fetch → web/fetch}/global.js +0 -0
  114. /package/lib/{fileapi → web/fileapi}/encoding.js +0 -0
  115. /package/lib/{fileapi → web/fileapi}/progressevent.js +0 -0
  116. /package/lib/{fileapi → web/fileapi}/symbols.js +0 -0
  117. /package/lib/{websocket → web/websocket}/symbols.js +0 -0
@@ -1,9 +1,9 @@
1
1
  'use strict'
2
2
 
3
3
  const { Writable } = require('node:stream')
4
- const { parserStates, opcodes, states, emptyBuffer } = require('./constants')
4
+ const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants')
5
5
  const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols')
6
- const { channels } = require('../core/diagnostics')
6
+ const { channels } = require('../../core/diagnostics')
7
7
  const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = require('./util')
8
8
  const { WebsocketFrameSend } = require('./frame')
9
9
 
@@ -12,6 +12,8 @@ const { WebsocketFrameSend } = require('./frame')
12
12
  // Copyright (c) 2013 Arnout Kazemier and contributors
13
13
  // Copyright (c) 2016 Luigi Pinca and contributors
14
14
 
15
+ const textDecoder = new TextDecoder('utf-8', { fatal: true })
16
+
15
17
  class ByteParser extends Writable {
16
18
  #buffers = []
17
19
  #byteOffset = 0
@@ -100,9 +102,9 @@ class ByteParser extends Writable {
100
102
 
101
103
  const body = this.consume(payloadLength)
102
104
 
103
- this.#info.closeInfo = this.parseCloseBody(false, body)
105
+ this.#info.closeInfo = this.parseCloseBody(body)
104
106
 
105
- if (!this.ws[kSentClose]) {
107
+ if (this.ws[kSentClose] !== sentCloseFrameState.SENT) {
106
108
  // If an endpoint receives a Close frame and did not previously send a
107
109
  // Close frame, the endpoint MUST send a Close frame in response. (When
108
110
  // sending a Close frame in response, the endpoint typically echos the
@@ -118,7 +120,7 @@ class ByteParser extends Writable {
118
120
  closeFrame.createFrame(opcodes.CLOSE),
119
121
  (err) => {
120
122
  if (!err) {
121
- this.ws[kSentClose] = true
123
+ this.ws[kSentClose] = sentCloseFrameState.SENT
122
124
  }
123
125
  }
124
126
  )
@@ -288,7 +290,7 @@ class ByteParser extends Writable {
288
290
  return buffer
289
291
  }
290
292
 
291
- parseCloseBody (onlyCode, data) {
293
+ parseCloseBody (data) {
292
294
  // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5
293
295
  /** @type {number|undefined} */
294
296
  let code
@@ -300,14 +302,6 @@ class ByteParser extends Writable {
300
302
  code = data.readUInt16BE(0)
301
303
  }
302
304
 
303
- if (onlyCode) {
304
- if (!isValidStatusCode(code)) {
305
- return null
306
- }
307
-
308
- return { code }
309
- }
310
-
311
305
  // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6
312
306
  /** @type {Buffer} */
313
307
  let reason = data.subarray(2)
@@ -322,8 +316,7 @@ class ByteParser extends Writable {
322
316
  }
323
317
 
324
318
  try {
325
- // TODO: optimize this
326
- reason = new TextDecoder('utf-8', { fatal: true }).decode(reason)
319
+ reason = textDecoder.decode(reason)
327
320
  } catch {
328
321
  return null
329
322
  }
@@ -8,6 +8,17 @@ const { MessageEvent, ErrorEvent } = require('./events')
8
8
 
9
9
  /**
10
10
  * @param {import('./websocket').WebSocket} ws
11
+ * @returns {boolean}
12
+ */
13
+ function isConnecting (ws) {
14
+ // If the WebSocket connection is not yet established, and the connection
15
+ // is not yet closed, then the WebSocket connection is in the CONNECTING state.
16
+ return ws[kReadyState] === states.CONNECTING
17
+ }
18
+
19
+ /**
20
+ * @param {import('./websocket').WebSocket} ws
21
+ * @returns {boolean}
11
22
  */
12
23
  function isEstablished (ws) {
13
24
  // If the server's response is validated as provided for above, it is
@@ -18,6 +29,7 @@ function isEstablished (ws) {
18
29
 
19
30
  /**
20
31
  * @param {import('./websocket').WebSocket} ws
32
+ * @returns {boolean}
21
33
  */
22
34
  function isClosing (ws) {
23
35
  // Upon either sending or receiving a Close control frame, it is said
@@ -28,6 +40,7 @@ function isClosing (ws) {
28
40
 
29
41
  /**
30
42
  * @param {import('./websocket').WebSocket} ws
43
+ * @returns {boolean}
31
44
  */
32
45
  function isClosed (ws) {
33
46
  return ws[kReadyState] === states.CLOSED
@@ -55,6 +68,8 @@ function fireEvent (e, target, eventConstructor = Event, eventInitDict = {}) {
55
68
  target.dispatchEvent(event)
56
69
  }
57
70
 
71
+ const textDecoder = new TextDecoder('utf-8', { fatal: true })
72
+
58
73
  /**
59
74
  * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
60
75
  * @param {import('./websocket').WebSocket} ws
@@ -74,7 +89,7 @@ function websocketMessageReceived (ws, type, data) {
74
89
  // -> type indicates that the data is Text
75
90
  // a new DOMString containing data
76
91
  try {
77
- dataForEvent = new TextDecoder('utf-8', { fatal: true }).decode(data)
92
+ dataForEvent = textDecoder.decode(data)
78
93
  } catch {
79
94
  failWebsocketConnection(ws, 'Received invalid UTF-8 in text frame.')
80
95
  return
@@ -119,31 +134,29 @@ function isValidSubprotocol (protocol) {
119
134
  return false
120
135
  }
121
136
 
122
- for (const char of protocol) {
123
- const code = char.charCodeAt(0)
137
+ for (let i = 0; i < protocol.length; ++i) {
138
+ const code = protocol.charCodeAt(i)
124
139
 
125
140
  if (
126
- code < 0x21 ||
141
+ code < 0x21 || // CTL, contains SP (0x20) and HT (0x09)
127
142
  code > 0x7E ||
128
- char === '(' ||
129
- char === ')' ||
130
- char === '<' ||
131
- char === '>' ||
132
- char === '@' ||
133
- char === ',' ||
134
- char === ';' ||
135
- char === ':' ||
136
- char === '\\' ||
137
- char === '"' ||
138
- char === '/' ||
139
- char === '[' ||
140
- char === ']' ||
141
- char === '?' ||
142
- char === '=' ||
143
- char === '{' ||
144
- char === '}' ||
145
- code === 32 || // SP
146
- code === 9 // HT
143
+ code === 0x22 || // "
144
+ code === 0x28 || // (
145
+ code === 0x29 || // )
146
+ code === 0x2C || // ,
147
+ code === 0x2F || // /
148
+ code === 0x3A || // :
149
+ code === 0x3B || // ;
150
+ code === 0x3C || // <
151
+ code === 0x3D || // =
152
+ code === 0x3E || // >
153
+ code === 0x3F || // ?
154
+ code === 0x40 || // @
155
+ code === 0x5B || // [
156
+ code === 0x5C || // \
157
+ code === 0x5D || // ]
158
+ code === 0x7B || // {
159
+ code === 0x7D // }
147
160
  ) {
148
161
  return false
149
162
  }
@@ -190,6 +203,7 @@ function failWebsocketConnection (ws, reason) {
190
203
  }
191
204
 
192
205
  module.exports = {
206
+ isConnecting,
193
207
  isEstablished,
194
208
  isClosing,
195
209
  isClosed,
@@ -1,9 +1,9 @@
1
1
  'use strict'
2
2
 
3
3
  const { webidl } = require('../fetch/webidl')
4
- const { URLSerializer } = require('../fetch/dataURL')
4
+ const { URLSerializer } = require('../fetch/data-url')
5
5
  const { getGlobalOrigin } = require('../fetch/global')
6
- const { staticPropertyDescriptors, states, opcodes, emptyBuffer } = require('./constants')
6
+ const { staticPropertyDescriptors, states, sentCloseFrameState, opcodes, emptyBuffer } = require('./constants')
7
7
  const {
8
8
  kWebSocketURL,
9
9
  kReadyState,
@@ -13,12 +13,20 @@ const {
13
13
  kSentClose,
14
14
  kByteParser
15
15
  } = require('./symbols')
16
- const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection, fireEvent } = require('./util')
16
+ const {
17
+ isConnecting,
18
+ isEstablished,
19
+ isClosed,
20
+ isClosing,
21
+ isValidSubprotocol,
22
+ failWebsocketConnection,
23
+ fireEvent
24
+ } = require('./util')
17
25
  const { establishWebSocketConnection } = require('./connection')
18
26
  const { WebsocketFrameSend } = require('./frame')
19
27
  const { ByteParser } = require('./receiver')
20
- const { kEnumerableProperty, isBlobLike } = require('../core/util')
21
- const { getGlobalDispatcher } = require('../global')
28
+ const { kEnumerableProperty, isBlobLike } = require('../../core/util')
29
+ const { getGlobalDispatcher } = require('../../global')
22
30
  const { types } = require('node:util')
23
31
 
24
32
  let experimentalWarned = false
@@ -132,6 +140,8 @@ class WebSocket extends EventTarget {
132
140
  // be CONNECTING (0).
133
141
  this[kReadyState] = WebSocket.CONNECTING
134
142
 
143
+ this[kSentClose] = sentCloseFrameState.NOT_SENT
144
+
135
145
  // The extensions attribute must initially return the empty string.
136
146
 
137
147
  // The protocol attribute must initially return the empty string.
@@ -184,7 +194,7 @@ class WebSocket extends EventTarget {
184
194
  }
185
195
 
186
196
  // 3. Run the first matching steps from the following list:
187
- if (this[kReadyState] === WebSocket.CLOSING || this[kReadyState] === WebSocket.CLOSED) {
197
+ if (isClosing(this) || isClosed(this)) {
188
198
  // If this's ready state is CLOSING (2) or CLOSED (3)
189
199
  // Do nothing.
190
200
  } else if (!isEstablished(this)) {
@@ -193,7 +203,7 @@ class WebSocket extends EventTarget {
193
203
  // to CLOSING (2).
194
204
  failWebsocketConnection(this, 'Connection was closed before it was established.')
195
205
  this[kReadyState] = WebSocket.CLOSING
196
- } else if (!isClosing(this)) {
206
+ } else if (this[kSentClose] === sentCloseFrameState.NOT_SENT) {
197
207
  // If the WebSocket closing handshake has not yet been started
198
208
  // Start the WebSocket closing handshake and set this's ready
199
209
  // state to CLOSING (2).
@@ -204,6 +214,8 @@ class WebSocket extends EventTarget {
204
214
  // - If reason is also present, then reasonBytes must be
205
215
  // provided in the Close message after the status code.
206
216
 
217
+ this[kSentClose] = sentCloseFrameState.PROCESSING
218
+
207
219
  const frame = new WebsocketFrameSend()
208
220
 
209
221
  // If neither code nor reason is present, the WebSocket Close
@@ -230,7 +242,7 @@ class WebSocket extends EventTarget {
230
242
 
231
243
  socket.write(frame.createFrame(opcodes.CLOSE), (err) => {
232
244
  if (!err) {
233
- this[kSentClose] = true
245
+ this[kSentClose] = sentCloseFrameState.SENT
234
246
  }
235
247
  })
236
248
 
@@ -258,7 +270,7 @@ class WebSocket extends EventTarget {
258
270
 
259
271
  // 1. If this's ready state is CONNECTING, then throw an
260
272
  // "InvalidStateError" DOMException.
261
- if (this[kReadyState] === WebSocket.CONNECTING) {
273
+ if (isConnecting(this)) {
262
274
  throw new DOMException('Sent before connected.', 'InvalidStateError')
263
275
  }
264
276
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "6.6.2",
3
+ "version": "6.7.1",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {
@@ -61,42 +61,34 @@
61
61
  ],
62
62
  "main": "index.js",
63
63
  "types": "index.d.ts",
64
- "files": [
65
- "*.d.ts",
66
- "index.js",
67
- "index-fetch.js",
68
- "loader.js",
69
- "lib",
70
- "types",
71
- "docs"
72
- ],
73
64
  "scripts": {
74
- "build:node": "npx esbuild@0.19.4 index-fetch.js --bundle --platform=node --outfile=undici-fetch.js --define:esbuildDetection=1 --keep-names",
65
+ "build:node": "npx esbuild@0.19.4 index-fetch.js --bundle --platform=node --outfile=undici-fetch.js --define:esbuildDetection=1 --keep-names && node scripts/strip-comments.js",
75
66
  "prebuild:wasm": "node build/wasm.js --prebuild",
76
67
  "build:wasm": "node build/wasm.js --docker",
77
68
  "lint": "standard | snazzy",
78
69
  "lint:fix": "standard --fix | snazzy",
79
- "test": "node scripts/generate-pem && npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:eventsource && npm run test:wpt && npm run test:websocket && npm run test:jest && npm run test:typescript && npm run test:node-test",
80
- "test:cookies": "borp --coverage -p \"test/cookie/*.js\"",
81
- "test:node-fetch": "mocha --exit test/node-fetch",
82
- "test:eventsource": "npm run build:node && borp --expose-gc --coverage -p \"test/eventsource/*.js\"",
83
- "test:fetch": "npm run build:node && borp --expose-gc --coverage -p \"test/fetch/*.js\" && borp --coverage -p \"test/webidl/*.js\"",
84
- "test:jest": "jest",
85
- "test:tap": "tap test/*.js",
86
- "test:node-test": "borp --coverage -p \"test/node-test/**/*.js\"",
87
- "test:tdd": "tap test/*.js --coverage -w",
70
+ "test": "npm run test:javascript && cross-env NODE_V8_COVERAGE= npm run test:typescript",
71
+ "test:javascript": "node scripts/generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:eventsource && npm run test:wpt && npm run test:websocket && npm run test:node-test && npm run test:jest",
72
+ "test:cookies": "borp -p \"test/cookie/*.js\"",
73
+ "test:node-fetch": "borp -p \"test/node-fetch/**/*.js\"",
74
+ "test:eventsource": "npm run build:node && borp --expose-gc -p \"test/eventsource/*.js\"",
75
+ "test:fetch": "npm run build:node && borp --expose-gc -p \"test/fetch/*.js\" && borp -p \"test/webidl/*.js\" && borp -p \"test/busboy/*.js\"",
76
+ "test:jest": "cross-env NODE_V8_COVERAGE= jest",
77
+ "test:unit": "borp --expose-gc -p \"test/*.js\"",
78
+ "test:node-test": "borp -p \"test/node-test/**/*.js\"",
79
+ "test:tdd": "borp --expose-gc -p \"test/*.js\"",
88
80
  "test:tdd:node-test": "borp -p \"test/node-test/**/*.js\" -w",
89
81
  "test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts",
90
- "test:websocket": "borp --coverage -p \"test/websocket/*.js\"",
82
+ "test:websocket": "borp -p \"test/websocket/*.js\"",
91
83
  "test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs",
92
- "coverage": "nyc --reporter=text --reporter=html npm run test",
93
- "coverage:ci": "nyc --reporter=lcov npm run test",
94
- "bench": "PORT=3042 concurrently -k -s first npm:bench:server npm:bench:run",
95
- "bench:server": "node benchmarks/server.js",
96
- "prebench:run": "node benchmarks/wait.js",
97
- "bench:run": "SAMPLES=100 CONNECTIONS=50 node benchmarks/benchmark.js",
98
- "serve:website": "docsify serve .",
99
- "prepare": "husky install",
84
+ "coverage": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report",
85
+ "coverage:ci": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report:ci",
86
+ "coverage:clean": "node ./scripts/clean-coverage.js",
87
+ "coverage:report": "cross-env NODE_V8_COVERAGE= c8 report",
88
+ "coverage:report:ci": "c8 report",
89
+ "bench": "echo \"Error: Benchmarks have been moved to '/benchmarks'\" && exit 1",
90
+ "serve:website": "echo \"Error: Documentation has been moved to '/docs'\" && exit 1",
91
+ "prepare": "husky install && node ./scripts/platform-shell.js",
100
92
  "fuzz": "jsfuzz test/fuzzing/fuzz.js corpus"
101
93
  },
102
94
  "devDependencies": {
@@ -105,47 +97,30 @@
105
97
  "@types/node": "^18.0.3",
106
98
  "abort-controller": "^3.0.0",
107
99
  "borp": "^0.9.1",
108
- "chai": "^4.3.4",
109
- "chai-as-promised": "^7.1.1",
110
- "chai-iterator": "^3.0.2",
111
- "chai-string": "^1.5.0",
112
- "concurrently": "^8.0.1",
113
- "cronometro": "^2.0.2",
100
+ "c8": "^9.1.0",
101
+ "cross-env": "^7.0.3",
114
102
  "dns-packet": "^5.4.0",
115
- "docsify-cli": "^4.4.3",
116
103
  "form-data": "^4.0.0",
117
104
  "formdata-node": "^6.0.3",
118
105
  "https-pem": "^3.0.0",
119
106
  "husky": "^9.0.7",
120
- "import-fresh": "^3.3.0",
121
107
  "jest": "^29.0.2",
122
108
  "jsdom": "^24.0.0",
123
109
  "jsfuzz": "^1.0.15",
124
- "mitata": "^0.1.8",
125
- "mocha": "^10.0.0",
126
- "p-timeout": "^3.2.0",
127
110
  "pre-commit": "^1.2.2",
128
- "proxy": "^1.0.2",
129
- "proxyquire": "^2.1.3",
130
- "sinon": "^17.0.1",
111
+ "proxy": "^2.1.1",
131
112
  "snazzy": "^9.0.0",
132
113
  "standard": "^17.0.0",
133
- "tap": "^16.1.0",
134
114
  "tsd": "^0.30.1",
135
115
  "typescript": "^5.0.2",
136
- "wait-on": "^7.0.1",
137
- "ws": "^8.11.0",
138
- "axios": "^1.6.5",
139
- "got": "^14.0.0",
140
- "node-fetch": "^3.3.2",
141
- "request": "^2.88.2"
116
+ "ws": "^8.11.0"
142
117
  },
143
118
  "engines": {
144
119
  "node": ">=18.0"
145
120
  },
146
121
  "standard": {
147
122
  "env": [
148
- "mocha"
123
+ "jest"
149
124
  ],
150
125
  "ignore": [
151
126
  "lib/llhttp/constants.js",
@@ -166,8 +141,5 @@
166
141
  "testMatch": [
167
142
  "<rootDir>/test/jest/**"
168
143
  ]
169
- },
170
- "dependencies": {
171
- "@fastify/busboy": "^2.0.0"
172
144
  }
173
145
  }
@@ -100,7 +100,7 @@ declare namespace Dispatcher {
100
100
  /** Default: `null` */
101
101
  body?: string | Buffer | Uint8Array | Readable | null | FormData;
102
102
  /** Default: `null` */
103
- headers?: IncomingHttpHeaders | string[] | null;
103
+ headers?: IncomingHttpHeaders | string[] | Iterable<[string, string | string[] | undefined]> | null;
104
104
  /** Query string params to be embedded in the request URL. Default: `null` */
105
105
  query?: Record<string, any>;
106
106
  /** Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceding requests in the pipeline have completed. Default: `true` if `method` is `HEAD` or `GET`. */
package/types/fetch.d.ts CHANGED
@@ -27,12 +27,29 @@ export type BodyInit =
27
27
  | null
28
28
  | string
29
29
 
30
- export interface BodyMixin {
30
+ export class BodyMixin {
31
31
  readonly body: ReadableStream | null
32
32
  readonly bodyUsed: boolean
33
33
 
34
34
  readonly arrayBuffer: () => Promise<ArrayBuffer>
35
35
  readonly blob: () => Promise<Blob>
36
+ /**
37
+ * @deprecated This method is not recommended for parsing multipart/form-data bodies in server environments.
38
+ * It is recommended to use a library such as [@fastify/busboy](https://www.npmjs.com/package/@fastify/busboy) as follows:
39
+ *
40
+ * @example
41
+ * ```js
42
+ * import { Busboy } from '@fastify/busboy'
43
+ * import { Readable } from 'node:stream'
44
+ *
45
+ * const response = await fetch('...')
46
+ * const busboy = new Busboy({ headers: { 'content-type': response.headers.get('content-type') } })
47
+ *
48
+ * // handle events emitted from `busboy`
49
+ *
50
+ * Readable.fromWeb(response.body).pipe(busboy)
51
+ * ```
52
+ */
36
53
  readonly formData: () => Promise<FormData>
37
54
  readonly json: () => Promise<unknown>
38
55
  readonly text: () => Promise<string>
@@ -135,7 +152,7 @@ export type RequestRedirect = 'error' | 'follow' | 'manual'
135
152
 
136
153
  export type RequestDuplex = 'half'
137
154
 
138
- export declare class Request implements BodyMixin {
155
+ export declare class Request extends BodyMixin {
139
156
  constructor (input: RequestInfo, init?: RequestInit)
140
157
 
141
158
  readonly cache: RequestCache
@@ -153,15 +170,6 @@ export declare class Request implements BodyMixin {
153
170
  readonly signal: AbortSignal
154
171
  readonly duplex: RequestDuplex
155
172
 
156
- readonly body: ReadableStream | null
157
- readonly bodyUsed: boolean
158
-
159
- readonly arrayBuffer: () => Promise<ArrayBuffer>
160
- readonly blob: () => Promise<Blob>
161
- readonly formData: () => Promise<FormData>
162
- readonly json: () => Promise<unknown>
163
- readonly text: () => Promise<string>
164
-
165
173
  readonly clone: () => Request
166
174
  }
167
175
 
@@ -181,7 +189,7 @@ export type ResponseType =
181
189
 
182
190
  export type ResponseRedirectStatus = 301 | 302 | 303 | 307 | 308
183
191
 
184
- export declare class Response implements BodyMixin {
192
+ export declare class Response extends BodyMixin {
185
193
  constructor (body?: BodyInit, init?: ResponseInit)
186
194
 
187
195
  readonly headers: Headers
@@ -192,15 +200,6 @@ export declare class Response implements BodyMixin {
192
200
  readonly url: string
193
201
  readonly redirected: boolean
194
202
 
195
- readonly body: ReadableStream | null
196
- readonly bodyUsed: boolean
197
-
198
- readonly arrayBuffer: () => Promise<ArrayBuffer>
199
- readonly blob: () => Promise<Blob>
200
- readonly formData: () => Promise<FormData>
201
- readonly json: () => Promise<unknown>
202
- readonly text: () => Promise<string>
203
-
204
203
  readonly clone: () => Response
205
204
 
206
205
  static error (): Response
package/types/index.d.ts CHANGED
@@ -15,6 +15,7 @@ import MockAgent from'./mock-agent'
15
15
  import mockErrors from'./mock-errors'
16
16
  import ProxyAgent from'./proxy-agent'
17
17
  import RetryHandler from'./retry-handler'
18
+ import RetryAgent from'./retry-agent'
18
19
  import { request, pipeline, stream, connect, upgrade } from './api'
19
20
 
20
21
  export * from './util'
@@ -30,7 +31,7 @@ export * from './content-type'
30
31
  export * from './cache'
31
32
  export { Interceptable } from './mock-interceptor'
32
33
 
33
- export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler }
34
+ export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent }
34
35
  export default Undici
35
36
 
36
37
  declare namespace Undici {
@@ -0,0 +1,11 @@
1
+ import Agent from './agent'
2
+ import buildConnector from './connector';
3
+ import Dispatcher from './dispatcher'
4
+ import { IncomingHttpHeaders } from './header'
5
+ import RetryHandler from './retry-handler'
6
+
7
+ export default RetryAgent
8
+
9
+ declare class RetryAgent extends Dispatcher {
10
+ constructor(dispatcher: Dispatcher, options?: RetryHandler.RetryOptions)
11
+ }
package/types/webidl.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  type Converter<T> = (object: unknown) => T
7
7
 
8
- type SequenceConverter<T> = (object: unknown) => T[]
8
+ type SequenceConverter<T> = (object: unknown, iterable?: IterableIterator<T>) => T[]
9
9
 
10
10
  type RecordConverter<K extends string, V> = (object: unknown) => Record<K, V>
11
11
 
@@ -62,6 +62,11 @@ interface WebidlUtil {
62
62
  * @see https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
63
63
  */
64
64
  IntegerPart (N: number): number
65
+
66
+ /**
67
+ * Stringifies {@param V}
68
+ */
69
+ Stringify (V: any): string
65
70
  }
66
71
 
67
72
  interface WebidlConverters {
package/docs/api/Fetch.md DELETED
@@ -1,27 +0,0 @@
1
- # Fetch
2
-
3
- Undici exposes a fetch() method starts the process of fetching a resource from the network.
4
-
5
- Documentation and examples can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/fetch).
6
-
7
- ## File
8
-
9
- This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/File)
10
-
11
- In Node versions v18.13.0 and above and v19.2.0 and above, undici will default to using Node's [File](https://nodejs.org/api/buffer.html#class-file) class. In versions where it's not available, it will default to the undici one.
12
-
13
- ## FormData
14
-
15
- This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
16
-
17
- ## Response
18
-
19
- This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Response)
20
-
21
- ## Request
22
-
23
- This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Request)
24
-
25
- ## Header
26
-
27
- This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
Binary file
@@ -1,5 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = {
4
- kConstruct: require('../core/symbols').kConstruct
5
- }