@whatwg-node/node-fetch 0.7.7-rc-20250110093600-48b5086ea3535f34641fd8559221fa26fe734251 → 0.7.8-alpha-20250122134914-14266b4231406ede9b9179c23b41bf6e6ed0ce35
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/cjs/Request.js +1 -0
- package/cjs/fetch.js +81 -10
- package/cjs/fetchCurl.js +139 -137
- package/cjs/fetchUndici.js +180 -0
- package/esm/Request.js +1 -0
- package/esm/fetch.js +48 -11
- package/esm/fetchCurl.js +138 -136
- package/esm/fetchUndici.js +177 -0
- package/package.json +1 -1
- package/typings/Request.d.cts +1 -0
- package/typings/Request.d.ts +1 -0
- package/typings/fetch.d.cts +2 -0
- package/typings/fetch.d.ts +2 -0
- package/typings/fetchCurl.d.cts +1 -1
- package/typings/fetchCurl.d.ts +1 -1
- package/typings/fetchUndici.d.cts +3 -0
- package/typings/fetchUndici.d.ts +3 -0
package/cjs/Request.js
CHANGED
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
|
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
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
76
|
-
|
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 (
|
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.
|
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
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
96
|
-
|
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
|
-
|
101
|
-
curlHandle.
|
46
|
+
if (process.env.DEBUG) {
|
47
|
+
curlHandle.setOpt('VERBOSE', true);
|
102
48
|
}
|
103
|
-
|
104
|
-
|
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
|
-
|
108
|
-
const
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
count
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
-
|
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
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 {
|
5
|
-
import {
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
73
|
-
|
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
|
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
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
93
|
-
|
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
|
-
|
98
|
-
curlHandle.
|
43
|
+
if (process.env.DEBUG) {
|
44
|
+
curlHandle.setOpt('VERBOSE', true);
|
99
45
|
}
|
100
|
-
|
101
|
-
|
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
|
-
|
105
|
-
const
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
-
|
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
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
count
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
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.
|
3
|
+
"version": "0.7.8-alpha-20250122134914-14266b4231406ede9b9179c23b41bf6e6ed0ce35",
|
4
4
|
"description": "Fetch API implementation for Node",
|
5
5
|
"sideEffects": false,
|
6
6
|
"dependencies": {
|
package/typings/Request.d.cts
CHANGED
@@ -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>;
|
package/typings/Request.d.ts
CHANGED
@@ -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>;
|
package/typings/fetch.d.cts
CHANGED
@@ -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>>;
|
package/typings/fetch.d.ts
CHANGED
@@ -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>>;
|
package/typings/fetchCurl.d.cts
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
import { PonyfillRequest } from './Request.cjs';
|
2
2
|
import { PonyfillResponse } from './Response.cjs';
|
3
|
-
export declare function
|
3
|
+
export declare function createFetchCurl(nodeLibcurl: typeof import('node-libcurl')): <TResponseJSON = any, TRequestJSON = any>(fetchRequest: PonyfillRequest<TRequestJSON>) => Promise<PonyfillResponse<TResponseJSON>>;
|
package/typings/fetchCurl.d.ts
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
import { PonyfillRequest } from './Request.js';
|
2
2
|
import { PonyfillResponse } from './Response.js';
|
3
|
-
export declare function
|
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>>;
|