nock 15.0.0 → 15.0.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/README.md +39 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +109 -0
- package/dist/lib/back.d.ts +44 -0
- package/{lib → dist/lib}/back.js +111 -84
- package/dist/lib/common.d.ts +27 -0
- package/{lib → dist/lib}/common.js +80 -190
- package/dist/lib/debug.d.ts +9 -0
- package/dist/lib/debug.js +17 -0
- package/dist/lib/global_emitter.d.ts +11 -0
- package/dist/lib/global_emitter.js +13 -0
- package/dist/lib/handle-request.d.ts +2 -0
- package/{lib → dist/lib}/handle-request.js +24 -39
- package/dist/lib/intercept.d.ts +25 -0
- package/{lib → dist/lib}/intercept.js +81 -94
- package/dist/lib/interceptor.d.ts +44 -0
- package/{lib → dist/lib}/interceptor.js +223 -119
- package/dist/lib/interceptors/builtin.d.ts +3 -0
- package/dist/lib/interceptors/builtin.js +56 -0
- package/dist/lib/match_body.d.ts +1 -0
- package/{lib → dist/lib}/match_body.js +20 -27
- package/dist/lib/playback_interceptor.d.ts +8 -0
- package/{lib → dist/lib}/playback_interceptor.js +52 -62
- package/dist/lib/recorder.d.ts +13 -0
- package/{lib → dist/lib}/recorder.js +63 -92
- package/dist/lib/scope.d.ts +59 -0
- package/{lib → dist/lib}/scope.js +158 -87
- package/dist/lib/stringify.d.ts +24 -0
- package/dist/lib/stringify.js +50 -0
- package/dist/lib/utils/node/index.d.ts +4 -0
- package/dist/lib/utils/node/index.js +16 -0
- package/package.json +25 -22
- package/index.js +0 -55
- package/lib/create_response.js +0 -53
- package/lib/debug.js +0 -12
- package/lib/global_emitter.js +0 -5
- package/lib/interceptors/builtin.js +0 -67
- package/lib/interceptors/undici.js +0 -78
- package/lib/utils/node/index.js +0 -33
- package/types/index.d.ts +0 -319
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Normalizes the request options so that it always has `host` property.
|
|
10
|
-
*
|
|
11
|
-
* @param {Object} options - a parsed options object of the request
|
|
12
|
-
*/
|
|
13
|
-
function normalizeRequestOptions(options) {
|
|
1
|
+
import { common as debug } from './debug.js'
|
|
2
|
+
import timers from 'node:timers'
|
|
3
|
+
import util from 'node:util'
|
|
4
|
+
import zlib from 'node:zlib'
|
|
5
|
+
|
|
6
|
+
function normalizeRequestOptions(options ) {
|
|
14
7
|
options.proto = options.proto || 'http'
|
|
15
8
|
options.port = options.port || (options.proto === 'http' ? 80 : 443)
|
|
16
9
|
if (options.host) {
|
|
@@ -37,14 +30,7 @@ function normalizeRequestOptions(options) {
|
|
|
37
30
|
return options
|
|
38
31
|
}
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
* Returns true if the data contained in buffer can be reconstructed
|
|
42
|
-
* from its utf8 representation.
|
|
43
|
-
*
|
|
44
|
-
* @param {ArrayBuffer} buffer
|
|
45
|
-
* @returns {boolean}
|
|
46
|
-
*/
|
|
47
|
-
function isUtf8Representable(buffer) {
|
|
33
|
+
function isUtf8Representable(buffer ) {
|
|
48
34
|
try {
|
|
49
35
|
new TextDecoder('utf8', { fatal: true }).decode(buffer)
|
|
50
36
|
return true
|
|
@@ -53,13 +39,7 @@ function isUtf8Representable(buffer) {
|
|
|
53
39
|
}
|
|
54
40
|
}
|
|
55
41
|
|
|
56
|
-
|
|
57
|
-
* In WHATWG URL vernacular, this returns the origin portion of a URL.
|
|
58
|
-
* However, the port is not included if it's standard and not already present on the host.
|
|
59
|
-
*
|
|
60
|
-
* @param {URL} url
|
|
61
|
-
*/
|
|
62
|
-
function normalizeOrigin(url) {
|
|
42
|
+
function normalizeOrigin(url ) {
|
|
63
43
|
// Remove brackets from hostname if IPV6
|
|
64
44
|
const normalizedOrigin = url.hostname.startsWith('[')
|
|
65
45
|
? `${url.protocol}//${url.hostname.slice(1, -1)}${url.port ? `:${url.port}` : ''}`
|
|
@@ -71,15 +51,10 @@ function normalizeOrigin(url) {
|
|
|
71
51
|
}
|
|
72
52
|
}
|
|
73
53
|
|
|
74
|
-
|
|
75
|
-
* Get high level information about request as string
|
|
76
|
-
* @param {Request} request
|
|
77
|
-
* @param {string} body
|
|
78
|
-
*/
|
|
79
|
-
function stringifyRequest(request, body) {
|
|
54
|
+
function stringifyRequest(request , body ) {
|
|
80
55
|
const url = new URL(request.url)
|
|
81
56
|
|
|
82
|
-
const log
|
|
57
|
+
const log = {
|
|
83
58
|
method: request.method,
|
|
84
59
|
url: `${url.origin}${url.pathname}`,
|
|
85
60
|
headers: Object.fromEntries(request.headers.entries()),
|
|
@@ -92,41 +67,31 @@ function stringifyRequest(request, body) {
|
|
|
92
67
|
return JSON.stringify(log, null, 2)
|
|
93
68
|
}
|
|
94
69
|
|
|
95
|
-
function isContentEncoded(headers) {
|
|
70
|
+
function isContentEncoded(headers ) {
|
|
96
71
|
const contentEncoding = headers['content-encoding']
|
|
97
72
|
return typeof contentEncoding === 'string' && contentEncoding !== ''
|
|
98
73
|
}
|
|
99
74
|
|
|
100
|
-
|
|
101
|
-
* @param {Headers} headers
|
|
102
|
-
* @param {'gzip' | 'deflate'} encoder
|
|
103
|
-
* @returns
|
|
104
|
-
*/
|
|
105
|
-
function contentEncoding(headers, encoder) {
|
|
75
|
+
function contentEncoding(headers , encoder ) {
|
|
106
76
|
const contentEncoding = headers.get('content-encoding')
|
|
107
77
|
return contentEncoding?.toString() === encoder
|
|
108
78
|
}
|
|
109
79
|
|
|
110
|
-
|
|
111
|
-
* @param {Headers} headers
|
|
112
|
-
*/
|
|
113
|
-
function isJSONContent(headers) {
|
|
80
|
+
function isJSONContent(headers ) {
|
|
114
81
|
// https://tools.ietf.org/html/rfc8259
|
|
115
82
|
const contentType = String(headers.get('content-type') || '').toLowerCase()
|
|
116
83
|
return contentType.startsWith('application/json')
|
|
117
84
|
}
|
|
118
85
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
*/
|
|
124
|
-
function headersFieldNamesToLowerCase(headers, throwOnDuplicate) {
|
|
86
|
+
function headersFieldNamesToLowerCase(
|
|
87
|
+
headers ,
|
|
88
|
+
throwOnDuplicate ,
|
|
89
|
+
) {
|
|
125
90
|
if (!isPlainObject(headers)) {
|
|
126
91
|
throw Error('Headers must be provided as an object')
|
|
127
92
|
}
|
|
128
93
|
|
|
129
|
-
const lowerCaseHeaders
|
|
94
|
+
const lowerCaseHeaders = {}
|
|
130
95
|
Object.entries(headers).forEach(([fieldName, fieldValue]) => {
|
|
131
96
|
const key = fieldName.toLowerCase()
|
|
132
97
|
if (lowerCaseHeaders[key] !== undefined) {
|
|
@@ -146,21 +111,13 @@ function headersFieldNamesToLowerCase(headers, throwOnDuplicate) {
|
|
|
146
111
|
return lowerCaseHeaders
|
|
147
112
|
}
|
|
148
113
|
|
|
149
|
-
const headersFieldsArrayToLowerCase = headers => [
|
|
114
|
+
const headersFieldsArrayToLowerCase = (headers ) => [
|
|
150
115
|
...new Set(headers.map(fieldName => fieldName.toLowerCase())),
|
|
151
116
|
]
|
|
152
117
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
* Nock allows headers to be provided as a raw array, a plain object, or a Map.
|
|
157
|
-
*
|
|
158
|
-
* While all the header names are expected to be strings, the values are left intact as they can
|
|
159
|
-
* be functions, strings, or arrays of strings.
|
|
160
|
-
*
|
|
161
|
-
* https://nodejs.org/api/http.html#http_message_rawheaders
|
|
162
|
-
*/
|
|
163
|
-
function headersInputToRawArray(headers) {
|
|
118
|
+
function headersInputToRawArray(
|
|
119
|
+
headers ,
|
|
120
|
+
) {
|
|
164
121
|
if (headers === undefined) {
|
|
165
122
|
return []
|
|
166
123
|
}
|
|
@@ -178,11 +135,13 @@ function headersInputToRawArray(headers) {
|
|
|
178
135
|
|
|
179
136
|
// [].concat(...) is used instead of Array.flat until v11 is the minimum Node version
|
|
180
137
|
if (util.types.isMap(headers)) {
|
|
181
|
-
return
|
|
138
|
+
return ([] ).concat(
|
|
139
|
+
...Array.from(headers , ([k, v]) => [k.toString(), v]),
|
|
140
|
+
)
|
|
182
141
|
}
|
|
183
142
|
|
|
184
143
|
if (isPlainObject(headers)) {
|
|
185
|
-
return [].concat(...Object.entries(headers))
|
|
144
|
+
return ([] ).concat(...Object.entries(headers))
|
|
186
145
|
}
|
|
187
146
|
|
|
188
147
|
throw new Error(
|
|
@@ -190,17 +149,12 @@ function headersInputToRawArray(headers) {
|
|
|
190
149
|
)
|
|
191
150
|
}
|
|
192
151
|
|
|
193
|
-
|
|
194
|
-
* Converts an array of raw headers to an object, using the same rules as Nodes `http.IncomingMessage.headers`.
|
|
195
|
-
*
|
|
196
|
-
* Header names/keys are lower-cased.
|
|
197
|
-
*/
|
|
198
|
-
function headersArrayToObject(rawHeaders) {
|
|
152
|
+
function headersArrayToObject(rawHeaders ) {
|
|
199
153
|
if (!Array.isArray(rawHeaders)) {
|
|
200
154
|
throw Error('Expected a header array')
|
|
201
155
|
}
|
|
202
156
|
|
|
203
|
-
const accumulator
|
|
157
|
+
const accumulator = {}
|
|
204
158
|
|
|
205
159
|
forEachHeader(rawHeaders, (value, fieldName) => {
|
|
206
160
|
addHeaderLine(accumulator, fieldName, value)
|
|
@@ -229,29 +183,12 @@ const noDuplicatesHeaders = new Set([
|
|
|
229
183
|
'user-agent',
|
|
230
184
|
])
|
|
231
185
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
* https://nodejs.org/api/http.html#http_message_headers
|
|
239
|
-
* https://github.com/nodejs/node/blob/908292cf1f551c614a733d858528ffb13fb3a524/lib/_http_incoming.js#L245
|
|
240
|
-
*
|
|
241
|
-
* Header names are lower-cased.
|
|
242
|
-
* Duplicates in raw headers are handled in the following ways, depending on the header name:
|
|
243
|
-
* - Duplicates of field names listed in `noDuplicatesHeaders` (above) are discarded.
|
|
244
|
-
* - `set-cookie` is always an array. Duplicates are added to the array.
|
|
245
|
-
* - For duplicate `cookie` headers, the values are joined together with '; '.
|
|
246
|
-
* - For all other headers, the values are joined together with ', '.
|
|
247
|
-
*
|
|
248
|
-
* Node's implementation is larger because it highly optimizes for not having to call `toLowerCase()`.
|
|
249
|
-
* We've opted to always call `toLowerCase` in exchange for a more concise function.
|
|
250
|
-
*
|
|
251
|
-
* While Node has the luxury of knowing `value` is always a string, we do an extra step of coercion at the top.
|
|
252
|
-
*/
|
|
253
|
-
function addHeaderLine(headers, name, value) {
|
|
254
|
-
let values // code below expects `values` to be an array of strings
|
|
186
|
+
function addHeaderLine(
|
|
187
|
+
headers ,
|
|
188
|
+
name ,
|
|
189
|
+
value ,
|
|
190
|
+
) {
|
|
191
|
+
let values // code below expects `values` to be an array of strings
|
|
255
192
|
if (typeof value === 'function') {
|
|
256
193
|
// Function values are evaluated towards the end of the response, before that we use a placeholder
|
|
257
194
|
// string just to designate that the header exists. Useful when `Content-Type` is set with a function.
|
|
@@ -285,14 +222,10 @@ function addHeaderLine(headers, name, value) {
|
|
|
285
222
|
}
|
|
286
223
|
}
|
|
287
224
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
* @headers {Object} headers - object of header field names and values
|
|
293
|
-
* @fieldName {String} field name - string with the case-insensitive field name
|
|
294
|
-
*/
|
|
295
|
-
function deleteHeadersField(headers, fieldNameToDelete) {
|
|
225
|
+
function deleteHeadersField(
|
|
226
|
+
headers ,
|
|
227
|
+
fieldNameToDelete ,
|
|
228
|
+
) {
|
|
296
229
|
if (!isPlainObject(headers)) {
|
|
297
230
|
throw Error('headers must be an object')
|
|
298
231
|
}
|
|
@@ -309,21 +242,16 @@ function deleteHeadersField(headers, fieldNameToDelete) {
|
|
|
309
242
|
.forEach(fieldName => delete headers[fieldName])
|
|
310
243
|
}
|
|
311
244
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
* - The header value. string, array of strings, or a function
|
|
317
|
-
* - The header field name. string
|
|
318
|
-
* - Index of the header field in the raw header array.
|
|
319
|
-
*/
|
|
320
|
-
function forEachHeader(rawHeaders, callback) {
|
|
245
|
+
function forEachHeader(
|
|
246
|
+
rawHeaders ,
|
|
247
|
+
callback ,
|
|
248
|
+
) {
|
|
321
249
|
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
322
250
|
callback(rawHeaders[i + 1], rawHeaders[i], i)
|
|
323
251
|
}
|
|
324
252
|
}
|
|
325
253
|
|
|
326
|
-
function percentDecode(str) {
|
|
254
|
+
function percentDecode(str ) {
|
|
327
255
|
try {
|
|
328
256
|
return decodeURIComponent(str.replace(/\+/g, ' '))
|
|
329
257
|
} catch {
|
|
@@ -331,21 +259,16 @@ function percentDecode(str) {
|
|
|
331
259
|
}
|
|
332
260
|
}
|
|
333
261
|
|
|
334
|
-
|
|
335
|
-
* URI encode the provided string, stringently adhering to RFC 3986.
|
|
336
|
-
*
|
|
337
|
-
* RFC 3986 reserves !, ', (, ), and * but encodeURIComponent does not encode them so we do it manually.
|
|
338
|
-
*
|
|
339
|
-
* https://tools.ietf.org/html/rfc3986
|
|
340
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
|
|
341
|
-
*/
|
|
342
|
-
function percentEncode(str) {
|
|
262
|
+
function percentEncode(str ) {
|
|
343
263
|
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
|
344
264
|
return `%${c.charCodeAt(0).toString(16).toUpperCase()}`
|
|
345
265
|
})
|
|
346
266
|
}
|
|
347
267
|
|
|
348
|
-
function matchStringOrRegexp(
|
|
268
|
+
function matchStringOrRegexp(
|
|
269
|
+
target ,
|
|
270
|
+
pattern ,
|
|
271
|
+
) {
|
|
349
272
|
const targetStr =
|
|
350
273
|
target === undefined || target === null ? '' : String(target)
|
|
351
274
|
|
|
@@ -357,17 +280,11 @@ function matchStringOrRegexp(target, pattern) {
|
|
|
357
280
|
return targetStr === String(pattern)
|
|
358
281
|
}
|
|
359
282
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
* @param stringFormattingFn The function used to format string values. Can
|
|
366
|
-
* be used to encode or decode the query value.
|
|
367
|
-
*
|
|
368
|
-
* @returns *[] the formatted [key, value] pair.
|
|
369
|
-
*/
|
|
370
|
-
function formatQueryValue(key, value, stringFormattingFn) {
|
|
283
|
+
function formatQueryValue(
|
|
284
|
+
key ,
|
|
285
|
+
value ,
|
|
286
|
+
stringFormattingFn ,
|
|
287
|
+
) {
|
|
371
288
|
// TODO: Probably refactor code to replace `switch(true)` with `if`/`else`.
|
|
372
289
|
switch (true) {
|
|
373
290
|
case typeof value === 'number': // fall-through
|
|
@@ -386,13 +303,16 @@ function formatQueryValue(key, value, stringFormattingFn) {
|
|
|
386
303
|
case value instanceof RegExp:
|
|
387
304
|
break
|
|
388
305
|
case Array.isArray(value): {
|
|
389
|
-
value = value.map(function (val, idx) {
|
|
390
|
-
return formatQueryValue(idx, val, stringFormattingFn)[1]
|
|
306
|
+
value = value.map(function (val , idx ) {
|
|
307
|
+
return formatQueryValue(String(idx), val, stringFormattingFn)[1]
|
|
391
308
|
})
|
|
392
309
|
break
|
|
393
310
|
}
|
|
394
311
|
case typeof value === 'object': {
|
|
395
|
-
value = Object.entries(value).reduce(function (
|
|
312
|
+
value = Object.entries(value).reduce(function (
|
|
313
|
+
acc ,
|
|
314
|
+
[subKey, subVal],
|
|
315
|
+
) {
|
|
396
316
|
const subPair = formatQueryValue(subKey, subVal, stringFormattingFn)
|
|
397
317
|
acc[subPair[0]] = subPair[1]
|
|
398
318
|
|
|
@@ -406,7 +326,7 @@ function formatQueryValue(key, value, stringFormattingFn) {
|
|
|
406
326
|
return [key, value]
|
|
407
327
|
}
|
|
408
328
|
|
|
409
|
-
function isStream(obj) {
|
|
329
|
+
function isStream(obj ) {
|
|
410
330
|
return (
|
|
411
331
|
obj &&
|
|
412
332
|
typeof obj !== 'string' &&
|
|
@@ -415,17 +335,7 @@ function isStream(obj) {
|
|
|
415
335
|
)
|
|
416
336
|
}
|
|
417
337
|
|
|
418
|
-
|
|
419
|
-
* Determines if request data matches the expected schema.
|
|
420
|
-
*
|
|
421
|
-
* Used for comparing decoded search parameters, request body JSON objects,
|
|
422
|
-
* and URL decoded request form bodies.
|
|
423
|
-
*
|
|
424
|
-
* Performs a general recursive strict comparison with two caveats:
|
|
425
|
-
* - The expected data can use regexp to compare values
|
|
426
|
-
* - JSON path notation and nested objects are considered equal
|
|
427
|
-
*/
|
|
428
|
-
const dataEqual = (expected, actual) => {
|
|
338
|
+
const dataEqual = (expected , actual ) => {
|
|
429
339
|
if (isPlainObject(expected)) {
|
|
430
340
|
expected = expand(expected)
|
|
431
341
|
}
|
|
@@ -435,14 +345,12 @@ const dataEqual = (expected, actual) => {
|
|
|
435
345
|
return deepEqual(expected, actual)
|
|
436
346
|
}
|
|
437
347
|
|
|
438
|
-
|
|
439
|
-
* Performs a recursive strict comparison between two values.
|
|
440
|
-
*
|
|
441
|
-
* Expected values or leaf nodes of expected object values that are RegExp use test() for comparison.
|
|
442
|
-
*/
|
|
443
|
-
function deepEqual(expected, actual) {
|
|
348
|
+
function deepEqual(expected , actual ) {
|
|
444
349
|
debug('deepEqual comparing', typeof expected, expected, typeof actual, actual)
|
|
445
350
|
if (expected instanceof RegExp) {
|
|
351
|
+
if (expected.global || expected.sticky) {
|
|
352
|
+
expected.lastIndex = 0
|
|
353
|
+
}
|
|
446
354
|
return expected.test(actual)
|
|
447
355
|
}
|
|
448
356
|
|
|
@@ -469,9 +377,9 @@ const timeouts = new Set()
|
|
|
469
377
|
const immediates = new Set()
|
|
470
378
|
|
|
471
379
|
const wrapTimer =
|
|
472
|
-
(timer, ids) =>
|
|
473
|
-
(callback, ...timerArgs) => {
|
|
474
|
-
const cb = (...callbackArgs) => {
|
|
380
|
+
(timer , ids ) =>
|
|
381
|
+
(callback , ...timerArgs ) => {
|
|
382
|
+
const cb = (...callbackArgs ) => {
|
|
475
383
|
try {
|
|
476
384
|
callback(...callbackArgs)
|
|
477
385
|
} finally {
|
|
@@ -486,7 +394,7 @@ const wrapTimer =
|
|
|
486
394
|
const setTimeout = wrapTimer(timers.setTimeout, timeouts)
|
|
487
395
|
const setImmediate = wrapTimer(timers.setImmediate, immediates)
|
|
488
396
|
|
|
489
|
-
function clearTimer(clear, ids) {
|
|
397
|
+
function clearTimer(clear , ids ) {
|
|
490
398
|
ids.forEach(clear)
|
|
491
399
|
ids.clear()
|
|
492
400
|
}
|
|
@@ -497,12 +405,7 @@ function removeAllTimers() {
|
|
|
497
405
|
clearTimer(clearImmediate, immediates)
|
|
498
406
|
}
|
|
499
407
|
|
|
500
|
-
|
|
501
|
-
* Returns true if the given value is a plain object and not an Array.
|
|
502
|
-
* @param {*} value
|
|
503
|
-
* @returns {boolean}
|
|
504
|
-
*/
|
|
505
|
-
function isPlainObject(value) {
|
|
408
|
+
function isPlainObject(value ) {
|
|
506
409
|
if (typeof value !== 'object' || value === null) return false
|
|
507
410
|
|
|
508
411
|
if (Object.prototype.toString.call(value) !== '[object Object]') return false
|
|
@@ -521,27 +424,19 @@ function isPlainObject(value) {
|
|
|
521
424
|
}
|
|
522
425
|
|
|
523
426
|
const prototypePollutionBlockList = ['__proto__', 'prototype', 'constructor']
|
|
524
|
-
const blocklistFilter = function (part) {
|
|
427
|
+
const blocklistFilter = function (part ) {
|
|
525
428
|
return prototypePollutionBlockList.indexOf(part) === -1
|
|
526
429
|
}
|
|
527
430
|
|
|
528
|
-
|
|
529
|
-
* Converts flat objects whose keys use JSON path notation to nested objects.
|
|
530
|
-
*
|
|
531
|
-
* The input object is not mutated.
|
|
532
|
-
*
|
|
533
|
-
* @example
|
|
534
|
-
* { 'foo[bar][0]': 'baz' } -> { foo: { bar: [ 'baz' ] } }
|
|
535
|
-
*/
|
|
536
|
-
const expand = input => {
|
|
431
|
+
const expand = (input ) => {
|
|
537
432
|
if (input === undefined || input === null) {
|
|
538
433
|
return input
|
|
539
434
|
}
|
|
540
435
|
|
|
541
436
|
const keys = Object.keys(input)
|
|
542
437
|
|
|
543
|
-
const result
|
|
544
|
-
let resultPtr
|
|
438
|
+
const result = {}
|
|
439
|
+
let resultPtr = result
|
|
545
440
|
|
|
546
441
|
for (let path of keys) {
|
|
547
442
|
const originalPath = path
|
|
@@ -575,6 +470,8 @@ const expand = input => {
|
|
|
575
470
|
} else {
|
|
576
471
|
resultPtr[part] = {}
|
|
577
472
|
}
|
|
473
|
+
} else if (typeof resultPtr[part] !== 'object') {
|
|
474
|
+
return undefined
|
|
578
475
|
}
|
|
579
476
|
resultPtr = resultPtr[part]
|
|
580
477
|
}
|
|
@@ -583,11 +480,7 @@ const expand = input => {
|
|
|
583
480
|
return result
|
|
584
481
|
}
|
|
585
482
|
|
|
586
|
-
|
|
587
|
-
* @param {ArrayBuffer} buffer
|
|
588
|
-
* @param {string} contentEncoding
|
|
589
|
-
*/
|
|
590
|
-
function decompressRequestBody(buffer, contentEncoding) {
|
|
483
|
+
function decompressRequestBody(buffer , contentEncoding ) {
|
|
591
484
|
const encodings = contentEncoding
|
|
592
485
|
.toLowerCase()
|
|
593
486
|
.split(',')
|
|
@@ -606,18 +499,15 @@ function decompressRequestBody(buffer, contentEncoding) {
|
|
|
606
499
|
return buffer
|
|
607
500
|
}
|
|
608
501
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
*/
|
|
612
|
-
function convertHeadersToRaw(headers) {
|
|
613
|
-
const rawHeaders = []
|
|
502
|
+
function convertHeadersToRaw(headers ) {
|
|
503
|
+
const rawHeaders = []
|
|
614
504
|
for (const [name, value] of headers.entries()) {
|
|
615
505
|
rawHeaders.push(name, value)
|
|
616
506
|
}
|
|
617
507
|
return rawHeaders
|
|
618
508
|
}
|
|
619
509
|
|
|
620
|
-
|
|
510
|
+
export {
|
|
621
511
|
contentEncoding,
|
|
622
512
|
dataEqual,
|
|
623
513
|
deleteHeadersField,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DebugLoggerFunction } from 'node:util';
|
|
2
|
+
export declare const back: DebugLoggerFunction;
|
|
3
|
+
export declare const common: DebugLoggerFunction;
|
|
4
|
+
export declare const intercept: DebugLoggerFunction;
|
|
5
|
+
export declare const request_overrider: DebugLoggerFunction;
|
|
6
|
+
export declare const playback_interceptor: DebugLoggerFunction;
|
|
7
|
+
export declare const recorder: DebugLoggerFunction;
|
|
8
|
+
export declare const socket: DebugLoggerFunction;
|
|
9
|
+
export declare const scopeDebuglog: (namespace: string) => import("util").DebugLogger;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import { debuglog } from 'node:util'
|
|
3
|
+
|
|
4
|
+
export const back = debuglog('nock:back')
|
|
5
|
+
export const common = debuglog('nock:common')
|
|
6
|
+
export const intercept = debuglog('nock:intercept')
|
|
7
|
+
export const request_overrider = debuglog(
|
|
8
|
+
'nock:request_overrider',
|
|
9
|
+
)
|
|
10
|
+
export const playback_interceptor = debuglog(
|
|
11
|
+
'nock:playback_interceptor',
|
|
12
|
+
)
|
|
13
|
+
export const recorder = debuglog('nock:recorder')
|
|
14
|
+
export const socket = debuglog('nock:socket')
|
|
15
|
+
|
|
16
|
+
export const scopeDebuglog = (namespace ) =>
|
|
17
|
+
debuglog(`nock:scope:${namespace}`)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Interceptor } from './interceptor.ts';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
export interface InterceptorMatchResult {
|
|
4
|
+
interceptor: Interceptor;
|
|
5
|
+
reasons: string[];
|
|
6
|
+
}
|
|
7
|
+
type EventMap = {
|
|
8
|
+
'no match': [req: Request, interceptorResults?: InterceptorMatchResult[]];
|
|
9
|
+
};
|
|
10
|
+
declare const _default: EventEmitter<EventMap>;
|
|
11
|
+
export default _default;
|
|
@@ -1,27 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
|
|
2
|
+
import globalEmitter from './global_emitter.js'
|
|
3
|
+
import * as common from './common.js'
|
|
4
|
+
import { playbackInterceptor } from './playback_interceptor.js'
|
|
5
|
+
import { interceptorsFor, isOn, isEnabledForNetConnect } from './intercept.js'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
* @param {Request} request
|
|
9
|
-
*/
|
|
10
|
-
async function handleRequest(request) {
|
|
11
|
-
const {
|
|
12
|
-
interceptorsFor,
|
|
13
|
-
isOn,
|
|
14
|
-
isEnabledForNetConnect,
|
|
15
|
-
} = require('./intercept')
|
|
7
|
+
async function handleRequest(request ) {
|
|
16
8
|
const url = new URL(request.url)
|
|
17
9
|
const interceptors = interceptorsFor(url)
|
|
18
10
|
|
|
19
11
|
if (isOn() && interceptors) {
|
|
20
|
-
const matches = interceptors.some(interceptor =>
|
|
12
|
+
const matches = interceptors.some((interceptor ) =>
|
|
21
13
|
interceptor.matchOrigin(request),
|
|
22
14
|
)
|
|
23
15
|
const allowUnmocked = interceptors.some(
|
|
24
|
-
interceptor => interceptor.options.allowUnmocked,
|
|
16
|
+
(interceptor ) => interceptor.options.allowUnmocked,
|
|
25
17
|
)
|
|
26
18
|
if (!matches && allowUnmocked) {
|
|
27
19
|
globalEmitter.emit('no match', request)
|
|
@@ -34,8 +26,8 @@ async function handleRequest(request) {
|
|
|
34
26
|
requestBodyIsUtf8Representable ? 'utf8' : 'hex',
|
|
35
27
|
)
|
|
36
28
|
|
|
37
|
-
const matchResults
|
|
38
|
-
const matchedInterceptor = interceptors.find(i => {
|
|
29
|
+
const matchResults = []
|
|
30
|
+
const matchedInterceptor = interceptors.find((i ) => {
|
|
39
31
|
const reasons = i.match(request, requestBodyString)
|
|
40
32
|
if (reasons.length > 0) {
|
|
41
33
|
matchResults.push({ interceptor: i, reasons })
|
|
@@ -52,6 +44,10 @@ async function handleRequest(request) {
|
|
|
52
44
|
|
|
53
45
|
matchedInterceptor.markConsumed()
|
|
54
46
|
|
|
47
|
+
if (matchedInterceptor.isPassthrough) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
55
51
|
const response = await playbackInterceptor({
|
|
56
52
|
decompressedRequest: request,
|
|
57
53
|
requestBodyString,
|
|
@@ -69,7 +65,8 @@ async function handleRequest(request) {
|
|
|
69
65
|
|
|
70
66
|
// Try to find a hostname match that allows unmocked.
|
|
71
67
|
const allowUnmocked = interceptors.some(
|
|
72
|
-
i =>
|
|
68
|
+
(i ) =>
|
|
69
|
+
i.matchHostName(url.hostname) && i.options.allowUnmocked,
|
|
73
70
|
)
|
|
74
71
|
|
|
75
72
|
if (!allowUnmocked) {
|
|
@@ -96,26 +93,14 @@ async function handleRequest(request) {
|
|
|
96
93
|
}
|
|
97
94
|
}
|
|
98
95
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* @private
|
|
102
|
-
* @desc Error trying to make a connection when disabled external access.
|
|
103
|
-
* @class
|
|
104
|
-
* @example
|
|
105
|
-
* nock.disableNetConnect();
|
|
106
|
-
* http.get('http://zombo.com');
|
|
107
|
-
* // throw NetConnectNotAllowedError
|
|
108
|
-
*/
|
|
109
|
-
function NetConnectNotAllowedError(host, path) {
|
|
110
|
-
Error.call(this)
|
|
111
|
-
|
|
112
|
-
this.name = 'NetConnectNotAllowedError'
|
|
113
|
-
this.code = 'ENETUNREACH'
|
|
114
|
-
this.message = `Nock: Disallowed net connect for "${host}${path}"`
|
|
96
|
+
class NetConnectNotAllowedError extends Error {
|
|
97
|
+
|
|
115
98
|
|
|
116
|
-
|
|
99
|
+
constructor(host , path ) {
|
|
100
|
+
super(`Nock: Disallowed net connect for "${host}${path}"`)
|
|
101
|
+
this.name = 'NetConnectNotAllowedError'
|
|
102
|
+
this.code = 'ENETUNREACH'
|
|
103
|
+
}
|
|
117
104
|
}
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
module.exports = handleRequest
|
|
106
|
+
export default handleRequest
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Interceptor } from './interceptor.ts';
|
|
2
|
+
import type { Scope } from './scope.ts';
|
|
3
|
+
import * as common from './common.ts';
|
|
4
|
+
declare function enableNetConnect(matcher?: string | RegExp | ((host: string) => boolean)): void;
|
|
5
|
+
declare function isEnabledForNetConnect(url: string): boolean;
|
|
6
|
+
declare function disableNetConnect(): void;
|
|
7
|
+
declare function isOn(): boolean;
|
|
8
|
+
declare function addInterceptor(key: string, interceptor: Interceptor, scope: Scope, scopeOptions: Record<string, any>, host: string): void;
|
|
9
|
+
declare function remove(interceptor: Interceptor): void;
|
|
10
|
+
declare function removeAll(): void;
|
|
11
|
+
declare function interceptorsFor(url: URL): any;
|
|
12
|
+
declare function removeInterceptor(options: Interceptor | {
|
|
13
|
+
proto?: string;
|
|
14
|
+
host?: string;
|
|
15
|
+
method?: string;
|
|
16
|
+
path?: string;
|
|
17
|
+
}): boolean;
|
|
18
|
+
declare function isDone(): boolean;
|
|
19
|
+
declare function pendingMocks(): string[];
|
|
20
|
+
declare function activeMocks(): string[];
|
|
21
|
+
declare function activate(): void;
|
|
22
|
+
declare function deactivate(): void;
|
|
23
|
+
declare const isActiveFn: () => boolean;
|
|
24
|
+
declare const abortPendingRequests: typeof common.removeAllTimers;
|
|
25
|
+
export { addInterceptor, remove, removeAll, removeInterceptor, isOn, activate, isActiveFn as isActive, isDone, pendingMocks, activeMocks, enableNetConnect, disableNetConnect, deactivate as restoreOverriddenClientRequest, abortPendingRequests, interceptorsFor, isEnabledForNetConnect, };
|