@nxtedition/nxt-undici 1.0.4 → 1.0.6

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/lib/index.js CHANGED
@@ -4,6 +4,8 @@ const undici = require('undici')
4
4
  const stream = require('stream')
5
5
  const { parseHeaders } = require('./utils')
6
6
 
7
+ const dispatcherCache = new WeakMap()
8
+
7
9
  // https://github.com/fastify/fastify/blob/main/lib/reqIdGenFactory.js
8
10
  // 2,147,483,647 (2^31 − 1) stands for max SMI value (an internal optimization of V8).
9
11
  // With this upper bound, if you'll be generating 1k ids/sec, you're going to hit it in ~25 days.
@@ -87,6 +89,7 @@ const dispatchers = {
87
89
  signal: require('./interceptor/signal.js'),
88
90
  proxy: require('./interceptor/proxy.js'),
89
91
  cache: require('./interceptor/cache.js'),
92
+ requestId: require('./interceptor/request-id.js'),
90
93
  }
91
94
 
92
95
  async function request(url, opts) {
@@ -114,10 +117,9 @@ async function request(url, opts) {
114
117
  headers = opts.headers
115
118
  }
116
119
 
117
- headers = {
118
- 'request-id': genReqId(),
119
- 'user-agent': opts.userAgent ?? globalThis.userAgent,
120
- ...headers,
120
+ const userAgent = opts.userAgent ?? globalThis.userAgent
121
+ if (userAgent && headers?.['user-agent'] !== userAgent) {
122
+ headers = { 'user-agent': userAgent, ...headers }
121
123
  }
122
124
 
123
125
  if (method === 'CONNECT') {
@@ -125,127 +127,138 @@ async function request(url, opts) {
125
127
  }
126
128
 
127
129
  if (
130
+ headers != null &&
128
131
  (method === 'HEAD' || method === 'GET') &&
129
132
  (parseInt(headers['content-length']) > 0 || headers['transfer-encoding'])
130
133
  ) {
131
134
  throw new createError.BadRequest('HEAD and GET cannot have body')
132
135
  }
133
136
 
134
- opts = {
135
- url,
136
- method,
137
- body: opts.body,
138
- headers,
139
- origin: url.origin,
140
- path: url.path ? url.path : url.search ? `${url.pathname}${url.search ?? ''}` : url.pathname,
141
- reset: opts.reset ?? false,
142
- headersTimeout: opts.headersTimeout,
143
- bodyTimeout: opts.bodyTimeout,
144
- idempotent,
145
- signal: opts.signal,
146
- retry: opts.retry ?? 8,
147
- proxy: opts.proxy,
148
- cache: opts.cache,
149
- upgrade: opts.upgrade,
150
- follow: { count: opts.maxRedirections ?? 8, ...opts.redirect, ...opts.follow },
151
- logger: opts.logger,
152
- maxRedirections: 0, // Disable undici's redirect handling.
153
- }
154
-
155
137
  const expectsPayload = opts.method === 'PUT' || opts.method === 'POST' || opts.method === 'PATCH'
156
138
 
157
- if (opts.headers['content-length'] === '0' && !expectsPayload) {
139
+ if (headers != null && headers['content-length'] === '0' && !expectsPayload) {
158
140
  // https://tools.ietf.org/html/rfc7230#section-3.3.2
159
141
  // A user agent SHOULD NOT send a Content-Length header field when
160
142
  // the request message does not contain a payload body and the method
161
143
  // semantics do not anticipate such a body.
162
144
 
163
145
  // undici will error if provided an unexpected content-length: 0 header.
164
- delete opts.headers['content-length']
146
+ headers = { ...headers }
147
+ delete headers['content-length']
165
148
  }
166
149
 
167
150
  const dispatcher = opts.dispatcher ?? undici.getGlobalDispatcher()
168
151
 
169
- return new Promise((resolve) => {
170
- let dispatch = (opts, handler) => dispatcher.dispatch(opts, handler)
171
-
152
+ let dispatch = dispatcherCache.get(dispatcher)
153
+ if (dispatch == null) {
154
+ dispatch = (opts, handler) => dispatcher.dispatch(opts, handler)
172
155
  dispatch = dispatchers.catch(dispatch)
173
156
  dispatch = dispatchers.abort(dispatch)
174
157
  dispatch = dispatchers.log(dispatch)
175
- dispatch = opts.upgrade ? dispatch : dispatchers.responseRetry(dispatch)
176
- dispatch = opts.upgrade ? dispatch : dispatchers.responseStatusRetry(dispatch)
177
- dispatch = opts.upgrade ? dispatch : dispatchers.responseBodyRetry(dispatch)
178
- dispatch = opts.upgrade ? dispatch : dispatchers.content(dispatch)
158
+ dispatch = dispatchers.requestId(dispatch)
159
+ dispatch = dispatchers.responseRetry(dispatch)
160
+ dispatch = dispatchers.responseStatusRetry(dispatch)
161
+ dispatch = dispatchers.responseBodyRetry(dispatch)
162
+ dispatch = dispatchers.content(dispatch)
179
163
  dispatch = dispatchers.redirect(dispatch)
180
164
  dispatch = dispatchers.signal(dispatch)
181
- dispatch = opts.upgrade ? dispatch : dispatchers.cache(dispatch)
165
+ dispatch = dispatchers.cache(dispatch)
182
166
  dispatch = dispatchers.proxy(dispatch)
167
+ dispatcherCache.set(dispatcher, dispatch)
168
+ }
183
169
 
184
- dispatch(opts, {
185
- resolve,
186
- logger: opts.logger,
187
- /** @type {Function | null} */ abort: null,
188
- /** @type {stream.Readable | null} */ body: null,
189
- onConnect(abort) {
190
- this.abort = abort
170
+ return new Promise((resolve, reject) =>
171
+ dispatch(
172
+ {
173
+ id: opts.id ?? genReqId(),
174
+ url,
175
+ method,
176
+ body: opts.body,
177
+ headers,
178
+ origin: url.origin,
179
+ path: url.path ?? (url.search ? `${url.pathname}${url.search ?? ''}` : url.pathname),
180
+ query: opts.query,
181
+ reset: opts.reset ?? false,
182
+ headersTimeout: opts.headersTimeout,
183
+ bodyTimeout: opts.bodyTimeout,
184
+ idempotent,
185
+ signal: opts.signal,
186
+ retry: opts.retry ?? 8,
187
+ proxy: opts.proxy,
188
+ cache: opts.cache,
189
+ upgrade: opts.upgrade,
190
+ follow: opts.follow ?? 8,
191
+ logger: opts.logger,
191
192
  },
192
- onUpgrade(statusCode, rawHeaders, socket) {
193
- const headers = parseHeaders(rawHeaders)
193
+ {
194
+ resolve,
195
+ reject,
196
+ logger: opts.logger,
197
+ /** @type {Function | null} */ abort: null,
198
+ /** @type {stream.Readable | null} */ body: null,
199
+ onConnect(abort) {
200
+ this.abort = abort
201
+ },
202
+ onUpgrade(statusCode, rawHeaders, socket) {
203
+ const headers = parseHeaders(rawHeaders)
194
204
 
195
- if (statusCode !== 101) {
196
- this.abort(createError(statusCode, { headers }))
197
- } else {
198
- this.resolve({ headers, socket })
199
- }
200
- },
201
- onHeaders(statusCode, rawHeaders, resume, statusMessage) {
202
- assert(this.abort)
203
-
204
- const headers = parseHeaders(rawHeaders)
205
-
206
- if (statusCode >= 400) {
207
- this.abort(createError(statusCode, { headers }))
208
- } else {
209
- assert(statusCode >= 200)
210
-
211
- const contentLength = Number(headers['content-length'] ?? headers['Content-Length'])
212
-
213
- this.body = new Readable({
214
- read: resume,
215
- highWaterMark: 128 * 1024,
216
- statusCode,
217
- statusMessage,
218
- headers,
219
- size: Number.isFinite(contentLength) ? contentLength : null,
220
- }).on('error', (err) => {
221
- if (this.logger && this.body?.listenerCount('error') === 1) {
222
- this.logger.error({ err }, 'unhandled response body error')
223
- }
224
- })
225
-
226
- this.resolve(this.body)
227
- this.resolve = null
228
- }
205
+ if (statusCode !== 101) {
206
+ this.abort(createError(statusCode, { headers }))
207
+ } else {
208
+ this.resolve({ headers, socket })
209
+ }
210
+ },
211
+ onBodySent(chunk) {},
212
+ onHeaders(statusCode, rawHeaders, resume, statusMessage) {
213
+ assert(this.abort)
229
214
 
230
- return false
231
- },
232
- onData(chunk) {
233
- assert(this.body)
234
- return this.body.push(chunk)
235
- },
236
- onComplete() {
237
- assert(this.body)
238
- this.body.push(null)
239
- },
240
- onError(err) {
241
- if (this.body) {
242
- this.body.destroy(err)
243
- } else {
244
- this.resolve(Promise.reject(err))
245
- }
215
+ const headers = parseHeaders(rawHeaders)
216
+
217
+ if (statusCode >= 400) {
218
+ this.abort(createError(statusCode, { headers }))
219
+ } else {
220
+ assert(statusCode >= 200)
221
+
222
+ const contentLength = Number(headers['content-length'] ?? headers['Content-Length'])
223
+
224
+ this.body = new Readable({
225
+ read: resume,
226
+ highWaterMark: 128 * 1024,
227
+ statusCode,
228
+ statusMessage,
229
+ headers,
230
+ size: Number.isFinite(contentLength) ? contentLength : null,
231
+ }).on('error', (err) => {
232
+ if (this.logger && this.body?.listenerCount('error') === 1) {
233
+ this.logger.error({ err }, 'unhandled response body error')
234
+ }
235
+ })
236
+
237
+ this.resolve(this.body)
238
+ this.resolve = null
239
+ }
240
+
241
+ return false
242
+ },
243
+ onData(chunk) {
244
+ assert(this.body)
245
+ return this.body.push(chunk)
246
+ },
247
+ onComplete() {
248
+ assert(this.body)
249
+ this.body.push(null)
250
+ },
251
+ onError(err) {
252
+ if (this.body) {
253
+ this.body.destroy(err)
254
+ } else {
255
+ this.reject(err)
256
+ this.reject = null
257
+ }
258
+ },
246
259
  },
247
- })
248
- })
260
+ ),
261
+ )
249
262
  }
250
263
 
251
264
  module.exports = { request }
@@ -1,6 +1,5 @@
1
1
  const crypto = require('node:crypto')
2
2
  const stream = require('node:stream')
3
- const assert = require('node:assert')
4
3
  const { findHeader, isStream } = require('../utils')
5
4
 
6
5
  class Handler {
@@ -8,7 +7,6 @@ class Handler {
8
7
  this.handler = handler
9
8
  this.md5 = null
10
9
  this.length = null
11
-
12
10
  this.hasher = null
13
11
  this.pos = 0
14
12
  }
@@ -28,9 +26,7 @@ class Handler {
28
26
  onHeaders(statusCode, rawHeaders, resume, statusMessage) {
29
27
  this.md5 = findHeader(rawHeaders, 'content-md5')
30
28
  this.length = findHeader(rawHeaders, 'content-length')
31
-
32
29
  this.hasher = this.md5 != null ? crypto.createHash('md5') : null
33
-
34
30
  return this.handler.onHeaders(statusCode, rawHeaders, resume, statusMessage)
35
31
  }
36
32
 
@@ -67,6 +63,11 @@ class Handler {
67
63
  }
68
64
 
69
65
  module.exports = (dispatch) => (opts, handler) => {
66
+ if (opts.upgrade) {
67
+ return dispatch(opts, handler)
68
+ }
69
+
70
+ // TODO (fix): case-insensitive check?
70
71
  const md5 = opts.headers?.['content-md5'] ?? opts.headers?.['Content-MD5']
71
72
  const length = opts.headers?.['content-lenght'] ?? opts.headers?.['Content-Length']
72
73
 
@@ -86,7 +87,7 @@ module.exports = (dispatch) => (opts, handler) => {
86
87
  transform(chunk, encoding, callback) {
87
88
  pos += chunk.length
88
89
  hasher?.update(chunk)
89
- callback(null)
90
+ callback(null, chunk)
90
91
  },
91
92
  final(callback) {
92
93
  const hash = hasher?.digest('base64')
@@ -133,7 +134,7 @@ module.exports = (dispatch) => (opts, handler) => {
133
134
  })
134
135
  }
135
136
  } else {
136
- assert(false, 'not implemented')
137
+ throw new Error('not implemented')
137
138
  }
138
139
 
139
140
  return dispatch(opts, new Handler(opts, { handler }))
@@ -1,26 +1,13 @@
1
1
  const { parseHeaders } = require('../utils')
2
2
  const { performance } = require('perf_hooks')
3
3
 
4
- // https://github.com/fastify/fastify/blob/main/lib/reqIdGenFactory.js
5
- // 2,147,483,647 (2^31 − 1) stands for max SMI value (an internal optimization of V8).
6
- // With this upper bound, if you'll be generating 1k ids/sec, you're going to hit it in ~25 days.
7
- // This is very likely to happen in real-world applications, hence the limit is enforced.
8
- // Growing beyond this value will make the id generation slower and cause a deopt.
9
- // In the worst cases, it will become a float, losing accuracy.
10
- const maxInt = 2147483647
11
- let nextReqId = Math.floor(Math.random() * maxInt)
12
- function genReqId() {
13
- nextReqId = (nextReqId + 1) & maxInt
14
- return `req-${nextReqId.toString(36)}`
15
- }
16
-
17
4
  class Handler {
18
5
  constructor(opts, { handler }) {
19
6
  this.handler = handler
20
- this.opts = opts.id ? opts : { ...opts, id: genReqId() }
7
+ this.opts = opts
21
8
  this.abort = null
22
9
  this.aborted = false
23
- this.logger = opts.logger.child({ ureq: { id: opts.id } })
10
+ this.logger = opts.logger.child({ ureq: opts })
24
11
  this.pos = 0
25
12
  this.startTime = 0
26
13
  }
@@ -28,7 +15,7 @@ class Handler {
28
15
  onConnect(abort) {
29
16
  this.abort = abort
30
17
  this.startTime = performance.now()
31
- this.logger.debug({ ureq: this.opts }, 'upstream request started')
18
+ this.logger.debug('upstream request started')
32
19
  this.handler.onConnect((reason) => {
33
20
  this.aborted = true
34
21
  this.abort(reason)
@@ -36,9 +23,9 @@ class Handler {
36
23
  }
37
24
 
38
25
  onUpgrade(statusCode, rawHeaders, socket) {
39
- this.logger.debug({ ureq: this.opts }, 'upstream request upgraded')
26
+ this.logger.debug('upstream request upgraded')
40
27
  socket.on('close', () => {
41
- this.logger.debug({ ureq: this.opts }, 'upstream request socket closed')
28
+ this.logger.debug('upstream request socket closed')
42
29
  })
43
30
  return this.handler.onUpgrade(statusCode, rawHeaders, socket)
44
31
  }
@@ -102,7 +102,7 @@ const HOP_EXPR =
102
102
  function forEachHeader(headers, fn) {
103
103
  if (Array.isArray(headers)) {
104
104
  for (let n = 0; n < headers.length; n += 2) {
105
- fn(headers[n + 0].toString(), headers[n + 1].toString())
105
+ fn(headers[n + 0], headers[n + 1])
106
106
  }
107
107
  } else {
108
108
  for (const [key, val] of Object.entries(headers)) {
@@ -123,16 +123,16 @@ function reduceHeaders({ headers, proxyName, httpVersion, socket }, fn, acc) {
123
123
 
124
124
  forEachHeader(headers, (key, val) => {
125
125
  const len = key.length
126
- if (len === 3 && !via && key.toLowerCase() === 'via') {
127
- via = val
128
- } else if (len === 4 && !host && key.toLowerCase() === 'host') {
129
- host = val
130
- } else if (len === 9 && !forwarded && key.toLowerCase() === 'forwarded') {
131
- forwarded = val
132
- } else if (len === 10 && !connection && key.toLowerCase() === 'connection') {
133
- connection = val
134
- } else if (len === 10 && !authority && key.toLowerCase() === ':authority') {
135
- authority = val
126
+ if (len === 3 && !via && key.toString().toLowerCase() === 'via') {
127
+ via = val.toString()
128
+ } else if (len === 4 && !host && key.toString().toLowerCase() === 'host') {
129
+ host = val.toString()
130
+ } else if (len === 9 && !forwarded && key.toString().toLowerCase() === 'forwarded') {
131
+ forwarded = val.toString()
132
+ } else if (len === 10 && !connection && key.toString().toLowerCase() === 'connection') {
133
+ connection = val.toString()
134
+ } else if (len === 10 && !authority && key.toString().toLowerCase() === ':authority') {
135
+ authority = val.toString()
136
136
  }
137
137
  })
138
138
 
@@ -142,8 +142,10 @@ function reduceHeaders({ headers, proxyName, httpVersion, socket }, fn, acc) {
142
142
  }
143
143
 
144
144
  forEachHeader(headers, (key, val) => {
145
+ key = key.toString()
146
+
145
147
  if (key.charAt(0) !== ':' && !remove.includes(key) && !HOP_EXPR.test(key)) {
146
- acc = fn(acc, key, val)
148
+ acc = fn(acc, key, val.toString())
147
149
  }
148
150
  })
149
151
 
@@ -11,6 +11,7 @@ class Handler {
11
11
  this.abort = null
12
12
  this.aborted = false
13
13
  this.reason = null
14
+ this.maxCount = Number.isFinite(opts.follow) ? opts.follow : opts.follow?.count ?? 0
14
15
 
15
16
  this.count = 0
16
17
  this.location = null
@@ -34,11 +35,15 @@ class Handler {
34
35
  }
35
36
 
36
37
  onUpgrade(statusCode, headers, socket) {
37
- this.handler.onUpgrade(statusCode, headers, socket)
38
+ return this.handler.onUpgrade(statusCode, headers, socket)
39
+ }
40
+
41
+ onBodySent(chunk) {
42
+ return this.handler.onBodySent(chunk)
38
43
  }
39
44
 
40
45
  onError(error) {
41
- this.handler.onError(error)
46
+ return this.handler.onError(error)
42
47
  }
43
48
 
44
49
  onHeaders(statusCode, headers, resume, statusText) {
@@ -53,7 +58,7 @@ class Handler {
53
58
  this.location = findHeader(headers, 'location')
54
59
 
55
60
  if (!this.location) {
56
- throw new Error(`Missing redirection location.`)
61
+ throw new Error(`Missing redirection location .`)
57
62
  }
58
63
 
59
64
  this.count += 1
@@ -63,10 +68,8 @@ class Handler {
63
68
  return this.handler.onHeaders(statusCode, headers, resume, statusText)
64
69
  }
65
70
  } else {
66
- const maxCount = this.opts.follow.count ?? 0
67
-
68
- if (this.count >= maxCount) {
69
- throw new Error(`Max redirections reached: ${maxCount}.`)
71
+ if (this.count >= this.maxCount) {
72
+ throw new Error(`Max redirections reached: ${this.maxCount}.`)
70
73
  }
71
74
  }
72
75
 
@@ -136,13 +139,7 @@ class Handler {
136
139
 
137
140
  this.dispatch(this.opts, this)
138
141
  } else {
139
- this.handler.onComplete(trailers)
140
- }
141
- }
142
-
143
- onBodySent(chunk) {
144
- if (this.handler.onBodySent) {
145
- this.handler.onBodySent(chunk)
142
+ return this.handler.onComplete(trailers)
146
143
  }
147
144
  }
148
145
  }
@@ -161,17 +158,12 @@ function shouldRemoveHeader(header, removeContent, unknownOrigin) {
161
158
 
162
159
  // https://tools.ietf.org/html/rfc7231#section-6.4
163
160
  function cleanRequestHeaders(headers, removeContent, unknownOrigin) {
164
- const ret = []
165
- if (Array.isArray(headers)) {
166
- for (let i = 0; i < headers.length; i += 2) {
167
- if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) {
168
- ret.push(headers[i], headers[i + 1])
169
- }
170
- }
171
- } else if (headers && typeof headers === 'object') {
161
+ let ret
162
+ if (headers && typeof headers === 'object') {
172
163
  for (const key of Object.keys(headers)) {
173
164
  if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) {
174
- ret.push(key, headers[key])
165
+ ret ??= {}
166
+ ret[key] = headers[key]
175
167
  }
176
168
  }
177
169
  } else {
@@ -181,4 +173,6 @@ function cleanRequestHeaders(headers, removeContent, unknownOrigin) {
181
173
  }
182
174
 
183
175
  module.exports = (dispatch) => (opts, handler) =>
184
- opts.follow ? dispatch(opts, new Handler(opts, { handler, dispatch })) : dispatch(opts, handler)
176
+ opts.follow != null
177
+ ? dispatch(opts, new Handler(opts, { handler, dispatch }))
178
+ : dispatch(opts, handler)
@@ -0,0 +1,29 @@
1
+ // https://github.com/fastify/fastify/blob/main/lib/reqIdGenFactory.js
2
+ // 2,147,483,647 (2^31 − 1) stands for max SMI value (an internal optimization of V8).
3
+ // With this upper bound, if you'll be generating 1k ids/sec, you're going to hit it in ~25 days.
4
+ // This is very likely to happen in real-world applications, hence the limit is enforced.
5
+ // Growing beyond this value will make the id generation slower and cause a deopt.
6
+ // In the worst cases, it will become a float, losing accuracy.
7
+ const maxInt = 2147483647
8
+ let nextReqId = Math.floor(Math.random() * maxInt)
9
+ function genReqId() {
10
+ nextReqId = (nextReqId + 1) & maxInt
11
+ return `req-${nextReqId.toString(36)}`
12
+ }
13
+
14
+ module.exports = (dispatch) => (opts, handler) => {
15
+ let id = opts.id ?? opts.headers?.['request-id'] ?? opts.headers?.['Request-Id']
16
+ id = id ? `${id},${genReqId()}` : genReqId()
17
+
18
+ return dispatch(
19
+ {
20
+ ...opts,
21
+ id,
22
+ headers: {
23
+ ...opts.headers,
24
+ 'request-id': id,
25
+ },
26
+ },
27
+ handler,
28
+ )
29
+ }
@@ -83,6 +83,6 @@ class Handler {
83
83
  }
84
84
 
85
85
  module.exports = (dispatch) => (opts, handler) =>
86
- opts.idempotent && opts.retry
86
+ opts.idempotent && opts.retry && !opts.upgrade
87
87
  ? dispatch(opts, new Handler(opts, { handler, dispatch }))
88
88
  : dispatch(opts, handler)
@@ -34,12 +34,16 @@ class Handler {
34
34
  }
35
35
 
36
36
  onComplete(rawTrailers) {
37
- this.signal.removeEventListener('abort', this.abort)
37
+ if (this.abort) {
38
+ this.signal.removeEventListener('abort', this.abort)
39
+ }
38
40
  return this.handler.onComplete(rawTrailers)
39
41
  }
40
42
 
41
43
  onError(err) {
42
- this.signal.removeEventListener('abort', this.abort)
44
+ if (this.abort) {
45
+ this.signal.removeEventListener('abort', this.abort)
46
+ }
43
47
  return this.handler.onError(err)
44
48
  }
45
49
  }
package/lib/utils.js CHANGED
@@ -204,9 +204,43 @@ function isStream(obj) {
204
204
  )
205
205
  }
206
206
 
207
+ // based on https://github.com/node-fetch/fetch-blob/blob/8ab587d34080de94140b54f07168451e7d0b655e/index.js#L229-L241 (MIT License)
208
+ function isBlobLike(object) {
209
+ return (
210
+ (Blob && object instanceof Blob) ||
211
+ (object &&
212
+ typeof object === 'object' &&
213
+ (typeof object.stream === 'function' || typeof object.arrayBuffer === 'function') &&
214
+ /^(Blob|File)$/.test(object[Symbol.toStringTag]))
215
+ )
216
+ }
217
+
218
+ function isBuffer(buffer) {
219
+ // See, https://github.com/mcollina/undici/pull/319
220
+ return buffer instanceof Uint8Array || Buffer.isBuffer(buffer)
221
+ }
222
+
223
+ function bodyLength(body) {
224
+ if (body == null) {
225
+ return 0
226
+ } else if (isStream(body)) {
227
+ const state = body._readableState
228
+ return state && state.ended === true && Number.isFinite(state.length) ? state.length : null
229
+ } else if (isBlobLike(body)) {
230
+ return body.size != null ? body.size : null
231
+ } else if (isBuffer(body)) {
232
+ return body.byteLength
233
+ }
234
+
235
+ return null
236
+ }
237
+
207
238
  module.exports = {
208
239
  isStream,
240
+ isBuffer,
241
+ isBlobLike,
209
242
  AbortError,
243
+ bodyLength,
210
244
  parseHeaders,
211
245
  isDisturbed,
212
246
  parseContentRange,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",
@@ -18,6 +18,9 @@
18
18
  "eslint": "^8.50.0",
19
19
  "eslint-config-prettier": "^9.0.0",
20
20
  "eslint-config-standard": "^17.0.0",
21
+ "eslint-plugin-import": "^2.28.1",
22
+ "eslint-plugin-n": "^16.2.0",
23
+ "eslint-plugin-promise": "^6.1.1",
21
24
  "husky": "^8.0.3",
22
25
  "lint-staged": "^14.0.1",
23
26
  "pinst": "^3.0.0",