@whatwg-node/node-fetch 0.7.7 → 0.7.8-alpha-20250122134914-14266b4231406ede9b9179c23b41bf6e6ed0ce35

Sign up to get free protection for your applications and to get access to all the features.
package/cjs/Request.js CHANGED
@@ -117,6 +117,7 @@ class PonyfillRequest extends Body_js_1.PonyfillBody {
117
117
  }
118
118
  duplex;
119
119
  agent;
120
+ dispatcher;
120
121
  _signal;
121
122
  get signal() {
122
123
  // Create a new signal only if needed
package/cjs/fetch.js CHANGED
@@ -1,11 +1,46 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createFetchPonyfill = createFetchPonyfill;
3
37
  exports.fetchPonyfill = fetchPonyfill;
4
38
  const node_buffer_1 = require("node:buffer");
5
39
  const node_fs_1 = require("node:fs");
6
40
  const node_url_1 = require("node:url");
41
+ const types_1 = require("node:util/types");
7
42
  const fetchCurl_js_1 = require("./fetchCurl.js");
8
- const fetchNodeHttp_js_1 = require("./fetchNodeHttp.js");
43
+ const fetchUndici_js_1 = require("./fetchUndici.js");
9
44
  const Request_js_1 = require("./Request.js");
10
45
  const Response_js_1 = require("./Response.js");
11
46
  const URL_js_1 = require("./URL.js");
@@ -54,12 +89,18 @@ function getResponseForBlob(url) {
54
89
  function isURL(obj) {
55
90
  return obj != null && obj.href != null;
56
91
  }
57
- function fetchPonyfill(info, init) {
58
- if (typeof info === 'string' || isURL(info)) {
59
- const ponyfillRequest = new Request_js_1.PonyfillRequest(info, init);
60
- return fetchPonyfill(ponyfillRequest);
61
- }
62
- const fetchRequest = info;
92
+ let fetchFn$;
93
+ let fetchFn;
94
+ function getNativeGlobalDispatcher() {
95
+ // @ts-expect-error - We know it is there
96
+ return globalThis[Symbol.for('undici.globalDispatcher.1')];
97
+ }
98
+ function createFetchFn() {
99
+ const libcurlModuleName = 'node-libcurl';
100
+ const undiciModuleName = 'undici';
101
+ return Promise.resolve(`${libcurlModuleName}`).then(s => __importStar(require(s))).then(libcurl => (0, fetchCurl_js_1.createFetchCurl)(libcurl), () => Promise.resolve(`${undiciModuleName}`).then(s => __importStar(require(s))).then((undici) => (0, fetchUndici_js_1.createFetchUndici)(() => undici.getGlobalDispatcher()), () => (0, fetchUndici_js_1.createFetchUndici)(getNativeGlobalDispatcher)));
102
+ }
103
+ function fetchNonHttp(fetchRequest) {
63
104
  if (fetchRequest.url.startsWith('data:')) {
64
105
  const response = getResponseForDataUri(fetchRequest.url);
65
106
  return (0, utils_js_1.fakePromise)(response);
@@ -72,8 +113,38 @@ function fetchPonyfill(info, init) {
72
113
  const response = getResponseForBlob(fetchRequest.url);
73
114
  return (0, utils_js_1.fakePromise)(response);
74
115
  }
75
- if (globalThis.libcurl && !fetchRequest.agent) {
76
- return (0, fetchCurl_js_1.fetchCurl)(fetchRequest);
116
+ }
117
+ function normalizeInfo(info, init) {
118
+ if (typeof info === 'string' || isURL(info)) {
119
+ return new Request_js_1.PonyfillRequest(info, init);
120
+ }
121
+ return info;
122
+ }
123
+ function createFetchPonyfill(fetchFn) {
124
+ return function fetchPonyfill(info, init) {
125
+ info = normalizeInfo(info, init);
126
+ const nonHttpRes = fetchNonHttp(info);
127
+ if (nonHttpRes) {
128
+ return nonHttpRes;
129
+ }
130
+ return fetchFn(info);
131
+ };
132
+ }
133
+ function fetchPonyfill(info, init) {
134
+ info = normalizeInfo(info, init);
135
+ const nonHttpRes = fetchNonHttp(info);
136
+ if (nonHttpRes) {
137
+ return nonHttpRes;
138
+ }
139
+ if (!fetchFn) {
140
+ fetchFn$ ||= createFetchFn();
141
+ if ((0, types_1.isPromise)(fetchFn$)) {
142
+ return fetchFn$.then(newFetchFn => {
143
+ fetchFn = newFetchFn;
144
+ return fetchFn(info);
145
+ });
146
+ }
147
+ fetchFn = fetchFn$;
77
148
  }
78
- return (0, fetchNodeHttp_js_1.fetchNodeHttp)(fetchRequest);
149
+ return fetchFn(info);
79
150
  }
package/cjs/fetchCurl.js CHANGED
@@ -1,160 +1,162 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchCurl = fetchCurl;
3
+ exports.createFetchCurl = createFetchCurl;
4
4
  const node_stream_1 = require("node:stream");
5
5
  const promises_1 = require("node:stream/promises");
6
6
  const node_tls_1 = require("node:tls");
7
7
  const Response_js_1 = require("./Response.js");
8
8
  const utils_js_1 = require("./utils.js");
9
- function fetchCurl(fetchRequest) {
10
- const { Curl, CurlFeature, CurlPause, CurlProgressFunc } = globalThis['libcurl'];
11
- const curlHandle = new Curl();
12
- curlHandle.enable(CurlFeature.NoDataParsing);
13
- curlHandle.setOpt('URL', fetchRequest.url);
14
- if (process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
15
- curlHandle.setOpt('SSL_VERIFYPEER', false);
16
- }
17
- if (process.env.NODE_EXTRA_CA_CERTS) {
18
- curlHandle.setOpt('CAINFO', process.env.NODE_EXTRA_CA_CERTS);
19
- }
20
- else {
21
- curlHandle.setOpt('CAINFO_BLOB', node_tls_1.rootCertificates.join('\n'));
22
- }
23
- curlHandle.enable(CurlFeature.StreamResponse);
24
- curlHandle.setStreamProgressCallback(function () {
25
- return fetchRequest['_signal']?.aborted
26
- ? process.env.DEBUG
27
- ? CurlProgressFunc.Continue
28
- : 1
29
- : 0;
30
- });
31
- if (fetchRequest['bodyType'] === 'String') {
32
- curlHandle.setOpt('POSTFIELDS', fetchRequest['bodyInit']);
33
- }
34
- else {
35
- const nodeReadable = (fetchRequest.body != null
36
- ? (0, utils_js_1.isNodeReadable)(fetchRequest.body)
37
- ? fetchRequest.body
38
- : node_stream_1.Readable.from(fetchRequest.body)
39
- : null);
40
- if (nodeReadable) {
41
- curlHandle.setOpt('UPLOAD', true);
42
- curlHandle.setUploadStream(nodeReadable);
9
+ function createFetchCurl(nodeLibcurl) {
10
+ return function fetchCurl(fetchRequest) {
11
+ const { Curl, CurlFeature, CurlPause, CurlProgressFunc } = nodeLibcurl;
12
+ const curlHandle = new Curl();
13
+ curlHandle.enable(CurlFeature.NoDataParsing);
14
+ curlHandle.setOpt('URL', fetchRequest.url);
15
+ if (process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
16
+ curlHandle.setOpt('SSL_VERIFYPEER', false);
43
17
  }
44
- }
45
- if (process.env.DEBUG) {
46
- curlHandle.setOpt('VERBOSE', true);
47
- }
48
- curlHandle.setOpt('TRANSFER_ENCODING', false);
49
- curlHandle.setOpt('HTTP_TRANSFER_DECODING', true);
50
- curlHandle.setOpt('FOLLOWLOCATION', fetchRequest.redirect === 'follow');
51
- curlHandle.setOpt('MAXREDIRS', 20);
52
- curlHandle.setOpt('ACCEPT_ENCODING', '');
53
- curlHandle.setOpt('CUSTOMREQUEST', fetchRequest.method);
54
- const headersSerializer = fetchRequest.headersSerializer || utils_js_1.defaultHeadersSerializer;
55
- let size;
56
- const curlHeaders = headersSerializer(fetchRequest.headers, value => {
57
- size = Number(value);
58
- });
59
- if (size != null) {
60
- curlHandle.setOpt('INFILESIZE', size);
61
- }
62
- curlHandle.setOpt('HTTPHEADER', curlHeaders);
63
- curlHandle.enable(CurlFeature.NoHeaderParsing);
64
- const deferredPromise = (0, utils_js_1.createDeferredPromise)();
65
- let streamResolved;
66
- function onAbort() {
67
- if (curlHandle.isOpen) {
68
- try {
69
- curlHandle.pause(CurlPause.Recv);
70
- }
71
- catch (e) {
72
- deferredPromise.reject(e);
73
- }
18
+ if (process.env.NODE_EXTRA_CA_CERTS) {
19
+ curlHandle.setOpt('CAINFO', process.env.NODE_EXTRA_CA_CERTS);
74
20
  }
75
- }
76
- if (fetchRequest['_signal']) {
77
- fetchRequest['_signal'].addEventListener('abort', onAbort, { once: true });
78
- }
79
- curlHandle.once('end', function endListener() {
80
- try {
81
- curlHandle.close();
82
- }
83
- catch (e) {
84
- deferredPromise.reject(e);
85
- }
86
- if (fetchRequest['_signal']) {
87
- fetchRequest['_signal'].removeEventListener('abort', onAbort);
21
+ else {
22
+ curlHandle.setOpt('CAINFO_BLOB', node_tls_1.rootCertificates.join('\n'));
88
23
  }
89
- });
90
- curlHandle.once('error', function errorListener(error) {
91
- if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
92
- streamResolved.destroy(error);
24
+ curlHandle.enable(CurlFeature.StreamResponse);
25
+ curlHandle.setStreamProgressCallback(function () {
26
+ return fetchRequest['_signal']?.aborted
27
+ ? process.env.DEBUG
28
+ ? CurlProgressFunc.Continue
29
+ : 1
30
+ : 0;
31
+ });
32
+ if (fetchRequest['bodyType'] === 'String') {
33
+ curlHandle.setOpt('POSTFIELDS', fetchRequest['bodyInit']);
93
34
  }
94
35
  else {
95
- if (error.message === 'Operation was aborted by an application callback') {
96
- error.message = 'The operation was aborted.';
36
+ const nodeReadable = (fetchRequest.body != null
37
+ ? (0, utils_js_1.isNodeReadable)(fetchRequest.body)
38
+ ? fetchRequest.body
39
+ : node_stream_1.Readable.from(fetchRequest.body)
40
+ : null);
41
+ if (nodeReadable) {
42
+ curlHandle.setOpt('UPLOAD', true);
43
+ curlHandle.setUploadStream(nodeReadable);
97
44
  }
98
- deferredPromise.reject(error);
99
45
  }
100
- try {
101
- curlHandle.close();
46
+ if (process.env.DEBUG) {
47
+ curlHandle.setOpt('VERBOSE', true);
102
48
  }
103
- catch (e) {
104
- deferredPromise.reject(e);
49
+ curlHandle.setOpt('TRANSFER_ENCODING', false);
50
+ curlHandle.setOpt('HTTP_TRANSFER_DECODING', true);
51
+ curlHandle.setOpt('FOLLOWLOCATION', fetchRequest.redirect === 'follow');
52
+ curlHandle.setOpt('MAXREDIRS', 20);
53
+ curlHandle.setOpt('ACCEPT_ENCODING', '');
54
+ curlHandle.setOpt('CUSTOMREQUEST', fetchRequest.method);
55
+ const headersSerializer = fetchRequest.headersSerializer || utils_js_1.defaultHeadersSerializer;
56
+ let size;
57
+ const curlHeaders = headersSerializer(fetchRequest.headers, value => {
58
+ size = Number(value);
59
+ });
60
+ if (size != null) {
61
+ curlHandle.setOpt('INFILESIZE', size);
105
62
  }
106
- });
107
- curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
108
- const outputStream = new node_stream_1.PassThrough();
109
- (0, promises_1.pipeline)(stream, outputStream, {
110
- end: true,
111
- signal: fetchRequest['_signal'] ?? undefined,
112
- })
113
- .then(() => {
114
- if (!stream.destroyed) {
115
- stream.resume();
63
+ curlHandle.setOpt('HTTPHEADER', curlHeaders);
64
+ curlHandle.enable(CurlFeature.NoHeaderParsing);
65
+ const deferredPromise = (0, utils_js_1.createDeferredPromise)();
66
+ let streamResolved;
67
+ function onAbort() {
68
+ if (curlHandle.isOpen) {
69
+ try {
70
+ curlHandle.pause(CurlPause.Recv);
71
+ }
72
+ catch (e) {
73
+ deferredPromise.reject(e);
74
+ }
116
75
  }
117
- })
118
- .catch(deferredPromise.reject);
119
- const headersFlat = headersBuf
120
- .toString('utf8')
121
- .split(/\r?\n|\r/g)
122
- .filter(headerFilter => {
123
- if (headerFilter && !headerFilter.startsWith('HTTP/')) {
124
- if (fetchRequest.redirect === 'error' &&
125
- (headerFilter.includes('location') || headerFilter.includes('Location'))) {
126
- if (!stream.destroyed) {
127
- stream.resume();
128
- }
129
- outputStream.destroy();
130
- deferredPromise.reject(new Error('redirect is not allowed'));
76
+ }
77
+ if (fetchRequest['_signal']) {
78
+ fetchRequest['_signal'].addEventListener('abort', onAbort, { once: true });
79
+ }
80
+ curlHandle.once('end', function endListener() {
81
+ try {
82
+ curlHandle.close();
83
+ }
84
+ catch (e) {
85
+ deferredPromise.reject(e);
86
+ }
87
+ if (fetchRequest['_signal']) {
88
+ fetchRequest['_signal'].removeEventListener('abort', onAbort);
89
+ }
90
+ });
91
+ curlHandle.once('error', function errorListener(error) {
92
+ if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
93
+ streamResolved.destroy(error);
94
+ }
95
+ else {
96
+ if (error.message === 'Operation was aborted by an application callback') {
97
+ error.message = 'The operation was aborted.';
131
98
  }
132
- return true;
99
+ deferredPromise.reject(error);
100
+ }
101
+ try {
102
+ curlHandle.close();
103
+ }
104
+ catch (e) {
105
+ deferredPromise.reject(e);
133
106
  }
134
- return false;
135
107
  });
136
- const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
137
- const ponyfillResponse = new Response_js_1.PonyfillResponse(outputStream, {
138
- status,
139
- headers: headersInit,
140
- url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
141
- redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
108
+ curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
109
+ const outputStream = new node_stream_1.PassThrough();
110
+ (0, promises_1.pipeline)(stream, outputStream, {
111
+ end: true,
112
+ signal: fetchRequest['_signal'] ?? undefined,
113
+ })
114
+ .then(() => {
115
+ if (!stream.destroyed) {
116
+ stream.resume();
117
+ }
118
+ })
119
+ .catch(deferredPromise.reject);
120
+ const headersFlat = headersBuf
121
+ .toString('utf8')
122
+ .split(/\r?\n|\r/g)
123
+ .filter(headerFilter => {
124
+ if (headerFilter && !headerFilter.startsWith('HTTP/')) {
125
+ if (fetchRequest.redirect === 'error' &&
126
+ (headerFilter.includes('location') || headerFilter.includes('Location'))) {
127
+ if (!stream.destroyed) {
128
+ stream.resume();
129
+ }
130
+ outputStream.destroy();
131
+ deferredPromise.reject(new Error('redirect is not allowed'));
132
+ }
133
+ return true;
134
+ }
135
+ return false;
136
+ });
137
+ const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
138
+ const ponyfillResponse = new Response_js_1.PonyfillResponse(outputStream, {
139
+ status,
140
+ headers: headersInit,
141
+ url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
142
+ redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
143
+ });
144
+ deferredPromise.resolve(ponyfillResponse);
145
+ streamResolved = outputStream;
142
146
  });
143
- deferredPromise.resolve(ponyfillResponse);
144
- streamResolved = outputStream;
145
- });
146
- let count = 0;
147
- try {
148
- count = Curl.getCount();
149
- }
150
- catch { }
151
- if (count > 0) {
152
- setImmediate(() => {
147
+ let count = 0;
148
+ try {
149
+ count = Curl.getCount();
150
+ }
151
+ catch { }
152
+ if (count > 0) {
153
+ setImmediate(() => {
154
+ curlHandle.perform();
155
+ });
156
+ }
157
+ else {
153
158
  curlHandle.perform();
154
- });
155
- }
156
- else {
157
- curlHandle.perform();
158
- }
159
- return deferredPromise.promise;
159
+ }
160
+ return deferredPromise.promise;
161
+ };
160
162
  }
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFetchUndici = createFetchUndici;
4
+ const stream_1 = require("stream");
5
+ const types_1 = require("util/types");
6
+ const zlib_1 = require("zlib");
7
+ const fetchNodeHttp_js_1 = require("./fetchNodeHttp.js");
8
+ const Request_js_1 = require("./Request.js");
9
+ const Response_js_1 = require("./Response.js");
10
+ const URL_js_1 = require("./URL.js");
11
+ const utils_js_1 = require("./utils.js");
12
+ function createFetchUndici(getGlobalDispatcher) {
13
+ return function fetchUndici(fetchRequest) {
14
+ const dispatcher = fetchRequest.dispatcher || getGlobalDispatcher();
15
+ if (!dispatcher) {
16
+ return (0, fetchNodeHttp_js_1.fetchNodeHttp)(fetchRequest);
17
+ }
18
+ return new Promise((resolve, reject) => {
19
+ let abortListener;
20
+ let passthrough;
21
+ let response;
22
+ let body = null;
23
+ const bodyInit = fetchRequest['bodyInit'];
24
+ if (bodyInit != null) {
25
+ if (typeof bodyInit === 'string' ||
26
+ Buffer.isBuffer(bodyInit) ||
27
+ (0, types_1.isUint8Array)(bodyInit) ||
28
+ bodyInit instanceof stream_1.Readable) {
29
+ body = bodyInit;
30
+ }
31
+ else if (fetchRequest.body != null) {
32
+ if ((0, utils_js_1.isNodeReadable)(fetchRequest.body?.readable)) {
33
+ body = fetchRequest.body.readable;
34
+ }
35
+ else {
36
+ body = stream_1.Readable.from(fetchRequest.body);
37
+ }
38
+ }
39
+ }
40
+ function setPassthrough(contentEncoding) {
41
+ switch (contentEncoding) {
42
+ case 'x-gzip':
43
+ case 'gzip':
44
+ passthrough = (0, zlib_1.createGunzip)();
45
+ break;
46
+ case 'x-deflate':
47
+ case 'deflate':
48
+ passthrough = (0, zlib_1.createInflate)();
49
+ break;
50
+ case 'x-deflate-raw':
51
+ case 'deflate-raw':
52
+ passthrough = (0, zlib_1.createInflateRaw)();
53
+ break;
54
+ case 'br':
55
+ passthrough = (0, zlib_1.createBrotliDecompress)();
56
+ break;
57
+ default:
58
+ passthrough = new stream_1.PassThrough();
59
+ }
60
+ return passthrough;
61
+ }
62
+ const headersSerializer = fetchRequest.headersSerializer || utils_js_1.getHeadersObj;
63
+ const nodeHeaders = headersSerializer(fetchRequest.headers);
64
+ if (nodeHeaders['accept-encoding'] == null) {
65
+ nodeHeaders['accept-encoding'] = 'gzip, deflate, br';
66
+ }
67
+ (fetchRequest.dispatcher || getGlobalDispatcher()).dispatch({
68
+ origin: fetchRequest.parsedUrl.origin,
69
+ path: fetchRequest.parsedUrl.pathname,
70
+ query: Object.fromEntries(fetchRequest.parsedUrl.searchParams),
71
+ method: fetchRequest.method,
72
+ headers: nodeHeaders,
73
+ body,
74
+ }, {
75
+ onRequestStart(controller) {
76
+ abortListener = function abortListener() {
77
+ controller.abort(fetchRequest['_signal']?.reason);
78
+ };
79
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
80
+ },
81
+ onRequestUpgrade(_controller, statusCode, headers, socket) {
82
+ response = new Response_js_1.PonyfillResponse(socket, {
83
+ status: statusCode,
84
+ headers: headers,
85
+ url: fetchRequest.url,
86
+ });
87
+ resolve(response);
88
+ },
89
+ onResponseStart(controller, statusCode, headers, statusMessage) {
90
+ if (headers.location) {
91
+ if (fetchRequest.redirect === 'error') {
92
+ const redirectError = new Error('Redirects are not allowed');
93
+ reject(redirectError);
94
+ controller.resume();
95
+ return;
96
+ }
97
+ if (fetchRequest.redirect === 'follow') {
98
+ const redirectedUrl = new URL_js_1.PonyfillURL(headers.location, fetchRequest.parsedUrl || fetchRequest.url);
99
+ const redirectResponse$ = fetchUndici(new Request_js_1.PonyfillRequest(redirectedUrl, fetchRequest));
100
+ resolve(redirectResponse$.then(redirectResponse => {
101
+ redirectResponse.redirected = true;
102
+ return redirectResponse;
103
+ }));
104
+ controller.resume();
105
+ return;
106
+ }
107
+ }
108
+ passthrough = setPassthrough(headers['content-encoding']);
109
+ resolve(new Response_js_1.PonyfillResponse(passthrough, {
110
+ status: statusCode,
111
+ statusText: statusMessage,
112
+ headers: headers,
113
+ url: fetchRequest.url,
114
+ }));
115
+ },
116
+ onResponseData(_controller, chunk) {
117
+ passthrough.write(chunk);
118
+ },
119
+ onResponseEnd(_controller, _trailers) {
120
+ passthrough.end();
121
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
122
+ },
123
+ onResponseError(_controller, error) {
124
+ if (passthrough) {
125
+ passthrough.destroy(error);
126
+ }
127
+ else {
128
+ reject(error);
129
+ }
130
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
131
+ },
132
+ // Old Undici support
133
+ onConnect(abort) {
134
+ abortListener = function abortListener() {
135
+ abort(fetchRequest['_signal']?.reason);
136
+ };
137
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
138
+ },
139
+ onError(error) {
140
+ if (passthrough) {
141
+ passthrough.destroy(error);
142
+ }
143
+ else {
144
+ reject(error);
145
+ }
146
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
147
+ },
148
+ // TODO: onUpgrade
149
+ onHeaders(statusCode, headersBuf, _resume, statusText) {
150
+ const headers = headersBuf.map(headerBuf => {
151
+ const header = headerBuf
152
+ .toString('utf-8')
153
+ .split(/:\s(.+)/)
154
+ .slice(0, 2);
155
+ if (header[0] === 'content-encoding') {
156
+ const contentEncoding = header[1];
157
+ setPassthrough(contentEncoding);
158
+ }
159
+ return header;
160
+ });
161
+ passthrough ||= new stream_1.PassThrough();
162
+ resolve(new Response_js_1.PonyfillResponse(passthrough, {
163
+ status: statusCode,
164
+ statusText,
165
+ headers,
166
+ url: fetchRequest.url,
167
+ }));
168
+ return true;
169
+ },
170
+ onData(chunk) {
171
+ return passthrough.write(chunk);
172
+ },
173
+ onComplete() {
174
+ passthrough.end();
175
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
176
+ },
177
+ });
178
+ });
179
+ };
180
+ }
package/esm/Request.js CHANGED
@@ -114,6 +114,7 @@ export class PonyfillRequest extends PonyfillBody {
114
114
  }
115
115
  duplex;
116
116
  agent;
117
+ dispatcher;
117
118
  _signal;
118
119
  get signal() {
119
120
  // Create a new signal only if needed
package/esm/fetch.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Buffer } from 'node:buffer';
2
2
  import { createReadStream } from 'node:fs';
3
3
  import { fileURLToPath } from 'node:url';
4
- import { fetchCurl } from './fetchCurl.js';
5
- import { fetchNodeHttp } from './fetchNodeHttp.js';
4
+ import { isPromise } from 'node:util/types';
5
+ import { createFetchCurl } from './fetchCurl.js';
6
+ import { createFetchUndici } from './fetchUndici.js';
6
7
  import { PonyfillRequest } from './Request.js';
7
8
  import { PonyfillResponse } from './Response.js';
8
9
  import { PonyfillURL } from './URL.js';
@@ -51,12 +52,18 @@ function getResponseForBlob(url) {
51
52
  function isURL(obj) {
52
53
  return obj != null && obj.href != null;
53
54
  }
54
- export function fetchPonyfill(info, init) {
55
- if (typeof info === 'string' || isURL(info)) {
56
- const ponyfillRequest = new PonyfillRequest(info, init);
57
- return fetchPonyfill(ponyfillRequest);
58
- }
59
- const fetchRequest = info;
55
+ let fetchFn$;
56
+ let fetchFn;
57
+ function getNativeGlobalDispatcher() {
58
+ // @ts-expect-error - We know it is there
59
+ return globalThis[Symbol.for('undici.globalDispatcher.1')];
60
+ }
61
+ function createFetchFn() {
62
+ const libcurlModuleName = 'node-libcurl';
63
+ const undiciModuleName = 'undici';
64
+ return import(libcurlModuleName).then(libcurl => createFetchCurl(libcurl), () => import(undiciModuleName).then((undici) => createFetchUndici(() => undici.getGlobalDispatcher()), () => createFetchUndici(getNativeGlobalDispatcher)));
65
+ }
66
+ function fetchNonHttp(fetchRequest) {
60
67
  if (fetchRequest.url.startsWith('data:')) {
61
68
  const response = getResponseForDataUri(fetchRequest.url);
62
69
  return fakePromise(response);
@@ -69,8 +76,38 @@ export function fetchPonyfill(info, init) {
69
76
  const response = getResponseForBlob(fetchRequest.url);
70
77
  return fakePromise(response);
71
78
  }
72
- if (globalThis.libcurl && !fetchRequest.agent) {
73
- return fetchCurl(fetchRequest);
79
+ }
80
+ function normalizeInfo(info, init) {
81
+ if (typeof info === 'string' || isURL(info)) {
82
+ return new PonyfillRequest(info, init);
83
+ }
84
+ return info;
85
+ }
86
+ export function createFetchPonyfill(fetchFn) {
87
+ return function fetchPonyfill(info, init) {
88
+ info = normalizeInfo(info, init);
89
+ const nonHttpRes = fetchNonHttp(info);
90
+ if (nonHttpRes) {
91
+ return nonHttpRes;
92
+ }
93
+ return fetchFn(info);
94
+ };
95
+ }
96
+ export function fetchPonyfill(info, init) {
97
+ info = normalizeInfo(info, init);
98
+ const nonHttpRes = fetchNonHttp(info);
99
+ if (nonHttpRes) {
100
+ return nonHttpRes;
101
+ }
102
+ if (!fetchFn) {
103
+ fetchFn$ ||= createFetchFn();
104
+ if (isPromise(fetchFn$)) {
105
+ return fetchFn$.then(newFetchFn => {
106
+ fetchFn = newFetchFn;
107
+ return fetchFn(info);
108
+ });
109
+ }
110
+ fetchFn = fetchFn$;
74
111
  }
75
- return fetchNodeHttp(fetchRequest);
112
+ return fetchFn(info);
76
113
  }
package/esm/fetchCurl.js CHANGED
@@ -3,155 +3,157 @@ import { pipeline } from 'node:stream/promises';
3
3
  import { rootCertificates } from 'node:tls';
4
4
  import { PonyfillResponse } from './Response.js';
5
5
  import { createDeferredPromise, defaultHeadersSerializer, isNodeReadable } from './utils.js';
6
- export function fetchCurl(fetchRequest) {
7
- const { Curl, CurlFeature, CurlPause, CurlProgressFunc } = globalThis['libcurl'];
8
- const curlHandle = new Curl();
9
- curlHandle.enable(CurlFeature.NoDataParsing);
10
- curlHandle.setOpt('URL', fetchRequest.url);
11
- if (process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
12
- curlHandle.setOpt('SSL_VERIFYPEER', false);
13
- }
14
- if (process.env.NODE_EXTRA_CA_CERTS) {
15
- curlHandle.setOpt('CAINFO', process.env.NODE_EXTRA_CA_CERTS);
16
- }
17
- else {
18
- curlHandle.setOpt('CAINFO_BLOB', rootCertificates.join('\n'));
19
- }
20
- curlHandle.enable(CurlFeature.StreamResponse);
21
- curlHandle.setStreamProgressCallback(function () {
22
- return fetchRequest['_signal']?.aborted
23
- ? process.env.DEBUG
24
- ? CurlProgressFunc.Continue
25
- : 1
26
- : 0;
27
- });
28
- if (fetchRequest['bodyType'] === 'String') {
29
- curlHandle.setOpt('POSTFIELDS', fetchRequest['bodyInit']);
30
- }
31
- else {
32
- const nodeReadable = (fetchRequest.body != null
33
- ? isNodeReadable(fetchRequest.body)
34
- ? fetchRequest.body
35
- : Readable.from(fetchRequest.body)
36
- : null);
37
- if (nodeReadable) {
38
- curlHandle.setOpt('UPLOAD', true);
39
- curlHandle.setUploadStream(nodeReadable);
6
+ export function createFetchCurl(nodeLibcurl) {
7
+ return function fetchCurl(fetchRequest) {
8
+ const { Curl, CurlFeature, CurlPause, CurlProgressFunc } = nodeLibcurl;
9
+ const curlHandle = new Curl();
10
+ curlHandle.enable(CurlFeature.NoDataParsing);
11
+ curlHandle.setOpt('URL', fetchRequest.url);
12
+ if (process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
13
+ curlHandle.setOpt('SSL_VERIFYPEER', false);
40
14
  }
41
- }
42
- if (process.env.DEBUG) {
43
- curlHandle.setOpt('VERBOSE', true);
44
- }
45
- curlHandle.setOpt('TRANSFER_ENCODING', false);
46
- curlHandle.setOpt('HTTP_TRANSFER_DECODING', true);
47
- curlHandle.setOpt('FOLLOWLOCATION', fetchRequest.redirect === 'follow');
48
- curlHandle.setOpt('MAXREDIRS', 20);
49
- curlHandle.setOpt('ACCEPT_ENCODING', '');
50
- curlHandle.setOpt('CUSTOMREQUEST', fetchRequest.method);
51
- const headersSerializer = fetchRequest.headersSerializer || defaultHeadersSerializer;
52
- let size;
53
- const curlHeaders = headersSerializer(fetchRequest.headers, value => {
54
- size = Number(value);
55
- });
56
- if (size != null) {
57
- curlHandle.setOpt('INFILESIZE', size);
58
- }
59
- curlHandle.setOpt('HTTPHEADER', curlHeaders);
60
- curlHandle.enable(CurlFeature.NoHeaderParsing);
61
- const deferredPromise = createDeferredPromise();
62
- let streamResolved;
63
- function onAbort() {
64
- if (curlHandle.isOpen) {
65
- try {
66
- curlHandle.pause(CurlPause.Recv);
67
- }
68
- catch (e) {
69
- deferredPromise.reject(e);
70
- }
15
+ if (process.env.NODE_EXTRA_CA_CERTS) {
16
+ curlHandle.setOpt('CAINFO', process.env.NODE_EXTRA_CA_CERTS);
71
17
  }
72
- }
73
- if (fetchRequest['_signal']) {
74
- fetchRequest['_signal'].addEventListener('abort', onAbort, { once: true });
75
- }
76
- curlHandle.once('end', function endListener() {
77
- try {
78
- curlHandle.close();
79
- }
80
- catch (e) {
81
- deferredPromise.reject(e);
82
- }
83
- if (fetchRequest['_signal']) {
84
- fetchRequest['_signal'].removeEventListener('abort', onAbort);
18
+ else {
19
+ curlHandle.setOpt('CAINFO_BLOB', rootCertificates.join('\n'));
85
20
  }
86
- });
87
- curlHandle.once('error', function errorListener(error) {
88
- if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
89
- streamResolved.destroy(error);
21
+ curlHandle.enable(CurlFeature.StreamResponse);
22
+ curlHandle.setStreamProgressCallback(function () {
23
+ return fetchRequest['_signal']?.aborted
24
+ ? process.env.DEBUG
25
+ ? CurlProgressFunc.Continue
26
+ : 1
27
+ : 0;
28
+ });
29
+ if (fetchRequest['bodyType'] === 'String') {
30
+ curlHandle.setOpt('POSTFIELDS', fetchRequest['bodyInit']);
90
31
  }
91
32
  else {
92
- if (error.message === 'Operation was aborted by an application callback') {
93
- error.message = 'The operation was aborted.';
33
+ const nodeReadable = (fetchRequest.body != null
34
+ ? isNodeReadable(fetchRequest.body)
35
+ ? fetchRequest.body
36
+ : Readable.from(fetchRequest.body)
37
+ : null);
38
+ if (nodeReadable) {
39
+ curlHandle.setOpt('UPLOAD', true);
40
+ curlHandle.setUploadStream(nodeReadable);
94
41
  }
95
- deferredPromise.reject(error);
96
42
  }
97
- try {
98
- curlHandle.close();
43
+ if (process.env.DEBUG) {
44
+ curlHandle.setOpt('VERBOSE', true);
99
45
  }
100
- catch (e) {
101
- deferredPromise.reject(e);
46
+ curlHandle.setOpt('TRANSFER_ENCODING', false);
47
+ curlHandle.setOpt('HTTP_TRANSFER_DECODING', true);
48
+ curlHandle.setOpt('FOLLOWLOCATION', fetchRequest.redirect === 'follow');
49
+ curlHandle.setOpt('MAXREDIRS', 20);
50
+ curlHandle.setOpt('ACCEPT_ENCODING', '');
51
+ curlHandle.setOpt('CUSTOMREQUEST', fetchRequest.method);
52
+ const headersSerializer = fetchRequest.headersSerializer || defaultHeadersSerializer;
53
+ let size;
54
+ const curlHeaders = headersSerializer(fetchRequest.headers, value => {
55
+ size = Number(value);
56
+ });
57
+ if (size != null) {
58
+ curlHandle.setOpt('INFILESIZE', size);
102
59
  }
103
- });
104
- curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
105
- const outputStream = new PassThrough();
106
- pipeline(stream, outputStream, {
107
- end: true,
108
- signal: fetchRequest['_signal'] ?? undefined,
109
- })
110
- .then(() => {
111
- if (!stream.destroyed) {
112
- stream.resume();
60
+ curlHandle.setOpt('HTTPHEADER', curlHeaders);
61
+ curlHandle.enable(CurlFeature.NoHeaderParsing);
62
+ const deferredPromise = createDeferredPromise();
63
+ let streamResolved;
64
+ function onAbort() {
65
+ if (curlHandle.isOpen) {
66
+ try {
67
+ curlHandle.pause(CurlPause.Recv);
68
+ }
69
+ catch (e) {
70
+ deferredPromise.reject(e);
71
+ }
113
72
  }
114
- })
115
- .catch(deferredPromise.reject);
116
- const headersFlat = headersBuf
117
- .toString('utf8')
118
- .split(/\r?\n|\r/g)
119
- .filter(headerFilter => {
120
- if (headerFilter && !headerFilter.startsWith('HTTP/')) {
121
- if (fetchRequest.redirect === 'error' &&
122
- (headerFilter.includes('location') || headerFilter.includes('Location'))) {
123
- if (!stream.destroyed) {
124
- stream.resume();
125
- }
126
- outputStream.destroy();
127
- deferredPromise.reject(new Error('redirect is not allowed'));
73
+ }
74
+ if (fetchRequest['_signal']) {
75
+ fetchRequest['_signal'].addEventListener('abort', onAbort, { once: true });
76
+ }
77
+ curlHandle.once('end', function endListener() {
78
+ try {
79
+ curlHandle.close();
80
+ }
81
+ catch (e) {
82
+ deferredPromise.reject(e);
83
+ }
84
+ if (fetchRequest['_signal']) {
85
+ fetchRequest['_signal'].removeEventListener('abort', onAbort);
86
+ }
87
+ });
88
+ curlHandle.once('error', function errorListener(error) {
89
+ if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
90
+ streamResolved.destroy(error);
91
+ }
92
+ else {
93
+ if (error.message === 'Operation was aborted by an application callback') {
94
+ error.message = 'The operation was aborted.';
128
95
  }
129
- return true;
96
+ deferredPromise.reject(error);
97
+ }
98
+ try {
99
+ curlHandle.close();
100
+ }
101
+ catch (e) {
102
+ deferredPromise.reject(e);
130
103
  }
131
- return false;
132
104
  });
133
- const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
134
- const ponyfillResponse = new PonyfillResponse(outputStream, {
135
- status,
136
- headers: headersInit,
137
- url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
138
- redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
105
+ curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
106
+ const outputStream = new PassThrough();
107
+ pipeline(stream, outputStream, {
108
+ end: true,
109
+ signal: fetchRequest['_signal'] ?? undefined,
110
+ })
111
+ .then(() => {
112
+ if (!stream.destroyed) {
113
+ stream.resume();
114
+ }
115
+ })
116
+ .catch(deferredPromise.reject);
117
+ const headersFlat = headersBuf
118
+ .toString('utf8')
119
+ .split(/\r?\n|\r/g)
120
+ .filter(headerFilter => {
121
+ if (headerFilter && !headerFilter.startsWith('HTTP/')) {
122
+ if (fetchRequest.redirect === 'error' &&
123
+ (headerFilter.includes('location') || headerFilter.includes('Location'))) {
124
+ if (!stream.destroyed) {
125
+ stream.resume();
126
+ }
127
+ outputStream.destroy();
128
+ deferredPromise.reject(new Error('redirect is not allowed'));
129
+ }
130
+ return true;
131
+ }
132
+ return false;
133
+ });
134
+ const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
135
+ const ponyfillResponse = new PonyfillResponse(outputStream, {
136
+ status,
137
+ headers: headersInit,
138
+ url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
139
+ redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
140
+ });
141
+ deferredPromise.resolve(ponyfillResponse);
142
+ streamResolved = outputStream;
139
143
  });
140
- deferredPromise.resolve(ponyfillResponse);
141
- streamResolved = outputStream;
142
- });
143
- let count = 0;
144
- try {
145
- count = Curl.getCount();
146
- }
147
- catch { }
148
- if (count > 0) {
149
- setImmediate(() => {
144
+ let count = 0;
145
+ try {
146
+ count = Curl.getCount();
147
+ }
148
+ catch { }
149
+ if (count > 0) {
150
+ setImmediate(() => {
151
+ curlHandle.perform();
152
+ });
153
+ }
154
+ else {
150
155
  curlHandle.perform();
151
- });
152
- }
153
- else {
154
- curlHandle.perform();
155
- }
156
- return deferredPromise.promise;
156
+ }
157
+ return deferredPromise.promise;
158
+ };
157
159
  }
@@ -0,0 +1,177 @@
1
+ import { PassThrough, Readable } from 'stream';
2
+ import { isUint8Array } from 'util/types';
3
+ import { createBrotliDecompress, createGunzip, createInflate, createInflateRaw } from 'zlib';
4
+ import { fetchNodeHttp } from './fetchNodeHttp.js';
5
+ import { PonyfillRequest } from './Request.js';
6
+ import { PonyfillResponse } from './Response.js';
7
+ import { PonyfillURL } from './URL.js';
8
+ import { getHeadersObj, isNodeReadable } from './utils.js';
9
+ export function createFetchUndici(getGlobalDispatcher) {
10
+ return function fetchUndici(fetchRequest) {
11
+ const dispatcher = fetchRequest.dispatcher || getGlobalDispatcher();
12
+ if (!dispatcher) {
13
+ return fetchNodeHttp(fetchRequest);
14
+ }
15
+ return new Promise((resolve, reject) => {
16
+ let abortListener;
17
+ let passthrough;
18
+ let response;
19
+ let body = null;
20
+ const bodyInit = fetchRequest['bodyInit'];
21
+ if (bodyInit != null) {
22
+ if (typeof bodyInit === 'string' ||
23
+ Buffer.isBuffer(bodyInit) ||
24
+ isUint8Array(bodyInit) ||
25
+ bodyInit instanceof Readable) {
26
+ body = bodyInit;
27
+ }
28
+ else if (fetchRequest.body != null) {
29
+ if (isNodeReadable(fetchRequest.body?.readable)) {
30
+ body = fetchRequest.body.readable;
31
+ }
32
+ else {
33
+ body = Readable.from(fetchRequest.body);
34
+ }
35
+ }
36
+ }
37
+ function setPassthrough(contentEncoding) {
38
+ switch (contentEncoding) {
39
+ case 'x-gzip':
40
+ case 'gzip':
41
+ passthrough = createGunzip();
42
+ break;
43
+ case 'x-deflate':
44
+ case 'deflate':
45
+ passthrough = createInflate();
46
+ break;
47
+ case 'x-deflate-raw':
48
+ case 'deflate-raw':
49
+ passthrough = createInflateRaw();
50
+ break;
51
+ case 'br':
52
+ passthrough = createBrotliDecompress();
53
+ break;
54
+ default:
55
+ passthrough = new PassThrough();
56
+ }
57
+ return passthrough;
58
+ }
59
+ const headersSerializer = fetchRequest.headersSerializer || getHeadersObj;
60
+ const nodeHeaders = headersSerializer(fetchRequest.headers);
61
+ if (nodeHeaders['accept-encoding'] == null) {
62
+ nodeHeaders['accept-encoding'] = 'gzip, deflate, br';
63
+ }
64
+ (fetchRequest.dispatcher || getGlobalDispatcher()).dispatch({
65
+ origin: fetchRequest.parsedUrl.origin,
66
+ path: fetchRequest.parsedUrl.pathname,
67
+ query: Object.fromEntries(fetchRequest.parsedUrl.searchParams),
68
+ method: fetchRequest.method,
69
+ headers: nodeHeaders,
70
+ body,
71
+ }, {
72
+ onRequestStart(controller) {
73
+ abortListener = function abortListener() {
74
+ controller.abort(fetchRequest['_signal']?.reason);
75
+ };
76
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
77
+ },
78
+ onRequestUpgrade(_controller, statusCode, headers, socket) {
79
+ response = new PonyfillResponse(socket, {
80
+ status: statusCode,
81
+ headers: headers,
82
+ url: fetchRequest.url,
83
+ });
84
+ resolve(response);
85
+ },
86
+ onResponseStart(controller, statusCode, headers, statusMessage) {
87
+ if (headers.location) {
88
+ if (fetchRequest.redirect === 'error') {
89
+ const redirectError = new Error('Redirects are not allowed');
90
+ reject(redirectError);
91
+ controller.resume();
92
+ return;
93
+ }
94
+ if (fetchRequest.redirect === 'follow') {
95
+ const redirectedUrl = new PonyfillURL(headers.location, fetchRequest.parsedUrl || fetchRequest.url);
96
+ const redirectResponse$ = fetchUndici(new PonyfillRequest(redirectedUrl, fetchRequest));
97
+ resolve(redirectResponse$.then(redirectResponse => {
98
+ redirectResponse.redirected = true;
99
+ return redirectResponse;
100
+ }));
101
+ controller.resume();
102
+ return;
103
+ }
104
+ }
105
+ passthrough = setPassthrough(headers['content-encoding']);
106
+ resolve(new PonyfillResponse(passthrough, {
107
+ status: statusCode,
108
+ statusText: statusMessage,
109
+ headers: headers,
110
+ url: fetchRequest.url,
111
+ }));
112
+ },
113
+ onResponseData(_controller, chunk) {
114
+ passthrough.write(chunk);
115
+ },
116
+ onResponseEnd(_controller, _trailers) {
117
+ passthrough.end();
118
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
119
+ },
120
+ onResponseError(_controller, error) {
121
+ if (passthrough) {
122
+ passthrough.destroy(error);
123
+ }
124
+ else {
125
+ reject(error);
126
+ }
127
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
128
+ },
129
+ // Old Undici support
130
+ onConnect(abort) {
131
+ abortListener = function abortListener() {
132
+ abort(fetchRequest['_signal']?.reason);
133
+ };
134
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
135
+ },
136
+ onError(error) {
137
+ if (passthrough) {
138
+ passthrough.destroy(error);
139
+ }
140
+ else {
141
+ reject(error);
142
+ }
143
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
144
+ },
145
+ // TODO: onUpgrade
146
+ onHeaders(statusCode, headersBuf, _resume, statusText) {
147
+ const headers = headersBuf.map(headerBuf => {
148
+ const header = headerBuf
149
+ .toString('utf-8')
150
+ .split(/:\s(.+)/)
151
+ .slice(0, 2);
152
+ if (header[0] === 'content-encoding') {
153
+ const contentEncoding = header[1];
154
+ setPassthrough(contentEncoding);
155
+ }
156
+ return header;
157
+ });
158
+ passthrough ||= new PassThrough();
159
+ resolve(new PonyfillResponse(passthrough, {
160
+ status: statusCode,
161
+ statusText,
162
+ headers,
163
+ url: fetchRequest.url,
164
+ }));
165
+ return true;
166
+ },
167
+ onData(chunk) {
168
+ return passthrough.write(chunk);
169
+ },
170
+ onComplete() {
171
+ passthrough.end();
172
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
173
+ },
174
+ });
175
+ });
176
+ };
177
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatwg-node/node-fetch",
3
- "version": "0.7.7",
3
+ "version": "0.7.8-alpha-20250122134914-14266b4231406ede9b9179c23b41bf6e6ed0ce35",
4
4
  "description": "Fetch API implementation for Node",
5
5
  "sideEffects": false,
6
6
  "dependencies": {
@@ -31,6 +31,7 @@ export declare class PonyfillRequest<TJSON = any> extends PonyfillBody<TJSON> im
31
31
  get parsedUrl(): URL;
32
32
  duplex: 'half' | 'full';
33
33
  agent: HTTPAgent | HTTPSAgent | false | undefined;
34
+ dispatcher: import('undici').Dispatcher | undefined;
34
35
  private _signal;
35
36
  get signal(): AbortSignal;
36
37
  clone(): PonyfillRequest<TJSON>;
@@ -31,6 +31,7 @@ export declare class PonyfillRequest<TJSON = any> extends PonyfillBody<TJSON> im
31
31
  get parsedUrl(): URL;
32
32
  duplex: 'half' | 'full';
33
33
  agent: HTTPAgent | HTTPSAgent | false | undefined;
34
+ dispatcher: import('undici').Dispatcher | undefined;
34
35
  private _signal;
35
36
  get signal(): AbortSignal;
36
37
  clone(): PonyfillRequest<TJSON>;
@@ -1,3 +1,5 @@
1
+ import { fetchNodeHttp } from './fetchNodeHttp.cjs';
1
2
  import { PonyfillRequest, RequestPonyfillInit } from './Request.cjs';
2
3
  import { PonyfillResponse } from './Response.cjs';
4
+ export declare function createFetchPonyfill(fetchFn: typeof fetchNodeHttp): <TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit) => Promise<PonyfillResponse<TResponseJSON>>;
3
5
  export declare function fetchPonyfill<TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit): Promise<PonyfillResponse<TResponseJSON>>;
@@ -1,3 +1,5 @@
1
+ import { fetchNodeHttp } from './fetchNodeHttp.js';
1
2
  import { PonyfillRequest, RequestPonyfillInit } from './Request.js';
2
3
  import { PonyfillResponse } from './Response.js';
4
+ export declare function createFetchPonyfill(fetchFn: typeof fetchNodeHttp): <TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit) => Promise<PonyfillResponse<TResponseJSON>>;
3
5
  export declare function fetchPonyfill<TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit): Promise<PonyfillResponse<TResponseJSON>>;
@@ -1,3 +1,3 @@
1
1
  import { PonyfillRequest } from './Request.cjs';
2
2
  import { PonyfillResponse } from './Response.cjs';
3
- export declare function fetchCurl<TResponseJSON = any, TRequestJSON = any>(fetchRequest: PonyfillRequest<TRequestJSON>): Promise<PonyfillResponse<TResponseJSON>>;
3
+ export declare function createFetchCurl(nodeLibcurl: typeof import('node-libcurl')): <TResponseJSON = any, TRequestJSON = any>(fetchRequest: PonyfillRequest<TRequestJSON>) => Promise<PonyfillResponse<TResponseJSON>>;
@@ -1,3 +1,3 @@
1
1
  import { PonyfillRequest } from './Request.js';
2
2
  import { PonyfillResponse } from './Response.js';
3
- export declare function fetchCurl<TResponseJSON = any, TRequestJSON = any>(fetchRequest: PonyfillRequest<TRequestJSON>): Promise<PonyfillResponse<TResponseJSON>>;
3
+ export declare function createFetchCurl(nodeLibcurl: typeof import('node-libcurl')): <TResponseJSON = any, TRequestJSON = any>(fetchRequest: PonyfillRequest<TRequestJSON>) => Promise<PonyfillResponse<TResponseJSON>>;
@@ -0,0 +1,3 @@
1
+ import { PonyfillRequest } from './Request.cjs';
2
+ import { PonyfillResponse } from './Response.cjs';
3
+ export declare function createFetchUndici(getGlobalDispatcher: () => import('undici').Dispatcher): <TResponseJSON = any, TRequestJSON = any>(fetchRequest: PonyfillRequest<TRequestJSON>) => Promise<PonyfillResponse<TResponseJSON>>;
@@ -0,0 +1,3 @@
1
+ import { PonyfillRequest } from './Request.js';
2
+ import { PonyfillResponse } from './Response.js';
3
+ export declare function createFetchUndici(getGlobalDispatcher: () => import('undici').Dispatcher): <TResponseJSON = any, TRequestJSON = any>(fetchRequest: PonyfillRequest<TRequestJSON>) => Promise<PonyfillResponse<TResponseJSON>>;