@nxtedition/nxt-undici 2.2.4 → 2.2.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
@@ -137,13 +137,6 @@ export async function request(url, opts) {
137
137
  verify: opts.verify ?? true,
138
138
  logger: opts.logger ?? null,
139
139
  startTime: performance.now(),
140
- stats: {
141
- connect: -1,
142
- headers: -1,
143
- data: -1,
144
- complete: -1,
145
- error: -1,
146
- },
147
140
  },
148
141
  {
149
142
  resolve,
@@ -155,8 +148,6 @@ export async function request(url, opts) {
155
148
  /** @type {Function | null} */ abort: null,
156
149
  /** @type {stream.Readable | null} */ body: null,
157
150
  onConnect(abort) {
158
- this.stats.connect = performance.now() - this.startTime
159
-
160
151
  if (this.signal?.aborted) {
161
152
  abort(this.signal.reason)
162
153
  } else {
@@ -189,24 +180,19 @@ export async function request(url, opts) {
189
180
  statusMessage,
190
181
  headers = parseHeaders(rawHeaders),
191
182
  ) {
192
- if (this.stats.headers === -1) {
193
- this.stats.headers = performance.now() - this.startTime - this.stats.connect
194
- }
195
-
196
183
  assert(statusCode >= 200)
197
184
 
198
185
  const contentLength = headers['content-length']
199
186
  const contentType = headers['content-type']
200
187
 
201
188
  this.body = new BodyReadable(this, {
202
- stats: this.stats,
203
189
  resume,
204
190
  abort: this.abort,
205
191
  highWaterMark: this.highWaterMark,
206
192
  method: this.method,
207
193
  statusCode,
208
194
  statusMessage,
209
- contentType,
195
+ contentType: typeof contentType === 'string' ? contentType : undefined,
210
196
  headers,
211
197
  size: Number.isFinite(contentLength) ? contentLength : null,
212
198
  })
@@ -225,24 +211,12 @@ export async function request(url, opts) {
225
211
  return true
226
212
  },
227
213
  onData(chunk) {
228
- if (this.stats.data === -1) {
229
- this.stats.data = performance.now() - this.startTime - this.stats.headers
230
- }
231
-
232
214
  return this.body.push(chunk)
233
215
  },
234
216
  onComplete() {
235
- if (this.stats.complete === -1) {
236
- this.stats.complete = performance.now() - this.startTime - this.stats.data
237
- }
238
-
239
217
  this.body.push(null)
240
218
  },
241
219
  onError(err) {
242
- if (this.stats.error === -1) {
243
- this.stats.error = performance.now() - this.startTime - this.stats.data
244
- }
245
-
246
220
  this.signal?.removeEventListener('abort', this.onAbort)
247
221
  this.signal = null
248
222
 
@@ -10,7 +10,7 @@ class Handler extends DecoratorHandler {
10
10
  #logger
11
11
  #pos
12
12
  #timing
13
- #startTime
13
+ #startTime = performance.now()
14
14
 
15
15
  constructor(opts, { handler }) {
16
16
  super(handler)
@@ -24,12 +24,12 @@ class Handler extends DecoratorHandler {
24
24
  this.#pos = 0
25
25
  this.#abort = abort
26
26
  this.#timing = {
27
+ connect: performance.now() - this.#startTime,
27
28
  headers: -1,
28
29
  data: -1,
29
30
  complete: -1,
30
31
  error: -1,
31
32
  }
32
- this.#startTime = performance.now()
33
33
 
34
34
  this.#logger.debug({ ureq: this.#opts }, 'upstream request started')
35
35
 
@@ -49,7 +49,7 @@ class Handler extends DecoratorHandler {
49
49
  }
50
50
 
51
51
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
52
- this.#timing.headers = performance.now() - this.#startTime
52
+ this.#timing.headers = performance.now() - this.#timing.connect - this.#startTime
53
53
 
54
54
  this.#logger.debug(
55
55
  {
@@ -64,7 +64,7 @@ class Handler extends DecoratorHandler {
64
64
 
65
65
  onData(chunk) {
66
66
  if (this.#timing.data === -1) {
67
- this.#timing.data = performance.now() - this.#startTime
67
+ this.#timing.data = performance.now() - this.#timing.headers - this.#startTime
68
68
  }
69
69
 
70
70
  this.#pos += chunk.length
@@ -73,7 +73,7 @@ class Handler extends DecoratorHandler {
73
73
  }
74
74
 
75
75
  onComplete(rawTrailers) {
76
- this.#timing.complete = performance.now() - this.#startTime
76
+ this.#timing.complete = performance.now() - this.#timing.data - this.#startTime
77
77
 
78
78
  this.#logger.debug(
79
79
  { elapsedTime: this.#timing.complete, bytesRead: this.#pos, timing: this.#timing },
@@ -84,7 +84,7 @@ class Handler extends DecoratorHandler {
84
84
  }
85
85
 
86
86
  onError(err) {
87
- this.#timing.error = performance.now() - this.#startTime
87
+ this.#timing.error = performance.now() - this.#timing.data - this.#startTime
88
88
 
89
89
  if (this.#aborted) {
90
90
  this.#logger.debug(
@@ -69,7 +69,7 @@ class Handler extends DecoratorHandler {
69
69
  this.#count += 1
70
70
 
71
71
  if (typeof this.#opts.follow === 'function') {
72
- if (!this.#opts.follow(this.#location, this.#count)) {
72
+ if (!this.#opts.follow(this.#location, this.#count, this.#opts)) {
73
73
  assert(!this.#headersSent)
74
74
  this.#headersSent = true
75
75
  return this.#handler.onHeaders(statusCode, rawHeaders, resume, statusText, headers)
package/lib/readable.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import assert from 'node:assert'
2
- import { Readable, isDisturbed } from 'node:stream'
2
+ import { Readable } from 'node:stream'
3
3
  import { errors as undiciErrors } from 'undici'
4
+ import { isDisturbed } from './utils.js'
4
5
 
5
- const { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = undiciErrors
6
+ const { RequestAbortedError, NotSupportedError, InvalidArgumentError } = undiciErrors
6
7
 
7
- const kStats = Symbol('kStats')
8
8
  const kConsume = Symbol('kConsume')
9
9
  const kReading = Symbol('kReading')
10
10
  const kBody = Symbol('kBody')
@@ -27,7 +27,6 @@ export class BodyReadable extends Readable {
27
27
  constructor(
28
28
  handler,
29
29
  {
30
- stats,
31
30
  contentType = '',
32
31
  method,
33
32
  statusCode,
@@ -47,7 +46,6 @@ export class BodyReadable extends Readable {
47
46
 
48
47
  this._readableState.dataEmitted = false
49
48
 
50
- this[kStats] = stats
51
49
  this[kHandler] = handler
52
50
  this[kStatusCode] = statusCode
53
51
  this[kStatusMessage] = statusMessage
@@ -68,10 +66,6 @@ export class BodyReadable extends Readable {
68
66
  this[kReading] = false
69
67
  }
70
68
 
71
- get stats() {
72
- return this[kStats]
73
- }
74
-
75
69
  get statusCode() {
76
70
  return this[kStatusCode]
77
71
  }
@@ -198,7 +192,7 @@ export class BodyReadable extends Readable {
198
192
  const signal = opts?.signal
199
193
 
200
194
  if (this[kSize] != null && this[kSize] - this[kReadLength] > limit) {
201
- this.destroy(signal.reason ?? new AbortError())
195
+ this.destroy(signal.reason ?? new RequestAbortedError())
202
196
  }
203
197
 
204
198
  if (signal != null && (typeof signal !== 'object' || !('aborted' in signal))) {
@@ -222,14 +216,14 @@ export class BodyReadable extends Readable {
222
216
 
223
217
  return await new Promise((resolve, reject) => {
224
218
  const onAbort = () => {
225
- this.destroy(signal.reason ?? new AbortError())
219
+ this.destroy(signal.reason ?? new RequestAbortedError())
226
220
  }
227
221
  signal?.addEventListener('abort', onAbort)
228
222
 
229
223
  this.on('close', function () {
230
224
  signal?.removeEventListener('abort', onAbort)
231
225
  if (signal?.aborted) {
232
- reject(signal.reason ?? new AbortError())
226
+ reject(signal.reason ?? new RequestAbortedError())
233
227
  } else {
234
228
  resolve(null)
235
229
  }
package/lib/utils.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import tp from 'node:timers/promises'
2
2
  import cacheControlParser from 'cache-control-parser'
3
+ import stream from 'node:stream'
3
4
  import { util } from 'undici'
4
5
 
5
6
  export function parseCacheControl(str) {
@@ -39,7 +40,7 @@ export function isDisturbed(body) {
39
40
  return false
40
41
  }
41
42
 
42
- return true
43
+ return stream.isDisturbed(body)
43
44
  }
44
45
 
45
46
  export function parseContentRange(range) {
@@ -70,17 +71,13 @@ export function parseContentRange(range) {
70
71
  return { start, end: end ? end + 1 : size, size }
71
72
  }
72
73
 
73
- export function retry(err, retryCount, opts) {
74
+ export async function retry(err, retryCount, opts) {
74
75
  if (!opts) {
75
- return null
76
+ throw err
76
77
  }
77
78
 
78
79
  if (typeof opts === 'function') {
79
- try {
80
- return opts(err, retryCount, opts, (opts) => retry(err, retryCount, opts))
81
- } catch (err) {
82
- return Promise.reject(err)
83
- }
80
+ return opts(err, retryCount, opts, (opts) => retry(err, retryCount, opts))
84
81
  }
85
82
 
86
83
  if (typeof opts === 'number') {
@@ -90,7 +87,7 @@ export function retry(err, retryCount, opts) {
90
87
  const retryMax = opts?.count ?? 8
91
88
 
92
89
  if (retryCount > retryMax) {
93
- return null
90
+ throw err
94
91
  }
95
92
 
96
93
  const statusCode = err.statusCode ?? err.status ?? err.$metadata?.httpStatusCode ?? null
@@ -125,7 +122,7 @@ export function retry(err, retryCount, opts) {
125
122
  return tp.setTimeout(Math.min(10e3, retryCount * 1e3), undefined, { signal: opts.signal })
126
123
  }
127
124
 
128
- return null
125
+ throw err
129
126
  }
130
127
 
131
128
  export function parseURL(url) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "2.2.4",
3
+ "version": "2.2.6",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",
@@ -9,25 +9,25 @@
9
9
  "lib/*"
10
10
  ],
11
11
  "dependencies": {
12
- "cache-control-parser": "^2.0.5",
12
+ "cache-control-parser": "^2.0.6",
13
13
  "cacheable-lookup": "^7.0.0",
14
14
  "http-errors": "^2.0.0",
15
15
  "lru-cache": "^10.2.0",
16
- "undici": "^6.18.0"
16
+ "undici": "^6.18.2"
17
17
  },
18
18
  "devDependencies": {
19
- "@types/node": "^20.12.12",
19
+ "@types/node": "^20.14.2",
20
20
  "eslint": "^8.0.0",
21
21
  "eslint-config-prettier": "^9.1.0",
22
22
  "eslint-config-standard": "^17.0.0",
23
23
  "eslint-plugin-import": "^2.29.1",
24
- "eslint-plugin-n": "^17.7.0",
25
- "eslint-plugin-promise": "^6.1.1",
24
+ "eslint-plugin-n": "^17.9.0",
25
+ "eslint-plugin-promise": "^6.2.0",
26
26
  "husky": "^9.0.11",
27
- "lint-staged": "^15.2.2",
27
+ "lint-staged": "^15.2.7",
28
28
  "pinst": "^3.0.0",
29
- "prettier": "^3.2.5",
30
- "tap": "^18.8.0"
29
+ "prettier": "^3.3.2",
30
+ "tap": "^19.2.5"
31
31
  },
32
32
  "scripts": {
33
33
  "prepare": "husky install",