undici 6.21.0 → 7.0.0-alpha.10

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 (156) hide show
  1. package/README.md +27 -46
  2. package/docs/docs/api/Agent.md +14 -17
  3. package/docs/docs/api/BalancedPool.md +16 -16
  4. package/docs/docs/api/CacheStore.md +131 -0
  5. package/docs/docs/api/Client.md +12 -14
  6. package/docs/docs/api/Debug.md +1 -1
  7. package/docs/docs/api/Dispatcher.md +98 -194
  8. package/docs/docs/api/EnvHttpProxyAgent.md +12 -13
  9. package/docs/docs/api/MockAgent.md +5 -3
  10. package/docs/docs/api/MockClient.md +5 -5
  11. package/docs/docs/api/MockPool.md +4 -3
  12. package/docs/docs/api/Pool.md +15 -16
  13. package/docs/docs/api/PoolStats.md +1 -1
  14. package/docs/docs/api/ProxyAgent.md +3 -3
  15. package/docs/docs/api/RedirectHandler.md +1 -1
  16. package/docs/docs/api/RetryAgent.md +1 -1
  17. package/docs/docs/api/RetryHandler.md +4 -4
  18. package/docs/docs/api/WebSocket.md +46 -4
  19. package/docs/docs/api/api-lifecycle.md +11 -11
  20. package/docs/docs/best-practices/mocking-request.md +2 -2
  21. package/docs/docs/best-practices/proxy.md +1 -1
  22. package/index.d.ts +1 -1
  23. package/index.js +23 -7
  24. package/lib/api/abort-signal.js +2 -0
  25. package/lib/api/api-connect.js +3 -1
  26. package/lib/api/api-pipeline.js +7 -6
  27. package/lib/api/api-request.js +33 -48
  28. package/lib/api/api-stream.js +39 -50
  29. package/lib/api/api-upgrade.js +5 -3
  30. package/lib/api/readable.js +235 -62
  31. package/lib/api/util.js +2 -0
  32. package/lib/cache/memory-cache-store.js +177 -0
  33. package/lib/cache/sqlite-cache-store.js +446 -0
  34. package/lib/core/constants.js +35 -10
  35. package/lib/core/diagnostics.js +122 -128
  36. package/lib/core/errors.js +6 -6
  37. package/lib/core/request.js +13 -11
  38. package/lib/core/symbols.js +2 -1
  39. package/lib/core/tree.js +9 -1
  40. package/lib/core/util.js +237 -49
  41. package/lib/dispatcher/agent.js +3 -17
  42. package/lib/dispatcher/balanced-pool.js +5 -8
  43. package/lib/dispatcher/client-h1.js +379 -134
  44. package/lib/dispatcher/client-h2.js +173 -107
  45. package/lib/dispatcher/client.js +19 -32
  46. package/lib/dispatcher/dispatcher-base.js +6 -35
  47. package/lib/dispatcher/dispatcher.js +7 -24
  48. package/lib/dispatcher/fixed-queue.js +91 -49
  49. package/lib/dispatcher/pool-stats.js +2 -0
  50. package/lib/dispatcher/pool.js +3 -6
  51. package/lib/dispatcher/proxy-agent.js +3 -6
  52. package/lib/handler/cache-handler.js +393 -0
  53. package/lib/handler/cache-revalidation-handler.js +124 -0
  54. package/lib/handler/decorator-handler.js +27 -0
  55. package/lib/handler/redirect-handler.js +54 -59
  56. package/lib/handler/retry-handler.js +77 -109
  57. package/lib/handler/unwrap-handler.js +96 -0
  58. package/lib/handler/wrap-handler.js +98 -0
  59. package/lib/interceptor/cache.js +350 -0
  60. package/lib/interceptor/dns.js +375 -0
  61. package/lib/interceptor/dump.js +2 -2
  62. package/lib/interceptor/redirect.js +11 -14
  63. package/lib/interceptor/response-error.js +18 -7
  64. package/lib/llhttp/constants.d.ts +97 -0
  65. package/lib/llhttp/constants.js +412 -192
  66. package/lib/llhttp/constants.js.map +1 -0
  67. package/lib/llhttp/llhttp-wasm.js +11 -1
  68. package/lib/llhttp/llhttp_simd-wasm.js +11 -1
  69. package/lib/llhttp/utils.d.ts +2 -0
  70. package/lib/llhttp/utils.js +9 -9
  71. package/lib/llhttp/utils.js.map +1 -0
  72. package/lib/mock/mock-agent.js +5 -8
  73. package/lib/mock/mock-client.js +9 -4
  74. package/lib/mock/mock-errors.js +3 -1
  75. package/lib/mock/mock-interceptor.js +8 -6
  76. package/lib/mock/mock-pool.js +9 -4
  77. package/lib/mock/mock-symbols.js +3 -1
  78. package/lib/mock/mock-utils.js +29 -5
  79. package/lib/util/cache.js +360 -0
  80. package/lib/web/cache/cache.js +24 -21
  81. package/lib/web/cache/cachestorage.js +1 -1
  82. package/lib/web/cookies/index.js +29 -14
  83. package/lib/web/cookies/parse.js +8 -3
  84. package/lib/web/eventsource/eventsource-stream.js +9 -8
  85. package/lib/web/eventsource/eventsource.js +10 -6
  86. package/lib/web/fetch/body.js +43 -41
  87. package/lib/web/fetch/constants.js +12 -5
  88. package/lib/web/fetch/data-url.js +3 -3
  89. package/lib/web/fetch/formdata-parser.js +72 -45
  90. package/lib/web/fetch/formdata.js +65 -54
  91. package/lib/web/fetch/headers.js +118 -86
  92. package/lib/web/fetch/index.js +58 -67
  93. package/lib/web/fetch/request.js +136 -77
  94. package/lib/web/fetch/response.js +87 -56
  95. package/lib/web/fetch/util.js +259 -109
  96. package/lib/web/fetch/webidl.js +113 -68
  97. package/lib/web/websocket/connection.js +76 -147
  98. package/lib/web/websocket/constants.js +70 -10
  99. package/lib/web/websocket/events.js +4 -2
  100. package/lib/web/websocket/frame.js +45 -3
  101. package/lib/web/websocket/receiver.js +29 -33
  102. package/lib/web/websocket/sender.js +18 -13
  103. package/lib/web/websocket/stream/websocketerror.js +83 -0
  104. package/lib/web/websocket/stream/websocketstream.js +485 -0
  105. package/lib/web/websocket/util.js +128 -77
  106. package/lib/web/websocket/websocket.js +234 -135
  107. package/package.json +24 -36
  108. package/scripts/strip-comments.js +3 -1
  109. package/types/agent.d.ts +7 -7
  110. package/types/api.d.ts +24 -24
  111. package/types/balanced-pool.d.ts +11 -11
  112. package/types/cache-interceptor.d.ts +172 -0
  113. package/types/client.d.ts +11 -12
  114. package/types/cookies.d.ts +2 -0
  115. package/types/diagnostics-channel.d.ts +10 -10
  116. package/types/dispatcher.d.ts +113 -90
  117. package/types/env-http-proxy-agent.d.ts +2 -2
  118. package/types/errors.d.ts +53 -47
  119. package/types/fetch.d.ts +17 -16
  120. package/types/formdata.d.ts +7 -7
  121. package/types/global-dispatcher.d.ts +4 -4
  122. package/types/global-origin.d.ts +5 -5
  123. package/types/handlers.d.ts +7 -7
  124. package/types/header.d.ts +157 -1
  125. package/types/index.d.ts +44 -46
  126. package/types/interceptors.d.ts +25 -8
  127. package/types/mock-agent.d.ts +21 -18
  128. package/types/mock-client.d.ts +4 -4
  129. package/types/mock-errors.d.ts +3 -3
  130. package/types/mock-interceptor.d.ts +19 -19
  131. package/types/mock-pool.d.ts +4 -4
  132. package/types/patch.d.ts +0 -4
  133. package/types/pool-stats.d.ts +8 -8
  134. package/types/pool.d.ts +12 -12
  135. package/types/proxy-agent.d.ts +4 -4
  136. package/types/readable.d.ts +18 -15
  137. package/types/retry-agent.d.ts +1 -1
  138. package/types/retry-handler.d.ts +10 -10
  139. package/types/util.d.ts +3 -3
  140. package/types/utility.d.ts +7 -0
  141. package/types/webidl.d.ts +44 -6
  142. package/types/websocket.d.ts +34 -1
  143. package/docs/docs/api/DispatchInterceptor.md +0 -60
  144. package/lib/interceptor/redirect-interceptor.js +0 -21
  145. package/lib/mock/pluralizer.js +0 -29
  146. package/lib/web/cache/symbols.js +0 -5
  147. package/lib/web/fetch/file.js +0 -126
  148. package/lib/web/fetch/symbols.js +0 -9
  149. package/lib/web/fileapi/encoding.js +0 -290
  150. package/lib/web/fileapi/filereader.js +0 -344
  151. package/lib/web/fileapi/progressevent.js +0 -78
  152. package/lib/web/fileapi/symbols.js +0 -10
  153. package/lib/web/fileapi/util.js +0 -391
  154. package/lib/web/websocket/symbols.js +0 -12
  155. package/types/file.d.ts +0 -39
  156. package/types/filereader.d.ts +0 -54
@@ -0,0 +1,375 @@
1
+ 'use strict'
2
+ const { isIP } = require('node:net')
3
+ const { lookup } = require('node:dns')
4
+ const DecoratorHandler = require('../handler/decorator-handler')
5
+ const { InvalidArgumentError, InformationalError } = require('../core/errors')
6
+ const maxInt = Math.pow(2, 31) - 1
7
+
8
+ class DNSInstance {
9
+ #maxTTL = 0
10
+ #maxItems = 0
11
+ #records = new Map()
12
+ dualStack = true
13
+ affinity = null
14
+ lookup = null
15
+ pick = null
16
+
17
+ constructor (opts) {
18
+ this.#maxTTL = opts.maxTTL
19
+ this.#maxItems = opts.maxItems
20
+ this.dualStack = opts.dualStack
21
+ this.affinity = opts.affinity
22
+ this.lookup = opts.lookup ?? this.#defaultLookup
23
+ this.pick = opts.pick ?? this.#defaultPick
24
+ }
25
+
26
+ get full () {
27
+ return this.#records.size === this.#maxItems
28
+ }
29
+
30
+ runLookup (origin, opts, cb) {
31
+ const ips = this.#records.get(origin.hostname)
32
+
33
+ // If full, we just return the origin
34
+ if (ips == null && this.full) {
35
+ cb(null, origin.origin)
36
+ return
37
+ }
38
+
39
+ const newOpts = {
40
+ affinity: this.affinity,
41
+ dualStack: this.dualStack,
42
+ lookup: this.lookup,
43
+ pick: this.pick,
44
+ ...opts.dns,
45
+ maxTTL: this.#maxTTL,
46
+ maxItems: this.#maxItems
47
+ }
48
+
49
+ // If no IPs we lookup
50
+ if (ips == null) {
51
+ this.lookup(origin, newOpts, (err, addresses) => {
52
+ if (err || addresses == null || addresses.length === 0) {
53
+ cb(err ?? new InformationalError('No DNS entries found'))
54
+ return
55
+ }
56
+
57
+ this.setRecords(origin, addresses)
58
+ const records = this.#records.get(origin.hostname)
59
+
60
+ const ip = this.pick(
61
+ origin,
62
+ records,
63
+ newOpts.affinity
64
+ )
65
+
66
+ let port
67
+ if (typeof ip.port === 'number') {
68
+ port = `:${ip.port}`
69
+ } else if (origin.port !== '') {
70
+ port = `:${origin.port}`
71
+ } else {
72
+ port = ''
73
+ }
74
+
75
+ cb(
76
+ null,
77
+ `${origin.protocol}//${
78
+ ip.family === 6 ? `[${ip.address}]` : ip.address
79
+ }${port}`
80
+ )
81
+ })
82
+ } else {
83
+ // If there's IPs we pick
84
+ const ip = this.pick(
85
+ origin,
86
+ ips,
87
+ newOpts.affinity
88
+ )
89
+
90
+ // If no IPs we lookup - deleting old records
91
+ if (ip == null) {
92
+ this.#records.delete(origin.hostname)
93
+ this.runLookup(origin, opts, cb)
94
+ return
95
+ }
96
+
97
+ let port
98
+ if (typeof ip.port === 'number') {
99
+ port = `:${ip.port}`
100
+ } else if (origin.port !== '') {
101
+ port = `:${origin.port}`
102
+ } else {
103
+ port = ''
104
+ }
105
+
106
+ cb(
107
+ null,
108
+ `${origin.protocol}//${
109
+ ip.family === 6 ? `[${ip.address}]` : ip.address
110
+ }${port}`
111
+ )
112
+ }
113
+ }
114
+
115
+ #defaultLookup (origin, opts, cb) {
116
+ lookup(
117
+ origin.hostname,
118
+ {
119
+ all: true,
120
+ family: this.dualStack === false ? this.affinity : 0,
121
+ order: 'ipv4first'
122
+ },
123
+ (err, addresses) => {
124
+ if (err) {
125
+ return cb(err)
126
+ }
127
+
128
+ const results = new Map()
129
+
130
+ for (const addr of addresses) {
131
+ // On linux we found duplicates, we attempt to remove them with
132
+ // the latest record
133
+ results.set(`${addr.address}:${addr.family}`, addr)
134
+ }
135
+
136
+ cb(null, results.values())
137
+ }
138
+ )
139
+ }
140
+
141
+ #defaultPick (origin, hostnameRecords, affinity) {
142
+ let ip = null
143
+ const { records, offset } = hostnameRecords
144
+
145
+ let family
146
+ if (this.dualStack) {
147
+ if (affinity == null) {
148
+ // Balance between ip families
149
+ if (offset == null || offset === maxInt) {
150
+ hostnameRecords.offset = 0
151
+ affinity = 4
152
+ } else {
153
+ hostnameRecords.offset++
154
+ affinity = (hostnameRecords.offset & 1) === 1 ? 6 : 4
155
+ }
156
+ }
157
+
158
+ if (records[affinity] != null && records[affinity].ips.length > 0) {
159
+ family = records[affinity]
160
+ } else {
161
+ family = records[affinity === 4 ? 6 : 4]
162
+ }
163
+ } else {
164
+ family = records[affinity]
165
+ }
166
+
167
+ // If no IPs we return null
168
+ if (family == null || family.ips.length === 0) {
169
+ return ip
170
+ }
171
+
172
+ if (family.offset == null || family.offset === maxInt) {
173
+ family.offset = 0
174
+ } else {
175
+ family.offset++
176
+ }
177
+
178
+ const position = family.offset % family.ips.length
179
+ ip = family.ips[position] ?? null
180
+
181
+ if (ip == null) {
182
+ return ip
183
+ }
184
+
185
+ if (Date.now() - ip.timestamp > ip.ttl) { // record TTL is already in ms
186
+ // We delete expired records
187
+ // It is possible that they have different TTL, so we manage them individually
188
+ family.ips.splice(position, 1)
189
+ return this.pick(origin, hostnameRecords, affinity)
190
+ }
191
+
192
+ return ip
193
+ }
194
+
195
+ setRecords (origin, addresses) {
196
+ const timestamp = Date.now()
197
+ const records = { records: { 4: null, 6: null } }
198
+ for (const record of addresses) {
199
+ record.timestamp = timestamp
200
+ if (typeof record.ttl === 'number') {
201
+ // The record TTL is expected to be in ms
202
+ record.ttl = Math.min(record.ttl, this.#maxTTL)
203
+ } else {
204
+ record.ttl = this.#maxTTL
205
+ }
206
+
207
+ const familyRecords = records.records[record.family] ?? { ips: [] }
208
+
209
+ familyRecords.ips.push(record)
210
+ records.records[record.family] = familyRecords
211
+ }
212
+
213
+ this.#records.set(origin.hostname, records)
214
+ }
215
+
216
+ getHandler (meta, opts) {
217
+ return new DNSDispatchHandler(this, meta, opts)
218
+ }
219
+ }
220
+
221
+ class DNSDispatchHandler extends DecoratorHandler {
222
+ #state = null
223
+ #opts = null
224
+ #dispatch = null
225
+ #handler = null
226
+ #origin = null
227
+
228
+ constructor (state, { origin, handler, dispatch }, opts) {
229
+ super(handler)
230
+ this.#origin = origin
231
+ this.#handler = handler
232
+ this.#opts = { ...opts }
233
+ this.#state = state
234
+ this.#dispatch = dispatch
235
+ }
236
+
237
+ onError (err) {
238
+ switch (err.code) {
239
+ case 'ETIMEDOUT':
240
+ case 'ECONNREFUSED': {
241
+ if (this.#state.dualStack) {
242
+ // We delete the record and retry
243
+ this.#state.runLookup(this.#origin, this.#opts, (err, newOrigin) => {
244
+ if (err) {
245
+ return this.#handler.onError(err)
246
+ }
247
+
248
+ const dispatchOpts = {
249
+ ...this.#opts,
250
+ origin: newOrigin
251
+ }
252
+
253
+ this.#dispatch(dispatchOpts, this)
254
+ })
255
+
256
+ // if dual-stack disabled, we error out
257
+ return
258
+ }
259
+
260
+ this.#handler.onError(err)
261
+ return
262
+ }
263
+ case 'ENOTFOUND':
264
+ this.#state.deleteRecord(this.#origin)
265
+ // eslint-disable-next-line no-fallthrough
266
+ default:
267
+ this.#handler.onError(err)
268
+ break
269
+ }
270
+ }
271
+ }
272
+
273
+ module.exports = interceptorOpts => {
274
+ if (
275
+ interceptorOpts?.maxTTL != null &&
276
+ (typeof interceptorOpts?.maxTTL !== 'number' || interceptorOpts?.maxTTL < 0)
277
+ ) {
278
+ throw new InvalidArgumentError('Invalid maxTTL. Must be a positive number')
279
+ }
280
+
281
+ if (
282
+ interceptorOpts?.maxItems != null &&
283
+ (typeof interceptorOpts?.maxItems !== 'number' ||
284
+ interceptorOpts?.maxItems < 1)
285
+ ) {
286
+ throw new InvalidArgumentError(
287
+ 'Invalid maxItems. Must be a positive number and greater than zero'
288
+ )
289
+ }
290
+
291
+ if (
292
+ interceptorOpts?.affinity != null &&
293
+ interceptorOpts?.affinity !== 4 &&
294
+ interceptorOpts?.affinity !== 6
295
+ ) {
296
+ throw new InvalidArgumentError('Invalid affinity. Must be either 4 or 6')
297
+ }
298
+
299
+ if (
300
+ interceptorOpts?.dualStack != null &&
301
+ typeof interceptorOpts?.dualStack !== 'boolean'
302
+ ) {
303
+ throw new InvalidArgumentError('Invalid dualStack. Must be a boolean')
304
+ }
305
+
306
+ if (
307
+ interceptorOpts?.lookup != null &&
308
+ typeof interceptorOpts?.lookup !== 'function'
309
+ ) {
310
+ throw new InvalidArgumentError('Invalid lookup. Must be a function')
311
+ }
312
+
313
+ if (
314
+ interceptorOpts?.pick != null &&
315
+ typeof interceptorOpts?.pick !== 'function'
316
+ ) {
317
+ throw new InvalidArgumentError('Invalid pick. Must be a function')
318
+ }
319
+
320
+ const dualStack = interceptorOpts?.dualStack ?? true
321
+ let affinity
322
+ if (dualStack) {
323
+ affinity = interceptorOpts?.affinity ?? null
324
+ } else {
325
+ affinity = interceptorOpts?.affinity ?? 4
326
+ }
327
+
328
+ const opts = {
329
+ maxTTL: interceptorOpts?.maxTTL ?? 10e3, // Expressed in ms
330
+ lookup: interceptorOpts?.lookup ?? null,
331
+ pick: interceptorOpts?.pick ?? null,
332
+ dualStack,
333
+ affinity,
334
+ maxItems: interceptorOpts?.maxItems ?? Infinity
335
+ }
336
+
337
+ const instance = new DNSInstance(opts)
338
+
339
+ return dispatch => {
340
+ return function dnsInterceptor (origDispatchOpts, handler) {
341
+ const origin =
342
+ origDispatchOpts.origin.constructor === URL
343
+ ? origDispatchOpts.origin
344
+ : new URL(origDispatchOpts.origin)
345
+
346
+ if (isIP(origin.hostname) !== 0) {
347
+ return dispatch(origDispatchOpts, handler)
348
+ }
349
+
350
+ instance.runLookup(origin, origDispatchOpts, (err, newOrigin) => {
351
+ if (err) {
352
+ return handler.onError(err)
353
+ }
354
+
355
+ let dispatchOpts = null
356
+ dispatchOpts = {
357
+ ...origDispatchOpts,
358
+ servername: origin.hostname, // For SNI on TLS
359
+ origin: newOrigin,
360
+ headers: {
361
+ host: origin.hostname,
362
+ ...origDispatchOpts.headers
363
+ }
364
+ }
365
+
366
+ dispatch(
367
+ dispatchOpts,
368
+ instance.getHandler({ origin, dispatch, handler }, origDispatchOpts)
369
+ )
370
+ })
371
+
372
+ return true
373
+ }
374
+ }
375
+ }
@@ -14,12 +14,12 @@ class DumpHandler extends DecoratorHandler {
14
14
  #handler = null
15
15
 
16
16
  constructor ({ maxSize }, handler) {
17
- super(handler)
18
-
19
17
  if (maxSize != null && (!Number.isFinite(maxSize) || maxSize < 1)) {
20
18
  throw new InvalidArgumentError('maxSize must be a number greater than 0')
21
19
  }
22
20
 
21
+ super(handler)
22
+
23
23
  this.#maxSize = maxSize ?? this.#maxSize
24
24
  this.#handler = handler
25
25
  }
@@ -1,24 +1,21 @@
1
1
  'use strict'
2
+
2
3
  const RedirectHandler = require('../handler/redirect-handler')
3
4
 
4
- module.exports = opts => {
5
- const globalMaxRedirections = opts?.maxRedirections
6
- return dispatch => {
7
- return function redirectInterceptor (opts, handler) {
8
- const { maxRedirections = globalMaxRedirections, ...baseOpts } = opts
5
+ function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections } = {}) {
6
+ return (dispatch) => {
7
+ return function Intercept (opts, handler) {
8
+ const { maxRedirections = defaultMaxRedirections, ...rest } = opts
9
9
 
10
- if (!maxRedirections) {
10
+ if (maxRedirections == null || maxRedirections === 0) {
11
11
  return dispatch(opts, handler)
12
12
  }
13
13
 
14
- const redirectHandler = new RedirectHandler(
15
- dispatch,
16
- maxRedirections,
17
- opts,
18
- handler
19
- )
20
-
21
- return dispatch(baseOpts, redirectHandler)
14
+ const dispatchOpts = { ...rest, maxRedirections: 0 } // Stop sub dispatcher from also redirecting.
15
+ const redirectHandler = new RedirectHandler(dispatch, maxRedirections, dispatchOpts, handler)
16
+ return dispatch(dispatchOpts, redirectHandler)
22
17
  }
23
18
  }
24
19
  }
20
+
21
+ module.exports = createRedirectInterceptor
@@ -4,7 +4,7 @@ const { parseHeaders } = require('../core/util')
4
4
  const DecoratorHandler = require('../handler/decorator-handler')
5
5
  const { ResponseError } = require('../core/errors')
6
6
 
7
- class Handler extends DecoratorHandler {
7
+ class ResponseErrorHandler extends DecoratorHandler {
8
8
  #handler
9
9
  #statusCode
10
10
  #contentType
@@ -27,6 +27,10 @@ class Handler extends DecoratorHandler {
27
27
  return this.#handler.onConnect(abort)
28
28
  }
29
29
 
30
+ #checkContentType (contentType) {
31
+ return this.#contentType.indexOf(contentType) === 0
32
+ }
33
+
30
34
  onHeaders (statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
31
35
  this.#statusCode = statusCode
32
36
  this.#headers = headers
@@ -36,7 +40,7 @@ class Handler extends DecoratorHandler {
36
40
  return this.#handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers)
37
41
  }
38
42
 
39
- if (this.#contentType === 'application/json' || this.#contentType === 'text/plain') {
43
+ if (this.#checkContentType('application/json') || this.#checkContentType('text/plain')) {
40
44
  this.#decoder = new TextDecoder('utf-8')
41
45
  }
42
46
  }
@@ -53,7 +57,7 @@ class Handler extends DecoratorHandler {
53
57
  if (this.#statusCode >= 400) {
54
58
  this.#body += this.#decoder?.decode(undefined, { stream: false }) ?? ''
55
59
 
56
- if (this.#contentType === 'application/json') {
60
+ if (this.#checkContentType('application/json')) {
57
61
  try {
58
62
  this.#body = JSON.parse(this.#body)
59
63
  } catch {
@@ -65,7 +69,10 @@ class Handler extends DecoratorHandler {
65
69
  const stackTraceLimit = Error.stackTraceLimit
66
70
  Error.stackTraceLimit = 0
67
71
  try {
68
- err = new ResponseError('Response Error', this.#statusCode, this.#headers, this.#body)
72
+ err = new ResponseError('Response Error', this.#statusCode, {
73
+ body: this.#body,
74
+ headers: this.#headers
75
+ })
69
76
  } finally {
70
77
  Error.stackTraceLimit = stackTraceLimit
71
78
  }
@@ -81,6 +88,10 @@ class Handler extends DecoratorHandler {
81
88
  }
82
89
  }
83
90
 
84
- module.exports = (dispatch) => (opts, handler) => opts.throwOnError
85
- ? dispatch(opts, new Handler(opts, { handler }))
86
- : dispatch(opts, handler)
91
+ module.exports = () => {
92
+ return (dispatch) => {
93
+ return function Intercept (opts, handler) {
94
+ return dispatch(opts, new ResponseErrorHandler(opts, { handler }))
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,97 @@
1
+ export type IntDict = Record<string, number>;
2
+ export declare const ERROR: IntDict;
3
+ export declare const TYPE: IntDict;
4
+ export declare const FLAGS: IntDict;
5
+ export declare const LENIENT_FLAGS: IntDict;
6
+ export declare const METHODS: IntDict;
7
+ export declare const STATUSES: IntDict;
8
+ export declare const FINISH: IntDict;
9
+ export declare const HEADER_STATE: IntDict;
10
+ export declare const METHODS_HTTP: number[];
11
+ export declare const METHODS_ICE: number[];
12
+ export declare const METHODS_RTSP: number[];
13
+ export declare const METHOD_MAP: IntDict;
14
+ export declare const H_METHOD_MAP: {
15
+ [k: string]: number;
16
+ };
17
+ export declare const STATUSES_HTTP: number[];
18
+ export type CharList = Array<string | number>;
19
+ export declare const ALPHA: CharList;
20
+ export declare const NUM_MAP: {
21
+ 0: number;
22
+ 1: number;
23
+ 2: number;
24
+ 3: number;
25
+ 4: number;
26
+ 5: number;
27
+ 6: number;
28
+ 7: number;
29
+ 8: number;
30
+ 9: number;
31
+ };
32
+ export declare const HEX_MAP: {
33
+ 0: number;
34
+ 1: number;
35
+ 2: number;
36
+ 3: number;
37
+ 4: number;
38
+ 5: number;
39
+ 6: number;
40
+ 7: number;
41
+ 8: number;
42
+ 9: number;
43
+ A: number;
44
+ B: number;
45
+ C: number;
46
+ D: number;
47
+ E: number;
48
+ F: number;
49
+ a: number;
50
+ b: number;
51
+ c: number;
52
+ d: number;
53
+ e: number;
54
+ f: number;
55
+ };
56
+ export declare const NUM: CharList;
57
+ export declare const ALPHANUM: CharList;
58
+ export declare const MARK: CharList;
59
+ export declare const USERINFO_CHARS: CharList;
60
+ export declare const URL_CHAR: CharList;
61
+ export declare const HEX: CharList;
62
+ export declare const TOKEN: CharList;
63
+ export declare const HEADER_CHARS: CharList;
64
+ export declare const CONNECTION_TOKEN_CHARS: CharList;
65
+ export declare const QUOTED_STRING: CharList;
66
+ export declare const HTAB_SP_VCHAR_OBS_TEXT: CharList;
67
+ export declare const MAJOR: {
68
+ 0: number;
69
+ 1: number;
70
+ 2: number;
71
+ 3: number;
72
+ 4: number;
73
+ 5: number;
74
+ 6: number;
75
+ 7: number;
76
+ 8: number;
77
+ 9: number;
78
+ };
79
+ export declare const MINOR: {
80
+ 0: number;
81
+ 1: number;
82
+ 2: number;
83
+ 3: number;
84
+ 4: number;
85
+ 5: number;
86
+ 6: number;
87
+ 7: number;
88
+ 8: number;
89
+ 9: number;
90
+ };
91
+ export declare const SPECIAL_HEADERS: {
92
+ connection: number;
93
+ 'content-length': number;
94
+ 'proxy-connection': number;
95
+ 'transfer-encoding': number;
96
+ upgrade: number;
97
+ };