@whatwg-node/node-fetch 0.5.0-alpha-20230525151330-a086b4b → 0.5.0-alpha-20230529144043-3df0e1e
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/fetch-legacy.js +120 -0
- package/cjs/fetch-undici.js +71 -0
- package/cjs/fetch.js +13 -94
- package/cjs/utils.js +33 -1
- package/esm/fetch-legacy.js +116 -0
- package/esm/fetch-undici.js +67 -0
- package/esm/fetch.js +14 -93
- package/esm/utils.js +30 -0
- package/package.json +1 -1
- package/typings/fetch-legacy.d.cts +3 -0
- package/typings/fetch-legacy.d.ts +3 -0
- package/typings/fetch-undici.d.cts +3 -0
- package/typings/fetch-undici.d.ts +3 -0
- package/typings/fetch.d.cts +3 -3
- package/typings/fetch.d.ts +3 -3
- package/typings/utils.d.cts +3 -0
- package/typings/utils.d.ts +3 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.fetchLegacy = void 0;
|
4
|
+
const http_1 = require("http");
|
5
|
+
const https_1 = require("https");
|
6
|
+
const stream_1 = require("stream");
|
7
|
+
const zlib_1 = require("zlib");
|
8
|
+
const AbortError_js_1 = require("./AbortError.js");
|
9
|
+
const Request_js_1 = require("./Request.js");
|
10
|
+
const Response_js_1 = require("./Response.js");
|
11
|
+
const URL_js_1 = require("./URL.js");
|
12
|
+
const utils_js_1 = require("./utils.js");
|
13
|
+
function getRequestFnForProtocol(protocol) {
|
14
|
+
switch (protocol) {
|
15
|
+
case 'http:':
|
16
|
+
return http_1.request;
|
17
|
+
case 'https:':
|
18
|
+
return https_1.request;
|
19
|
+
}
|
20
|
+
throw new Error(`Unsupported protocol: ${protocol}`);
|
21
|
+
}
|
22
|
+
function fetchLegacy(info, init) {
|
23
|
+
if (typeof info === 'string' || 'href' in info) {
|
24
|
+
const ponyfillRequest = new Request_js_1.PonyfillRequest(info, init);
|
25
|
+
return fetchLegacy(ponyfillRequest);
|
26
|
+
}
|
27
|
+
const fetchRequest = info;
|
28
|
+
return new Promise((resolve, reject) => {
|
29
|
+
try {
|
30
|
+
const url = new URL_js_1.PonyfillURL(fetchRequest.url, 'http://localhost');
|
31
|
+
if (url.protocol === 'data:') {
|
32
|
+
const response = (0, utils_js_1.getResponseForDataUri)(url);
|
33
|
+
resolve(response);
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
if (url.protocol === 'file:') {
|
37
|
+
const response = (0, utils_js_1.getResponseForFile)(fetchRequest.url);
|
38
|
+
resolve(response);
|
39
|
+
return;
|
40
|
+
}
|
41
|
+
const requestFn = getRequestFnForProtocol(url.protocol);
|
42
|
+
const nodeReadable = (fetchRequest.body != null
|
43
|
+
? 'pipe' in fetchRequest.body
|
44
|
+
? fetchRequest.body
|
45
|
+
: stream_1.Readable.from(fetchRequest.body)
|
46
|
+
: null);
|
47
|
+
const headersSerializer = fetchRequest.headersSerializer || utils_js_1.getHeadersObj;
|
48
|
+
const nodeHeaders = headersSerializer(fetchRequest.headers);
|
49
|
+
const nodeRequest = requestFn(fetchRequest.url, {
|
50
|
+
method: fetchRequest.method,
|
51
|
+
headers: nodeHeaders,
|
52
|
+
signal: fetchRequest.signal,
|
53
|
+
});
|
54
|
+
// TODO: will be removed after v16 reaches EOL
|
55
|
+
fetchRequest.signal?.addEventListener('abort', () => {
|
56
|
+
if (!nodeRequest.aborted) {
|
57
|
+
nodeRequest.abort();
|
58
|
+
}
|
59
|
+
});
|
60
|
+
// TODO: will be removed after v16 reaches EOL
|
61
|
+
nodeRequest.once('abort', (reason) => {
|
62
|
+
reject(new AbortError_js_1.PonyfillAbortError(reason));
|
63
|
+
});
|
64
|
+
nodeRequest.once('response', nodeResponse => {
|
65
|
+
let responseBody = nodeResponse;
|
66
|
+
const contentEncoding = nodeResponse.headers['content-encoding'];
|
67
|
+
switch (contentEncoding) {
|
68
|
+
case 'x-gzip':
|
69
|
+
case 'gzip':
|
70
|
+
responseBody = nodeResponse.pipe((0, zlib_1.createGunzip)());
|
71
|
+
break;
|
72
|
+
case 'x-deflate':
|
73
|
+
case 'deflate':
|
74
|
+
responseBody = nodeResponse.pipe((0, zlib_1.createInflate)());
|
75
|
+
break;
|
76
|
+
case 'br':
|
77
|
+
responseBody = nodeResponse.pipe((0, zlib_1.createBrotliDecompress)());
|
78
|
+
break;
|
79
|
+
}
|
80
|
+
if (nodeResponse.headers.location) {
|
81
|
+
if (fetchRequest.redirect === 'error') {
|
82
|
+
const redirectError = new Error('Redirects are not allowed');
|
83
|
+
reject(redirectError);
|
84
|
+
nodeResponse.resume();
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
if (fetchRequest.redirect === 'follow') {
|
88
|
+
const redirectedUrl = new URL_js_1.PonyfillURL(nodeResponse.headers.location, url);
|
89
|
+
const redirectResponse$ = fetchLegacy(redirectedUrl, info);
|
90
|
+
resolve(redirectResponse$.then(redirectResponse => {
|
91
|
+
redirectResponse.redirected = true;
|
92
|
+
return redirectResponse;
|
93
|
+
}));
|
94
|
+
nodeResponse.resume();
|
95
|
+
return;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
const responseHeaders = nodeResponse.headers;
|
99
|
+
const ponyfillResponse = new Response_js_1.PonyfillResponse(responseBody, {
|
100
|
+
status: nodeResponse.statusCode,
|
101
|
+
statusText: nodeResponse.statusMessage,
|
102
|
+
headers: responseHeaders,
|
103
|
+
url: info.url,
|
104
|
+
});
|
105
|
+
resolve(ponyfillResponse);
|
106
|
+
});
|
107
|
+
nodeRequest.once('error', reject);
|
108
|
+
if (nodeReadable) {
|
109
|
+
nodeReadable.pipe(nodeRequest);
|
110
|
+
}
|
111
|
+
else {
|
112
|
+
nodeRequest.end();
|
113
|
+
}
|
114
|
+
}
|
115
|
+
catch (e) {
|
116
|
+
reject(e);
|
117
|
+
}
|
118
|
+
});
|
119
|
+
}
|
120
|
+
exports.fetchLegacy = fetchLegacy;
|
@@ -0,0 +1,71 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.fetchViaUndici = void 0;
|
4
|
+
const stream_1 = require("stream");
|
5
|
+
const zlib_1 = require("zlib");
|
6
|
+
const undici_1 = require("undici");
|
7
|
+
const Request_js_1 = require("./Request.js");
|
8
|
+
const Response_js_1 = require("./Response.js");
|
9
|
+
const URL_js_1 = require("./URL.js");
|
10
|
+
const utils_js_1 = require("./utils.js");
|
11
|
+
async function fetchViaUndici(info, init) {
|
12
|
+
if (typeof info === 'string' || 'href' in info) {
|
13
|
+
const ponyfillRequest = new Request_js_1.PonyfillRequest(info, init);
|
14
|
+
return fetchViaUndici(ponyfillRequest);
|
15
|
+
}
|
16
|
+
const fetchRequest = info;
|
17
|
+
const url = new URL_js_1.PonyfillURL(fetchRequest.url, 'http://localhost');
|
18
|
+
if (url.protocol === 'data:') {
|
19
|
+
const response = (0, utils_js_1.getResponseForDataUri)(url);
|
20
|
+
return response;
|
21
|
+
}
|
22
|
+
if (url.protocol === 'file:') {
|
23
|
+
const response = (0, utils_js_1.getResponseForFile)(fetchRequest.url);
|
24
|
+
return response;
|
25
|
+
}
|
26
|
+
const requestBody = (fetchRequest['bodyInit'] != null
|
27
|
+
? fetchRequest['bodyInit']
|
28
|
+
: fetchRequest.body != null
|
29
|
+
? 'pipe' in fetchRequest.body
|
30
|
+
? fetchRequest.body
|
31
|
+
: stream_1.Readable.from(fetchRequest.body)
|
32
|
+
: null);
|
33
|
+
const headersSerializer = fetchRequest.headersSerializer || utils_js_1.getHeadersObj;
|
34
|
+
const nodeHeaders = headersSerializer(fetchRequest.headers);
|
35
|
+
if (requestBody?.[Symbol.toStringTag] === 'FormData') {
|
36
|
+
delete nodeHeaders['content-type'];
|
37
|
+
}
|
38
|
+
const undiciData = await (0, undici_1.request)(fetchRequest.url, {
|
39
|
+
method: fetchRequest.method,
|
40
|
+
headers: nodeHeaders,
|
41
|
+
body: requestBody,
|
42
|
+
signal: fetchRequest.signal,
|
43
|
+
maxRedirections: fetchRequest.redirect === 'follow' ? 20 : 0,
|
44
|
+
});
|
45
|
+
if (fetchRequest.redirect === 'error' && undiciData.headers.location) {
|
46
|
+
const redirectError = new Error('Redirects are not allowed');
|
47
|
+
throw redirectError;
|
48
|
+
}
|
49
|
+
let responseBody = undiciData.body;
|
50
|
+
const contentEncoding = undiciData.headers['content-encoding'];
|
51
|
+
switch (contentEncoding) {
|
52
|
+
case 'x-gzip':
|
53
|
+
case 'gzip':
|
54
|
+
responseBody = responseBody.pipe((0, zlib_1.createGunzip)());
|
55
|
+
break;
|
56
|
+
case 'x-deflate':
|
57
|
+
case 'deflate':
|
58
|
+
responseBody = responseBody.pipe((0, zlib_1.createInflate)());
|
59
|
+
break;
|
60
|
+
case 'br':
|
61
|
+
responseBody = responseBody.pipe((0, zlib_1.createBrotliDecompress)());
|
62
|
+
break;
|
63
|
+
}
|
64
|
+
const ponyfillResponse = new Response_js_1.PonyfillResponse(responseBody, {
|
65
|
+
status: undiciData.statusCode,
|
66
|
+
headers: undiciData.headers,
|
67
|
+
url: fetchRequest.url,
|
68
|
+
});
|
69
|
+
return ponyfillResponse;
|
70
|
+
}
|
71
|
+
exports.fetchViaUndici = fetchViaUndici;
|
package/cjs/fetch.js
CHANGED
@@ -1,100 +1,19 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.fetchPonyfill = void 0;
|
4
|
-
const
|
5
|
-
const
|
6
|
-
|
7
|
-
const
|
8
|
-
const
|
9
|
-
|
10
|
-
|
11
|
-
const Response_js_1 = require("./Response.js");
|
12
|
-
const URL_js_1 = require("./URL.js");
|
13
|
-
const utils_js_1 = require("./utils.js");
|
14
|
-
function getResponseForFile(url) {
|
15
|
-
const path = (0, url_1.fileURLToPath)(url);
|
16
|
-
const readable = (0, fs_1.createReadStream)(path);
|
17
|
-
return new Response_js_1.PonyfillResponse(readable);
|
18
|
-
}
|
19
|
-
function getResponseForDataUri(url) {
|
20
|
-
const [mimeType = 'text/plain', ...datas] = url.pathname.split(',');
|
21
|
-
const data = decodeURIComponent(datas.join(','));
|
22
|
-
if (mimeType.endsWith(BASE64_SUFFIX)) {
|
23
|
-
const buffer = Buffer.from(data, 'base64url');
|
24
|
-
const realMimeType = mimeType.slice(0, -BASE64_SUFFIX.length);
|
25
|
-
const file = new Blob_js_1.PonyfillBlob([buffer], { type: realMimeType });
|
26
|
-
return new Response_js_1.PonyfillResponse(file, {
|
27
|
-
status: 200,
|
28
|
-
statusText: 'OK',
|
29
|
-
});
|
4
|
+
const fetch_legacy_1 = require("./fetch-legacy");
|
5
|
+
const fetch_undici_1 = require("./fetch-undici");
|
6
|
+
function getNodeMajorVersion() {
|
7
|
+
const version = process.version;
|
8
|
+
const match = version.match(/^v(\d+)/);
|
9
|
+
if (!match) {
|
10
|
+
throw new Error(`Unable to parse Node.js version: ${version}`);
|
30
11
|
}
|
31
|
-
return
|
32
|
-
status: 200,
|
33
|
-
statusText: 'OK',
|
34
|
-
headers: {
|
35
|
-
'content-type': mimeType,
|
36
|
-
},
|
37
|
-
});
|
12
|
+
return parseInt(match[1]);
|
38
13
|
}
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
}
|
45
|
-
const fetchRequest = info;
|
46
|
-
const url = new URL_js_1.PonyfillURL(fetchRequest.url, 'http://localhost');
|
47
|
-
if (url.protocol === 'data:') {
|
48
|
-
const response = getResponseForDataUri(url);
|
49
|
-
return response;
|
50
|
-
}
|
51
|
-
if (url.protocol === 'file:') {
|
52
|
-
const response = getResponseForFile(fetchRequest.url);
|
53
|
-
return response;
|
54
|
-
}
|
55
|
-
const requestBody = (fetchRequest['bodyInit'] != null
|
56
|
-
? fetchRequest['bodyInit']
|
57
|
-
: fetchRequest.body != null
|
58
|
-
? 'pipe' in fetchRequest.body
|
59
|
-
? fetchRequest.body
|
60
|
-
: stream_1.Readable.from(fetchRequest.body)
|
61
|
-
: null);
|
62
|
-
const headersSerializer = fetchRequest.headersSerializer || utils_js_1.getHeadersObj;
|
63
|
-
const nodeHeaders = headersSerializer(fetchRequest.headers);
|
64
|
-
if (requestBody?.[Symbol.toStringTag] === 'FormData') {
|
65
|
-
delete nodeHeaders['content-type'];
|
66
|
-
}
|
67
|
-
const undiciData = await (0, undici_1.request)(fetchRequest.url, {
|
68
|
-
method: fetchRequest.method,
|
69
|
-
headers: nodeHeaders,
|
70
|
-
body: requestBody,
|
71
|
-
signal: fetchRequest.signal,
|
72
|
-
maxRedirections: fetchRequest.redirect === 'follow' ? 20 : 0,
|
73
|
-
});
|
74
|
-
if (fetchRequest.redirect === 'error' && undiciData.headers.location) {
|
75
|
-
const redirectError = new Error('Redirects are not allowed');
|
76
|
-
throw redirectError;
|
77
|
-
}
|
78
|
-
let responseBody = undiciData.body;
|
79
|
-
const contentEncoding = undiciData.headers['content-encoding'];
|
80
|
-
switch (contentEncoding) {
|
81
|
-
case 'x-gzip':
|
82
|
-
case 'gzip':
|
83
|
-
responseBody = responseBody.pipe((0, zlib_1.createGunzip)());
|
84
|
-
break;
|
85
|
-
case 'x-deflate':
|
86
|
-
case 'deflate':
|
87
|
-
responseBody = responseBody.pipe((0, zlib_1.createInflate)());
|
88
|
-
break;
|
89
|
-
case 'br':
|
90
|
-
responseBody = responseBody.pipe((0, zlib_1.createBrotliDecompress)());
|
91
|
-
break;
|
92
|
-
}
|
93
|
-
const ponyfillResponse = new Response_js_1.PonyfillResponse(responseBody, {
|
94
|
-
status: undiciData.statusCode,
|
95
|
-
headers: undiciData.headers,
|
96
|
-
url: fetchRequest.url,
|
97
|
-
});
|
98
|
-
return ponyfillResponse;
|
14
|
+
if (getNodeMajorVersion() >= 19) {
|
15
|
+
exports.fetchPonyfill = fetch_undici_1.fetchViaUndici;
|
16
|
+
}
|
17
|
+
else {
|
18
|
+
exports.fetchPonyfill = fetch_legacy_1.fetchLegacy;
|
99
19
|
}
|
100
|
-
exports.fetchPonyfill = fetchPonyfill;
|
package/cjs/utils.js
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.uint8ArrayToArrayBuffer = exports.getHeadersObj = void 0;
|
3
|
+
exports.getResponseForDataUri = exports.getResponseForFile = exports.uint8ArrayToArrayBuffer = exports.getHeadersObj = void 0;
|
4
|
+
const fs_1 = require("fs");
|
5
|
+
const url_1 = require("url");
|
6
|
+
const Blob_1 = require("./Blob");
|
7
|
+
const Response_1 = require("./Response");
|
4
8
|
function getHeadersObj(headers) {
|
5
9
|
if (headers == null || !('forEach' in headers)) {
|
6
10
|
return headers;
|
@@ -16,3 +20,31 @@ function uint8ArrayToArrayBuffer(uint8array) {
|
|
16
20
|
return uint8array.buffer.slice(uint8array.byteOffset, uint8array.byteOffset + uint8array.byteLength);
|
17
21
|
}
|
18
22
|
exports.uint8ArrayToArrayBuffer = uint8ArrayToArrayBuffer;
|
23
|
+
function getResponseForFile(url) {
|
24
|
+
const path = (0, url_1.fileURLToPath)(url);
|
25
|
+
const readable = (0, fs_1.createReadStream)(path);
|
26
|
+
return new Response_1.PonyfillResponse(readable);
|
27
|
+
}
|
28
|
+
exports.getResponseForFile = getResponseForFile;
|
29
|
+
const BASE64_SUFFIX = ';base64';
|
30
|
+
function getResponseForDataUri(url) {
|
31
|
+
const [mimeType = 'text/plain', ...datas] = url.pathname.split(',');
|
32
|
+
const data = decodeURIComponent(datas.join(','));
|
33
|
+
if (mimeType.endsWith(BASE64_SUFFIX)) {
|
34
|
+
const buffer = Buffer.from(data, 'base64url');
|
35
|
+
const realMimeType = mimeType.slice(0, -BASE64_SUFFIX.length);
|
36
|
+
const file = new Blob_1.PonyfillBlob([buffer], { type: realMimeType });
|
37
|
+
return new Response_1.PonyfillResponse(file, {
|
38
|
+
status: 200,
|
39
|
+
statusText: 'OK',
|
40
|
+
});
|
41
|
+
}
|
42
|
+
return new Response_1.PonyfillResponse(data, {
|
43
|
+
status: 200,
|
44
|
+
statusText: 'OK',
|
45
|
+
headers: {
|
46
|
+
'content-type': mimeType,
|
47
|
+
},
|
48
|
+
});
|
49
|
+
}
|
50
|
+
exports.getResponseForDataUri = getResponseForDataUri;
|
@@ -0,0 +1,116 @@
|
|
1
|
+
import { request as httpRequest } from 'http';
|
2
|
+
import { request as httpsRequest } from 'https';
|
3
|
+
import { Readable } from 'stream';
|
4
|
+
import { createBrotliDecompress, createGunzip, createInflate } from 'zlib';
|
5
|
+
import { PonyfillAbortError } from './AbortError.js';
|
6
|
+
import { PonyfillRequest } from './Request.js';
|
7
|
+
import { PonyfillResponse } from './Response.js';
|
8
|
+
import { PonyfillURL } from './URL.js';
|
9
|
+
import { getHeadersObj, getResponseForDataUri, getResponseForFile } from './utils.js';
|
10
|
+
function getRequestFnForProtocol(protocol) {
|
11
|
+
switch (protocol) {
|
12
|
+
case 'http:':
|
13
|
+
return httpRequest;
|
14
|
+
case 'https:':
|
15
|
+
return httpsRequest;
|
16
|
+
}
|
17
|
+
throw new Error(`Unsupported protocol: ${protocol}`);
|
18
|
+
}
|
19
|
+
export function fetchLegacy(info, init) {
|
20
|
+
if (typeof info === 'string' || 'href' in info) {
|
21
|
+
const ponyfillRequest = new PonyfillRequest(info, init);
|
22
|
+
return fetchLegacy(ponyfillRequest);
|
23
|
+
}
|
24
|
+
const fetchRequest = info;
|
25
|
+
return new Promise((resolve, reject) => {
|
26
|
+
try {
|
27
|
+
const url = new PonyfillURL(fetchRequest.url, 'http://localhost');
|
28
|
+
if (url.protocol === 'data:') {
|
29
|
+
const response = getResponseForDataUri(url);
|
30
|
+
resolve(response);
|
31
|
+
return;
|
32
|
+
}
|
33
|
+
if (url.protocol === 'file:') {
|
34
|
+
const response = getResponseForFile(fetchRequest.url);
|
35
|
+
resolve(response);
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
const requestFn = getRequestFnForProtocol(url.protocol);
|
39
|
+
const nodeReadable = (fetchRequest.body != null
|
40
|
+
? 'pipe' in fetchRequest.body
|
41
|
+
? fetchRequest.body
|
42
|
+
: Readable.from(fetchRequest.body)
|
43
|
+
: null);
|
44
|
+
const headersSerializer = fetchRequest.headersSerializer || getHeadersObj;
|
45
|
+
const nodeHeaders = headersSerializer(fetchRequest.headers);
|
46
|
+
const nodeRequest = requestFn(fetchRequest.url, {
|
47
|
+
method: fetchRequest.method,
|
48
|
+
headers: nodeHeaders,
|
49
|
+
signal: fetchRequest.signal,
|
50
|
+
});
|
51
|
+
// TODO: will be removed after v16 reaches EOL
|
52
|
+
fetchRequest.signal?.addEventListener('abort', () => {
|
53
|
+
if (!nodeRequest.aborted) {
|
54
|
+
nodeRequest.abort();
|
55
|
+
}
|
56
|
+
});
|
57
|
+
// TODO: will be removed after v16 reaches EOL
|
58
|
+
nodeRequest.once('abort', (reason) => {
|
59
|
+
reject(new PonyfillAbortError(reason));
|
60
|
+
});
|
61
|
+
nodeRequest.once('response', nodeResponse => {
|
62
|
+
let responseBody = nodeResponse;
|
63
|
+
const contentEncoding = nodeResponse.headers['content-encoding'];
|
64
|
+
switch (contentEncoding) {
|
65
|
+
case 'x-gzip':
|
66
|
+
case 'gzip':
|
67
|
+
responseBody = nodeResponse.pipe(createGunzip());
|
68
|
+
break;
|
69
|
+
case 'x-deflate':
|
70
|
+
case 'deflate':
|
71
|
+
responseBody = nodeResponse.pipe(createInflate());
|
72
|
+
break;
|
73
|
+
case 'br':
|
74
|
+
responseBody = nodeResponse.pipe(createBrotliDecompress());
|
75
|
+
break;
|
76
|
+
}
|
77
|
+
if (nodeResponse.headers.location) {
|
78
|
+
if (fetchRequest.redirect === 'error') {
|
79
|
+
const redirectError = new Error('Redirects are not allowed');
|
80
|
+
reject(redirectError);
|
81
|
+
nodeResponse.resume();
|
82
|
+
return;
|
83
|
+
}
|
84
|
+
if (fetchRequest.redirect === 'follow') {
|
85
|
+
const redirectedUrl = new PonyfillURL(nodeResponse.headers.location, url);
|
86
|
+
const redirectResponse$ = fetchLegacy(redirectedUrl, info);
|
87
|
+
resolve(redirectResponse$.then(redirectResponse => {
|
88
|
+
redirectResponse.redirected = true;
|
89
|
+
return redirectResponse;
|
90
|
+
}));
|
91
|
+
nodeResponse.resume();
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
const responseHeaders = nodeResponse.headers;
|
96
|
+
const ponyfillResponse = new PonyfillResponse(responseBody, {
|
97
|
+
status: nodeResponse.statusCode,
|
98
|
+
statusText: nodeResponse.statusMessage,
|
99
|
+
headers: responseHeaders,
|
100
|
+
url: info.url,
|
101
|
+
});
|
102
|
+
resolve(ponyfillResponse);
|
103
|
+
});
|
104
|
+
nodeRequest.once('error', reject);
|
105
|
+
if (nodeReadable) {
|
106
|
+
nodeReadable.pipe(nodeRequest);
|
107
|
+
}
|
108
|
+
else {
|
109
|
+
nodeRequest.end();
|
110
|
+
}
|
111
|
+
}
|
112
|
+
catch (e) {
|
113
|
+
reject(e);
|
114
|
+
}
|
115
|
+
});
|
116
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { Readable } from 'stream';
|
2
|
+
import { createBrotliDecompress, createGunzip, createInflate } from 'zlib';
|
3
|
+
import { request } from 'undici';
|
4
|
+
import { PonyfillRequest } from './Request.js';
|
5
|
+
import { PonyfillResponse } from './Response.js';
|
6
|
+
import { PonyfillURL } from './URL.js';
|
7
|
+
import { getHeadersObj, getResponseForDataUri, getResponseForFile } from './utils.js';
|
8
|
+
export async function fetchViaUndici(info, init) {
|
9
|
+
if (typeof info === 'string' || 'href' in info) {
|
10
|
+
const ponyfillRequest = new PonyfillRequest(info, init);
|
11
|
+
return fetchViaUndici(ponyfillRequest);
|
12
|
+
}
|
13
|
+
const fetchRequest = info;
|
14
|
+
const url = new PonyfillURL(fetchRequest.url, 'http://localhost');
|
15
|
+
if (url.protocol === 'data:') {
|
16
|
+
const response = getResponseForDataUri(url);
|
17
|
+
return response;
|
18
|
+
}
|
19
|
+
if (url.protocol === 'file:') {
|
20
|
+
const response = getResponseForFile(fetchRequest.url);
|
21
|
+
return response;
|
22
|
+
}
|
23
|
+
const requestBody = (fetchRequest['bodyInit'] != null
|
24
|
+
? fetchRequest['bodyInit']
|
25
|
+
: fetchRequest.body != null
|
26
|
+
? 'pipe' in fetchRequest.body
|
27
|
+
? fetchRequest.body
|
28
|
+
: Readable.from(fetchRequest.body)
|
29
|
+
: null);
|
30
|
+
const headersSerializer = fetchRequest.headersSerializer || getHeadersObj;
|
31
|
+
const nodeHeaders = headersSerializer(fetchRequest.headers);
|
32
|
+
if (requestBody?.[Symbol.toStringTag] === 'FormData') {
|
33
|
+
delete nodeHeaders['content-type'];
|
34
|
+
}
|
35
|
+
const undiciData = await request(fetchRequest.url, {
|
36
|
+
method: fetchRequest.method,
|
37
|
+
headers: nodeHeaders,
|
38
|
+
body: requestBody,
|
39
|
+
signal: fetchRequest.signal,
|
40
|
+
maxRedirections: fetchRequest.redirect === 'follow' ? 20 : 0,
|
41
|
+
});
|
42
|
+
if (fetchRequest.redirect === 'error' && undiciData.headers.location) {
|
43
|
+
const redirectError = new Error('Redirects are not allowed');
|
44
|
+
throw redirectError;
|
45
|
+
}
|
46
|
+
let responseBody = undiciData.body;
|
47
|
+
const contentEncoding = undiciData.headers['content-encoding'];
|
48
|
+
switch (contentEncoding) {
|
49
|
+
case 'x-gzip':
|
50
|
+
case 'gzip':
|
51
|
+
responseBody = responseBody.pipe(createGunzip());
|
52
|
+
break;
|
53
|
+
case 'x-deflate':
|
54
|
+
case 'deflate':
|
55
|
+
responseBody = responseBody.pipe(createInflate());
|
56
|
+
break;
|
57
|
+
case 'br':
|
58
|
+
responseBody = responseBody.pipe(createBrotliDecompress());
|
59
|
+
break;
|
60
|
+
}
|
61
|
+
const ponyfillResponse = new PonyfillResponse(responseBody, {
|
62
|
+
status: undiciData.statusCode,
|
63
|
+
headers: undiciData.headers,
|
64
|
+
url: fetchRequest.url,
|
65
|
+
});
|
66
|
+
return ponyfillResponse;
|
67
|
+
}
|
package/esm/fetch.js
CHANGED
@@ -1,96 +1,17 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
import { PonyfillResponse } from './Response.js';
|
9
|
-
import { PonyfillURL } from './URL.js';
|
10
|
-
import { getHeadersObj } from './utils.js';
|
11
|
-
function getResponseForFile(url) {
|
12
|
-
const path = fileURLToPath(url);
|
13
|
-
const readable = createReadStream(path);
|
14
|
-
return new PonyfillResponse(readable);
|
15
|
-
}
|
16
|
-
function getResponseForDataUri(url) {
|
17
|
-
const [mimeType = 'text/plain', ...datas] = url.pathname.split(',');
|
18
|
-
const data = decodeURIComponent(datas.join(','));
|
19
|
-
if (mimeType.endsWith(BASE64_SUFFIX)) {
|
20
|
-
const buffer = Buffer.from(data, 'base64url');
|
21
|
-
const realMimeType = mimeType.slice(0, -BASE64_SUFFIX.length);
|
22
|
-
const file = new PonyfillBlob([buffer], { type: realMimeType });
|
23
|
-
return new PonyfillResponse(file, {
|
24
|
-
status: 200,
|
25
|
-
statusText: 'OK',
|
26
|
-
});
|
1
|
+
import { fetchLegacy } from './fetch-legacy';
|
2
|
+
import { fetchViaUndici } from './fetch-undici';
|
3
|
+
function getNodeMajorVersion() {
|
4
|
+
const version = process.version;
|
5
|
+
const match = version.match(/^v(\d+)/);
|
6
|
+
if (!match) {
|
7
|
+
throw new Error(`Unable to parse Node.js version: ${version}`);
|
27
8
|
}
|
28
|
-
return
|
29
|
-
status: 200,
|
30
|
-
statusText: 'OK',
|
31
|
-
headers: {
|
32
|
-
'content-type': mimeType,
|
33
|
-
},
|
34
|
-
});
|
9
|
+
return parseInt(match[1]);
|
35
10
|
}
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
const fetchRequest = info;
|
43
|
-
const url = new PonyfillURL(fetchRequest.url, 'http://localhost');
|
44
|
-
if (url.protocol === 'data:') {
|
45
|
-
const response = getResponseForDataUri(url);
|
46
|
-
return response;
|
47
|
-
}
|
48
|
-
if (url.protocol === 'file:') {
|
49
|
-
const response = getResponseForFile(fetchRequest.url);
|
50
|
-
return response;
|
51
|
-
}
|
52
|
-
const requestBody = (fetchRequest['bodyInit'] != null
|
53
|
-
? fetchRequest['bodyInit']
|
54
|
-
: fetchRequest.body != null
|
55
|
-
? 'pipe' in fetchRequest.body
|
56
|
-
? fetchRequest.body
|
57
|
-
: Readable.from(fetchRequest.body)
|
58
|
-
: null);
|
59
|
-
const headersSerializer = fetchRequest.headersSerializer || getHeadersObj;
|
60
|
-
const nodeHeaders = headersSerializer(fetchRequest.headers);
|
61
|
-
if (requestBody?.[Symbol.toStringTag] === 'FormData') {
|
62
|
-
delete nodeHeaders['content-type'];
|
63
|
-
}
|
64
|
-
const undiciData = await request(fetchRequest.url, {
|
65
|
-
method: fetchRequest.method,
|
66
|
-
headers: nodeHeaders,
|
67
|
-
body: requestBody,
|
68
|
-
signal: fetchRequest.signal,
|
69
|
-
maxRedirections: fetchRequest.redirect === 'follow' ? 20 : 0,
|
70
|
-
});
|
71
|
-
if (fetchRequest.redirect === 'error' && undiciData.headers.location) {
|
72
|
-
const redirectError = new Error('Redirects are not allowed');
|
73
|
-
throw redirectError;
|
74
|
-
}
|
75
|
-
let responseBody = undiciData.body;
|
76
|
-
const contentEncoding = undiciData.headers['content-encoding'];
|
77
|
-
switch (contentEncoding) {
|
78
|
-
case 'x-gzip':
|
79
|
-
case 'gzip':
|
80
|
-
responseBody = responseBody.pipe(createGunzip());
|
81
|
-
break;
|
82
|
-
case 'x-deflate':
|
83
|
-
case 'deflate':
|
84
|
-
responseBody = responseBody.pipe(createInflate());
|
85
|
-
break;
|
86
|
-
case 'br':
|
87
|
-
responseBody = responseBody.pipe(createBrotliDecompress());
|
88
|
-
break;
|
89
|
-
}
|
90
|
-
const ponyfillResponse = new PonyfillResponse(responseBody, {
|
91
|
-
status: undiciData.statusCode,
|
92
|
-
headers: undiciData.headers,
|
93
|
-
url: fetchRequest.url,
|
94
|
-
});
|
95
|
-
return ponyfillResponse;
|
11
|
+
export let fetchPonyfill;
|
12
|
+
if (getNodeMajorVersion() >= 19) {
|
13
|
+
fetchPonyfill = fetchViaUndici;
|
14
|
+
}
|
15
|
+
else {
|
16
|
+
fetchPonyfill = fetchLegacy;
|
96
17
|
}
|
package/esm/utils.js
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
import { createReadStream } from 'fs';
|
2
|
+
import { fileURLToPath } from 'url';
|
3
|
+
import { PonyfillBlob } from './Blob';
|
4
|
+
import { PonyfillResponse } from './Response';
|
1
5
|
export function getHeadersObj(headers) {
|
2
6
|
if (headers == null || !('forEach' in headers)) {
|
3
7
|
return headers;
|
@@ -11,3 +15,29 @@ export function getHeadersObj(headers) {
|
|
11
15
|
export function uint8ArrayToArrayBuffer(uint8array) {
|
12
16
|
return uint8array.buffer.slice(uint8array.byteOffset, uint8array.byteOffset + uint8array.byteLength);
|
13
17
|
}
|
18
|
+
export function getResponseForFile(url) {
|
19
|
+
const path = fileURLToPath(url);
|
20
|
+
const readable = createReadStream(path);
|
21
|
+
return new PonyfillResponse(readable);
|
22
|
+
}
|
23
|
+
const BASE64_SUFFIX = ';base64';
|
24
|
+
export function getResponseForDataUri(url) {
|
25
|
+
const [mimeType = 'text/plain', ...datas] = url.pathname.split(',');
|
26
|
+
const data = decodeURIComponent(datas.join(','));
|
27
|
+
if (mimeType.endsWith(BASE64_SUFFIX)) {
|
28
|
+
const buffer = Buffer.from(data, 'base64url');
|
29
|
+
const realMimeType = mimeType.slice(0, -BASE64_SUFFIX.length);
|
30
|
+
const file = new PonyfillBlob([buffer], { type: realMimeType });
|
31
|
+
return new PonyfillResponse(file, {
|
32
|
+
status: 200,
|
33
|
+
statusText: 'OK',
|
34
|
+
});
|
35
|
+
}
|
36
|
+
return new PonyfillResponse(data, {
|
37
|
+
status: 200,
|
38
|
+
statusText: 'OK',
|
39
|
+
headers: {
|
40
|
+
'content-type': mimeType,
|
41
|
+
},
|
42
|
+
});
|
43
|
+
}
|
package/package.json
CHANGED
@@ -0,0 +1,3 @@
|
|
1
|
+
import { PonyfillRequest, RequestPonyfillInit } from './Request.cjs';
|
2
|
+
import { PonyfillResponse } from './Response.cjs';
|
3
|
+
export declare function fetchLegacy<TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit): Promise<PonyfillResponse<TResponseJSON>>;
|
@@ -0,0 +1,3 @@
|
|
1
|
+
import { PonyfillRequest, RequestPonyfillInit } from './Request.js';
|
2
|
+
import { PonyfillResponse } from './Response.js';
|
3
|
+
export declare function fetchLegacy<TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit): Promise<PonyfillResponse<TResponseJSON>>;
|
@@ -0,0 +1,3 @@
|
|
1
|
+
import { PonyfillRequest, RequestPonyfillInit } from './Request.cjs';
|
2
|
+
import { PonyfillResponse } from './Response.cjs';
|
3
|
+
export declare function fetchViaUndici<TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit): Promise<PonyfillResponse<TResponseJSON>>;
|
@@ -0,0 +1,3 @@
|
|
1
|
+
import { PonyfillRequest, RequestPonyfillInit } from './Request.js';
|
2
|
+
import { PonyfillResponse } from './Response.js';
|
3
|
+
export declare function fetchViaUndici<TResponseJSON = any, TRequestJSON = any>(info: string | PonyfillRequest<TRequestJSON> | URL, init?: RequestPonyfillInit): Promise<PonyfillResponse<TResponseJSON>>;
|
package/typings/fetch.d.cts
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
export declare
|
1
|
+
import { fetchLegacy } from './fetch-legacy';
|
2
|
+
import { fetchViaUndici } from './fetch-undici';
|
3
|
+
export declare let fetchPonyfill: typeof fetchLegacy | typeof fetchViaUndici;
|
package/typings/fetch.d.ts
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
export declare
|
1
|
+
import { fetchLegacy } from './fetch-legacy';
|
2
|
+
import { fetchViaUndici } from './fetch-undici';
|
3
|
+
export declare let fetchPonyfill: typeof fetchLegacy | typeof fetchViaUndici;
|
package/typings/utils.d.cts
CHANGED
@@ -1,2 +1,5 @@
|
|
1
|
+
import { PonyfillResponse } from './Response';
|
1
2
|
export declare function getHeadersObj(headers: Headers): Record<string, string>;
|
2
3
|
export declare function uint8ArrayToArrayBuffer(uint8array: Uint8Array): ArrayBuffer;
|
4
|
+
export declare function getResponseForFile(url: string): PonyfillResponse<any>;
|
5
|
+
export declare function getResponseForDataUri(url: URL): PonyfillResponse<any>;
|
package/typings/utils.d.ts
CHANGED
@@ -1,2 +1,5 @@
|
|
1
|
+
import { PonyfillResponse } from './Response';
|
1
2
|
export declare function getHeadersObj(headers: Headers): Record<string, string>;
|
2
3
|
export declare function uint8ArrayToArrayBuffer(uint8array: Uint8Array): ArrayBuffer;
|
4
|
+
export declare function getResponseForFile(url: string): PonyfillResponse<any>;
|
5
|
+
export declare function getResponseForDataUri(url: URL): PonyfillResponse<any>;
|