@@ -6,7 +6,3 @@ | ||
| import * as builtinMock from './interceptors/builtin.js' | ||
| import { createRequire } from 'node:module' | ||
| const _require = createRequire(import.meta.url) | ||
| let undiciMock | ||
| let allInterceptors = {} | ||
@@ -239,21 +235,2 @@ let allowNetConnect | ||
| builtinMock.activate() | ||
| if (!undiciMock) { | ||
| try { | ||
| undiciMock = _require('./interceptors/undici.js') | ||
| } catch (err ) { | ||
| if ( | ||
| err.code !== 'MODULE_NOT_FOUND' && | ||
| err.code !== 'ERR_MODULE_NOT_FOUND' && | ||
| err.code !== 'ERR_REQUIRE_ESM' | ||
| ) { | ||
| throw err | ||
| } | ||
| debug( | ||
| 'Undici mocking is disabled because the undici module is not installed', | ||
| ) | ||
| } | ||
| } | ||
| undiciMock?.activate() | ||
| _isActive = true | ||
@@ -268,3 +245,2 @@ } else { | ||
| builtinMock.deactivate() | ||
| undiciMock?.deactivate() | ||
| _isActive = false | ||
@@ -271,0 +247,0 @@ } |
@@ -1,13 +0,11 @@ | ||
| import http from 'node:http' | ||
| import { getRawRequest, BatchInterceptor } from '@mswjs/interceptors' | ||
| import nodeInterceptors from '@mswjs/interceptors/presets/node' | ||
| import * as common from '../common.js' | ||
| import handleRequest from '../handle-request.js' | ||
| import { arrayBuffer } from 'node:stream/consumers' | ||
| import { getClientRequestBodyStream } from '@mswjs/interceptors/utils/node' | ||
| import { setGetRequestBody } from '../utils/node/index.js' | ||
| import { BatchInterceptor } from '@mswjs/interceptors' | ||
| import { FetchInterceptor } from '@mswjs/interceptors/fetch' | ||
| import { HttpRequestInterceptor } from '@mswjs/interceptors/http' | ||
| const interceptor = new BatchInterceptor({ | ||
| name: 'nock-interceptor', | ||
| interceptors: nodeInterceptors, | ||
| name: 'intercept', | ||
| interceptors: [new HttpRequestInterceptor(), new FetchInterceptor()], | ||
| }) | ||
@@ -22,34 +20,32 @@ | ||
| }) | ||
| interceptor.on('request', async function ({ request, controller } ) { | ||
| if (request.headers.get('expect') === '100-continue') { | ||
| // We currently do not support mocking 100-continue responses, so they are passed through for now. | ||
| return | ||
| } | ||
| const rawRequest = getRawRequest(request) | ||
| interceptor.on( | ||
| 'request', | ||
| async function ({ request, controller, initiator }) { | ||
| if (request.headers.get('expect') === '100-continue') { | ||
| // We currently do not support mocking 100-continue responses, so they are passed through for now. | ||
| return | ||
| } | ||
| // If this is GET request with body, we need to read the body from the socket because Fetch API doesn't support this. | ||
| const requestBodyBuffer = common.decompressRequestBody( | ||
| rawRequest instanceof http.ClientRequest && | ||
| request.method === 'GET' && | ||
| Number(request.headers.get('content-length')) > 0 | ||
| ? await arrayBuffer(getClientRequestBodyStream(request)) | ||
| : await request.clone().arrayBuffer(), | ||
| request.headers.get('content-encoding') || '', | ||
| ) | ||
| // If this is GET request with body, we need to read the body from the socket because Fetch API doesn't support this. | ||
| const requestBodyBuffer = common.decompressRequestBody( | ||
| await request.clone().arrayBuffer(), | ||
| request.headers.get('content-encoding') || '', | ||
| ) | ||
| const decompressedRequest = new Request(request, { | ||
| body: | ||
| requestBodyBuffer.byteLength > 0 && request.method !== 'GET' | ||
| ? requestBodyBuffer | ||
| : undefined, | ||
| }) | ||
| if (requestBodyBuffer.byteLength > 0 && request.method === 'GET') { | ||
| setGetRequestBody(decompressedRequest, requestBodyBuffer) | ||
| } | ||
| const decompressedRequest = new Request(request, { | ||
| body: | ||
| requestBodyBuffer.byteLength > 0 && request.method !== 'GET' | ||
| ? requestBodyBuffer | ||
| : undefined, | ||
| }) | ||
| if (requestBodyBuffer.byteLength > 0 && request.method === 'GET') { | ||
| setGetRequestBody(decompressedRequest, requestBodyBuffer) | ||
| } | ||
| const response = await handleRequest(decompressedRequest) | ||
| if (response) { | ||
| controller.respondWith(response) | ||
| } | ||
| }) | ||
| const response = await handleRequest(decompressedRequest) | ||
| if (response) { | ||
| controller.respondWith(response) | ||
| } | ||
| }, | ||
| ) | ||
| } | ||
@@ -56,0 +52,0 @@ |
+13
-40
@@ -17,4 +17,6 @@ | ||
| import { restoreOverriddenClientRequest } from './intercept.js' | ||
| import { gzipSync, brotliCompressSync, deflateSync } from 'node:zlib' | ||
| import nodeInterceptors from '@mswjs/interceptors/presets/node' | ||
| import { BatchInterceptor } from '@mswjs/interceptors' | ||
| import { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest' | ||
| import { FetchInterceptor } from '@mswjs/interceptors/fetch' | ||
| const SEPARATOR = '\n<<<<<<-- cut here -->>>>>>\n' | ||
@@ -24,5 +26,6 @@ let recordingInProgress = false | ||
| // TODO: don't reuse the nodeInterceptors, create new ones. | ||
| const clientRequestInterceptor = nodeInterceptors[0] | ||
| const fetchRequestInterceptor = nodeInterceptors[2] | ||
| const interceptor = new BatchInterceptor({ | ||
| name: 'intercept', | ||
| interceptors: [new ClientRequestInterceptor(), new FetchInterceptor()], | ||
| }) | ||
@@ -224,36 +227,7 @@ function getScope(url ) { | ||
| // We override the requests so that we can save information on them before executing. | ||
| clientRequestInterceptor.apply() | ||
| fetchRequestInterceptor.apply() | ||
| clientRequestInterceptor.on( | ||
| 'response', | ||
| async function ({ request, response } ) { | ||
| await recordResponse(request, response) | ||
| }, | ||
| ) | ||
| fetchRequestInterceptor.on( | ||
| 'response', | ||
| async function ({ request, response } ) { | ||
| // fetch decompresses the body automatically, so we need to recompress it | ||
| const codings = | ||
| response.headers | ||
| .get('content-encoding') | ||
| ?.toLowerCase() | ||
| .split(',') | ||
| .map((c ) => c.trim()) || [] | ||
| interceptor.apply() | ||
| interceptor.on('response', async function ({ request, response }) { | ||
| await recordResponse(request, response) | ||
| }) | ||
| let body = await response.arrayBuffer() | ||
| for (const coding of codings) { | ||
| if (coding === 'gzip') { | ||
| body = gzipSync(body) | ||
| } else if (coding === 'deflate') { | ||
| body = deflateSync(body) | ||
| } else if (coding === 'br') { | ||
| body = brotliCompressSync(body) | ||
| } | ||
| } | ||
| await recordResponse(request, new Response(body, response)) | ||
| }, | ||
| ) | ||
| async function recordResponse(mswRequest , mswResponse ) { | ||
@@ -325,4 +299,3 @@ const request = mswRequest.clone() | ||
| clientRequestInterceptor.dispose() | ||
| fetchRequestInterceptor.dispose() | ||
| interceptor.dispose() | ||
| restoreOverriddenClientRequest() | ||
@@ -329,0 +302,0 @@ recordingInProgress = false |
+2
-2
@@ -10,3 +10,3 @@ { | ||
| ], | ||
| "version": "15.0.0-beta.12", | ||
| "version": "15.0.0-beta.13", | ||
| "author": "Pedro Teixeira <pedro.teixeira@gmail.com>", | ||
@@ -33,3 +33,3 @@ "repository": { | ||
| "dependencies": { | ||
| "@mswjs/interceptors": "^0.41.2" | ||
| "@mswjs/interceptors": "^0.42.1" | ||
| }, | ||
@@ -36,0 +36,0 @@ "devDependencies": { |
| declare function activate(): void; | ||
| declare function deactivate(): void; | ||
| export { activate, deactivate }; |
| // This file is loaded lazily after confirming undici is installed | ||
| import undici from 'undici' | ||
| import handleRequest from '../handle-request.js' | ||
| import { URL } from 'node:url' | ||
| import { convertHeadersToRaw } from '../common.js' | ||
| class NockClient extends undici.Client { | ||
| constructor(origin , options ) { | ||
| super(origin, options) | ||
| } | ||
| dispatch(options , handler ) { | ||
| const url = new URL(options.path, options.origin) | ||
| if (options.query) { | ||
| url.search = new URLSearchParams(options.query).toString() | ||
| } | ||
| const decompressedRequest = new Request(url, { | ||
| method: options.method, | ||
| headers: options.headers, | ||
| body: options.body, | ||
| duplex: options.body ? 'half' : undefined, | ||
| }) | ||
| handleRequest(decompressedRequest) | ||
| .then(async (response ) => { | ||
| if (response) { | ||
| handler.onConnect?.((err ) => handler.onError(err), null) | ||
| handler.onHeaders?.( | ||
| response.status, | ||
| convertHeadersToRaw(response.headers), | ||
| () => {}, | ||
| response.statusText, | ||
| ) | ||
| handler.onData?.(Buffer.from(await response.arrayBuffer())) | ||
| handler.onComplete?.([]) // responseTrailers | ||
| } else { | ||
| const dispatcher = options.dispatcher || { | ||
| dispatch: super.dispatch.bind(this), | ||
| } | ||
| dispatcher.dispatch(options, handler) | ||
| } | ||
| }) | ||
| .catch((err ) => { | ||
| handler.onError?.(err) | ||
| }) | ||
| return true | ||
| } | ||
| } | ||
| class NockAgent extends undici.Dispatcher { | ||
| constructor(options ) { | ||
| super() | ||
| this.agent = new undici.Agent({ factory: this.factory.bind(this) }) | ||
| this.originalOptions = options | ||
| } | ||
| dispatch(options , handler ) { | ||
| return this.agent.dispatch(options, handler) | ||
| } | ||
| factory(origin ) { | ||
| const mockOptions = { ...this.originalOptions, agent: this } | ||
| return new NockClient(origin, mockOptions) | ||
| } | ||
| } | ||
| function activate() { | ||
| undici.setGlobalDispatcher(new NockAgent()) | ||
| } | ||
| function deactivate() { | ||
| undici.setGlobalDispatcher(new undici.Agent()) | ||
| } | ||
| export { activate, deactivate } |
Network access
Supply chain riskThis module accesses the network.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
6
-14.29%1
-50%179124
-2.25%33
-5.71%2982
-3.87%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
Updated