@nxtedition/nxt-undici 2.0.58 → 2.1.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.
package/lib/index.js CHANGED
@@ -4,6 +4,8 @@ import undici from 'undici'
4
4
  import { parseHeaders, AbortError, isStream } from './utils.js'
5
5
  import { BodyReadable } from './readable.js'
6
6
 
7
+ export { parseHeaders } from './utils.js'
8
+
7
9
  const dispatcherCache = new WeakMap()
8
10
 
9
11
  export const interceptors = {
@@ -104,8 +106,8 @@ export async function request(url, opts) {
104
106
  dispatch = interceptors.requestId(dispatch)
105
107
  dispatch = interceptors.responseRetry(dispatch)
106
108
  dispatch = interceptors.responseVerify(dispatch)
107
- dispatch = interceptors.cache(dispatch)
108
109
  dispatch = interceptors.redirect(dispatch)
110
+ dispatch = interceptors.cache(dispatch)
109
111
  dispatch = interceptors.proxy(dispatch)
110
112
  dispatcherCache.set(dispatcher, dispatch)
111
113
  }
@@ -134,6 +136,14 @@ export async function request(url, opts) {
134
136
  error: opts.error ?? true,
135
137
  verify: opts.verify ?? true,
136
138
  logger: opts.logger ?? null,
139
+ startTime: performance.now(),
140
+ stats: {
141
+ connect: -1,
142
+ headers: -1,
143
+ data: -1,
144
+ complete: -1,
145
+ error: -1,
146
+ },
137
147
  },
138
148
  {
139
149
  resolve,
@@ -145,6 +155,8 @@ export async function request(url, opts) {
145
155
  /** @type {Function | null} */ abort: null,
146
156
  /** @type {stream.Readable | null} */ body: null,
147
157
  onConnect(abort) {
158
+ this.stats.connect = performance.now() - this.startTime
159
+
148
160
  if (this.signal?.aborted) {
149
161
  abort(this.signal.reason)
150
162
  } else {
@@ -177,12 +189,17 @@ export async function request(url, opts) {
177
189
  statusMessage,
178
190
  headers = parseHeaders(rawHeaders),
179
191
  ) {
192
+ if (this.stats.headers === -1) {
193
+ this.stats.headers = performance.now() - this.startTime - this.stats.connect
194
+ }
195
+
180
196
  assert(statusCode >= 200)
181
197
 
182
198
  const contentLength = headers['content-length']
183
199
  const contentType = headers['content-type']
184
200
 
185
201
  this.body = new BodyReadable(this, {
202
+ stats: this.stats,
186
203
  resume,
187
204
  abort: this.abort,
188
205
  highWaterMark: this.highWaterMark,
@@ -208,12 +225,24 @@ export async function request(url, opts) {
208
225
  return true
209
226
  },
210
227
  onData(chunk) {
228
+ if (this.stats.data === -1) {
229
+ this.stats.data = performance.now() - this.startTime - this.stats.headers
230
+ }
231
+
211
232
  return this.body.push(chunk)
212
233
  },
213
234
  onComplete() {
235
+ if (this.stats.complete === -1) {
236
+ this.stats.complete = performance.now() - this.startTime - this.stats.data
237
+ }
238
+
214
239
  this.body.push(null)
215
240
  },
216
241
  onError(err) {
242
+ if (this.stats.error === -1) {
243
+ this.stats.error = performance.now() - this.startTime - this.stats.data
244
+ }
245
+
217
246
  this.signal?.removeEventListener('abort', this.onAbort)
218
247
  this.signal = null
219
248
 
@@ -107,7 +107,7 @@ class CacheStore {
107
107
 
108
108
  function makeKey(opts) {
109
109
  // NOTE: Ignores headers...
110
- return `${opts.method}:${opts.path}`
110
+ return `${opts.origin}:${opts.method}:${opts.path}`
111
111
  }
112
112
 
113
113
  const DEFAULT_CACHE_STORE = new CacheStore({ maxSize: 128 * 1024, maxEntrySize: 1024 })
@@ -20,7 +20,7 @@ class Handler extends DecoratorHandler {
20
20
  {
21
21
  headers: rawHeaders,
22
22
  httpVersion: this.#opts.httpVersion ?? this.#opts.req?.httpVersion,
23
- socket: null,
23
+ socket: this.#opts.socket,
24
24
  proxyName: this.#opts.name,
25
25
  },
26
26
  (acc, key, val) => {
@@ -40,7 +40,7 @@ class Handler extends DecoratorHandler {
40
40
  {
41
41
  headers: rawHeaders,
42
42
  httpVersion: this.#opts.httpVersion ?? this.#opts.req?.httpVersion,
43
- socket: null,
43
+ socket: this.#opts.socket,
44
44
  proxyName: this.#opts.name,
45
45
  },
46
46
  (acc, key, val) => {
package/lib/readable.js CHANGED
@@ -4,6 +4,7 @@ import { errors as undiciErrors } from 'undici'
4
4
 
5
5
  const { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = undiciErrors
6
6
 
7
+ const kStats = Symbol('kStats')
7
8
  const kConsume = Symbol('kConsume')
8
9
  const kReading = Symbol('kReading')
9
10
  const kBody = Symbol('kBody')
@@ -26,6 +27,7 @@ export class BodyReadable extends Readable {
26
27
  constructor(
27
28
  handler,
28
29
  {
30
+ stats,
29
31
  contentType = '',
30
32
  method,
31
33
  statusCode,
@@ -45,6 +47,7 @@ export class BodyReadable extends Readable {
45
47
 
46
48
  this._readableState.dataEmitted = false
47
49
 
50
+ this[kStats] = stats
48
51
  this[kHandler] = handler
49
52
  this[kStatusCode] = statusCode
50
53
  this[kStatusMessage] = statusMessage
@@ -65,6 +68,10 @@ export class BodyReadable extends Readable {
65
68
  this[kReading] = false
66
69
  }
67
70
 
71
+ get stats() {
72
+ return this[kStats]
73
+ }
74
+
68
75
  get statusCode() {
69
76
  return this[kStatusCode]
70
77
  }
package/lib/utils.js CHANGED
@@ -229,7 +229,7 @@ export function parseHeaders(headers, obj) {
229
229
  let val = obj[key]
230
230
 
231
231
  if (val) {
232
- if (typeof val === 'string') {
232
+ if (!Array.isArray(val)) {
233
233
  val = [val]
234
234
  obj[key] = val
235
235
  }
@@ -260,7 +260,7 @@ export function parseHeaders(headers, obj) {
260
260
  let val = obj[key]
261
261
 
262
262
  if (val) {
263
- if (typeof val === 'string') {
263
+ if (!Array.isArray(val)) {
264
264
  val = [val]
265
265
  obj[key] = val
266
266
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "2.0.58",
3
+ "version": "2.1.1",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",