@whatwg-node/node-fetch 0.7.8-alpha-20250122141536-187117d0e771637bc659740c29e4b57339e20311 → 0.7.8-alpha-20250122150621-99aa3b02dabf84434a687202da321ea8807e453d

Sign up to get free protection for your applications and to get access to all the features.
package/cjs/fetch.js CHANGED
@@ -98,7 +98,20 @@ function getNativeGlobalDispatcher() {
98
98
  function createFetchFn() {
99
99
  const libcurlModuleName = 'node-libcurl';
100
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)));
101
+ if (process.env.DEBUG) {
102
+ console.debug(`[@whatwg-node/node-fetch] - Trying to import ${libcurlModuleName} for fetch ponyfill`);
103
+ }
104
+ return Promise.resolve(`${libcurlModuleName}`).then(s => __importStar(require(s))).then(libcurl => (0, fetchCurl_js_1.createFetchCurl)(libcurl), () => {
105
+ if (process.env.DEBUG) {
106
+ console.debug(`[@whatwg-node/node-fetch] - Failed to import ${libcurlModuleName}, trying ${undiciModuleName}`);
107
+ }
108
+ return Promise.resolve(`${undiciModuleName}`).then(s => __importStar(require(s))).then((undici) => (0, fetchUndici_js_1.createFetchUndici)(() => undici.getGlobalDispatcher()), () => {
109
+ if (process.env.DEBUG) {
110
+ console.debug(`[@whatwg-node/node-fetch] - Failed to import ${undiciModuleName}, falling back to built-in undici in Node`);
111
+ }
112
+ return (0, fetchUndici_js_1.createFetchUndici)(getNativeGlobalDispatcher);
113
+ });
114
+ });
102
115
  }
103
116
  function fetchNonHttp(fetchRequest) {
104
117
  if (fetchRequest.url.startsWith('data:')) {
@@ -13,163 +13,178 @@ function createFetchUndici(getGlobalDispatcher) {
13
13
  return function fetchUndici(fetchRequest) {
14
14
  const dispatcher = fetchRequest.dispatcher || getGlobalDispatcher();
15
15
  if (!dispatcher) {
16
+ if (process.env.DEBUG) {
17
+ console.debug('[@whatwg-node/node-fetch] - native undici dispatcher not available, falling back to node:http');
18
+ }
16
19
  return (0, fetchNodeHttp_js_1.fetchNodeHttp)(fetchRequest);
17
20
  }
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 node_stream_1.Readable) {
29
- body = bodyInit;
21
+ const deferred = (0, utils_js_1.createDeferredPromise)();
22
+ let abortListener;
23
+ let passthrough;
24
+ let response;
25
+ let body = null;
26
+ const bodyInit = fetchRequest['bodyInit'];
27
+ if (bodyInit != null) {
28
+ if (typeof bodyInit === 'string' ||
29
+ Buffer.isBuffer(bodyInit) ||
30
+ (0, types_1.isUint8Array)(bodyInit) ||
31
+ bodyInit instanceof node_stream_1.Readable) {
32
+ body = bodyInit;
33
+ }
34
+ else if (fetchRequest.body != null) {
35
+ if ((0, utils_js_1.isNodeReadable)(fetchRequest.body?.readable)) {
36
+ body = fetchRequest.body.readable;
30
37
  }
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 = node_stream_1.Readable.from(fetchRequest.body);
37
- }
38
+ else {
39
+ body = node_stream_1.Readable.from(fetchRequest.body);
38
40
  }
39
41
  }
40
- function setPassthrough(contentEncoding) {
41
- switch (contentEncoding) {
42
- case 'x-gzip':
43
- case 'gzip':
44
- passthrough = (0, node_zlib_1.createGunzip)();
45
- break;
46
- case 'x-deflate':
47
- case 'deflate':
48
- passthrough = (0, node_zlib_1.createInflate)();
49
- break;
50
- case 'x-deflate-raw':
51
- case 'deflate-raw':
52
- passthrough = (0, node_zlib_1.createInflateRaw)();
53
- break;
54
- case 'br':
55
- passthrough = (0, node_zlib_1.createBrotliDecompress)();
56
- break;
57
- default:
58
- passthrough = new node_stream_1.PassThrough();
59
- }
60
- return passthrough;
42
+ }
43
+ function setPassthrough(contentEncoding) {
44
+ switch (contentEncoding) {
45
+ case 'x-gzip':
46
+ case 'gzip':
47
+ passthrough = (0, node_zlib_1.createGunzip)();
48
+ break;
49
+ case 'x-deflate':
50
+ case 'deflate':
51
+ passthrough = (0, node_zlib_1.createInflate)();
52
+ break;
53
+ case 'x-deflate-raw':
54
+ case 'deflate-raw':
55
+ passthrough = (0, node_zlib_1.createInflateRaw)();
56
+ break;
57
+ case 'br':
58
+ passthrough = (0, node_zlib_1.createBrotliDecompress)();
59
+ break;
60
+ default:
61
+ passthrough = new node_stream_1.PassThrough();
61
62
  }
62
- function onAbort(e) {
63
+ return passthrough;
64
+ }
65
+ function onAbort(e) {
66
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
67
+ passthrough?.destroy(e);
68
+ deferred.reject(e);
69
+ }
70
+ const headersSerializer = fetchRequest.headersSerializer || utils_js_1.getHeadersObj;
71
+ const nodeHeaders = headersSerializer(fetchRequest.headers);
72
+ if (nodeHeaders['accept-encoding'] == null) {
73
+ nodeHeaders['accept-encoding'] = 'gzip, deflate, br';
74
+ }
75
+ const dispatcherReturn = dispatcher.dispatch({
76
+ origin: fetchRequest.parsedUrl.origin,
77
+ path: fetchRequest.parsedUrl.pathname,
78
+ query: Object.fromEntries(fetchRequest.parsedUrl.searchParams),
79
+ method: fetchRequest.method,
80
+ headers: nodeHeaders,
81
+ body,
82
+ }, {
83
+ onRequestStart(controller) {
84
+ abortListener = function abortListener() {
85
+ onAbort(fetchRequest['_signal']?.reason);
86
+ controller.abort(fetchRequest['_signal']?.reason);
87
+ };
88
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
89
+ },
90
+ onRequestUpgrade(_controller, statusCode, headers, socket) {
91
+ response = new Response_js_1.PonyfillResponse(socket, {
92
+ status: statusCode,
93
+ headers: headers,
94
+ url: fetchRequest.url,
95
+ });
96
+ deferred.resolve(response);
63
97
  fetchRequest['_signal']?.removeEventListener('abort', abortListener);
64
- passthrough?.destroy(e);
65
- reject(e);
66
- }
67
- const headersSerializer = fetchRequest.headersSerializer || utils_js_1.getHeadersObj;
68
- const nodeHeaders = headersSerializer(fetchRequest.headers);
69
- if (nodeHeaders['accept-encoding'] == null) {
70
- nodeHeaders['accept-encoding'] = 'gzip, deflate, br';
71
- }
72
- (fetchRequest.dispatcher || getGlobalDispatcher()).dispatch({
73
- origin: fetchRequest.parsedUrl.origin,
74
- path: fetchRequest.parsedUrl.pathname,
75
- query: Object.fromEntries(fetchRequest.parsedUrl.searchParams),
76
- method: fetchRequest.method,
77
- headers: nodeHeaders,
78
- body,
79
- }, {
80
- onRequestStart(controller) {
81
- abortListener = function abortListener() {
82
- controller.abort(fetchRequest['_signal']?.reason);
83
- onAbort(fetchRequest['_signal']?.reason);
84
- };
85
- fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
86
- },
87
- onRequestUpgrade(_controller, statusCode, headers, socket) {
88
- response = new Response_js_1.PonyfillResponse(socket, {
89
- status: statusCode,
90
- headers: headers,
91
- url: fetchRequest.url,
92
- });
93
- resolve(response);
94
- },
95
- onResponseStart(controller, statusCode, headers, statusMessage) {
96
- if (headers.location) {
97
- if (fetchRequest.redirect === 'error') {
98
- const redirectError = new Error('Redirects are not allowed');
99
- reject(redirectError);
100
- controller.resume();
101
- return;
102
- }
103
- if (fetchRequest.redirect === 'follow') {
104
- const redirectedUrl = new URL_js_1.PonyfillURL(headers.location, fetchRequest.parsedUrl || fetchRequest.url);
105
- const redirectResponse$ = fetchUndici(new Request_js_1.PonyfillRequest(redirectedUrl, fetchRequest));
106
- resolve(redirectResponse$.then(redirectResponse => {
107
- redirectResponse.redirected = true;
108
- return redirectResponse;
109
- }));
110
- controller.resume();
111
- return;
112
- }
98
+ },
99
+ onResponseStart(controller, statusCode, headers, statusMessage) {
100
+ if (headers.location) {
101
+ if (fetchRequest.redirect === 'error') {
102
+ const redirectError = new Error('Redirects are not allowed');
103
+ deferred.reject(redirectError);
104
+ controller.resume();
105
+ return;
113
106
  }
114
- passthrough = setPassthrough(headers['content-encoding']);
115
- resolve(new Response_js_1.PonyfillResponse(passthrough, {
116
- status: statusCode,
117
- statusText: statusMessage,
118
- headers: headers,
119
- url: fetchRequest.url,
120
- }));
121
- },
122
- onResponseData(_controller, chunk) {
123
- passthrough.write(chunk);
124
- },
125
- onResponseEnd(_controller, _trailers) {
126
- passthrough.end();
127
- fetchRequest['_signal']?.removeEventListener('abort', abortListener);
128
- },
129
- onResponseError(_controller, error) {
130
- onAbort(error);
131
- },
132
- // Old Undici support
133
- onConnect(abort) {
134
- abortListener = function abortListener() {
135
- abort(fetchRequest['_signal']?.reason);
136
- onAbort(fetchRequest['_signal']?.reason);
137
- };
138
- fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
139
- },
140
- onError(error) {
141
- onAbort(error);
142
- },
143
- // TODO: onUpgrade
144
- onHeaders(statusCode, headersBuf, _resume, statusText) {
145
- const headers = headersBuf.map(headerBuf => {
146
- const header = headerBuf
147
- .toString('utf-8')
148
- .split(/:\s(.+)/)
149
- .slice(0, 2);
150
- if (header[0] === 'content-encoding') {
151
- const contentEncoding = header[1];
152
- setPassthrough(contentEncoding);
153
- }
154
- return header;
155
- });
156
- passthrough ||= new node_stream_1.PassThrough();
157
- resolve(new Response_js_1.PonyfillResponse(passthrough, {
158
- status: statusCode,
159
- statusText,
160
- headers,
161
- url: fetchRequest.url,
162
- }));
163
- return true;
164
- },
165
- onData(chunk) {
166
- return passthrough.write(chunk);
167
- },
168
- onComplete() {
107
+ if (fetchRequest.redirect === 'follow') {
108
+ const redirectedUrl = new URL_js_1.PonyfillURL(headers.location, fetchRequest.parsedUrl || fetchRequest.url);
109
+ const redirectResponse$ = fetchUndici(new Request_js_1.PonyfillRequest(redirectedUrl, fetchRequest));
110
+ deferred.resolve(redirectResponse$.then(redirectResponse => {
111
+ redirectResponse.redirected = true;
112
+ return redirectResponse;
113
+ }));
114
+ controller.resume();
115
+ return;
116
+ }
117
+ }
118
+ passthrough = setPassthrough(headers['content-encoding']);
119
+ deferred.resolve(new Response_js_1.PonyfillResponse(passthrough, {
120
+ status: statusCode,
121
+ statusText: statusMessage,
122
+ headers: headers,
123
+ url: fetchRequest.url,
124
+ }));
125
+ },
126
+ onResponseData(controller, chunk) {
127
+ passthrough.write(chunk);
128
+ if (controller.reason) {
129
+ onAbort(controller.reason);
130
+ }
131
+ },
132
+ onResponseEnd(controller, _trailers) {
133
+ if (controller.reason) {
134
+ onAbort(controller.reason);
135
+ }
136
+ else {
169
137
  passthrough.end();
170
138
  fetchRequest['_signal']?.removeEventListener('abort', abortListener);
171
- },
172
- });
139
+ }
140
+ },
141
+ onResponseError(controller, error) {
142
+ onAbort(error || controller.reason);
143
+ },
144
+ // Old Undici support
145
+ onConnect(abort) {
146
+ abortListener = function abortListener() {
147
+ abort(fetchRequest['_signal']?.reason);
148
+ onAbort(fetchRequest['_signal']?.reason);
149
+ };
150
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
151
+ },
152
+ onError(error) {
153
+ onAbort(error);
154
+ },
155
+ // TODO: onUpgrade
156
+ onHeaders(statusCode, headersBuf, _resume, statusText) {
157
+ const headers = headersBuf.map(headerBuf => {
158
+ const header = headerBuf
159
+ .toString('utf-8')
160
+ .split(/:\s(.+)/)
161
+ .slice(0, 2);
162
+ if (header[0] === 'content-encoding') {
163
+ const contentEncoding = header[1];
164
+ setPassthrough(contentEncoding);
165
+ }
166
+ return header;
167
+ });
168
+ passthrough ||= new node_stream_1.PassThrough();
169
+ deferred.resolve(new Response_js_1.PonyfillResponse(passthrough, {
170
+ status: statusCode,
171
+ statusText,
172
+ headers,
173
+ url: fetchRequest.url,
174
+ }));
175
+ return true;
176
+ },
177
+ onData(chunk) {
178
+ return passthrough.write(chunk);
179
+ },
180
+ onComplete() {
181
+ passthrough.end();
182
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
183
+ },
173
184
  });
185
+ if (!dispatcherReturn) {
186
+ console.warn('Undici dispatcher returned false');
187
+ }
188
+ return deferred.promise;
174
189
  };
175
190
  }
package/esm/fetch.js CHANGED
@@ -61,7 +61,20 @@ function getNativeGlobalDispatcher() {
61
61
  function createFetchFn() {
62
62
  const libcurlModuleName = 'node-libcurl';
63
63
  const undiciModuleName = 'undici';
64
- return import(libcurlModuleName).then(libcurl => createFetchCurl(libcurl), () => import(undiciModuleName).then((undici) => createFetchUndici(() => undici.getGlobalDispatcher()), () => createFetchUndici(getNativeGlobalDispatcher)));
64
+ if (process.env.DEBUG) {
65
+ console.debug(`[@whatwg-node/node-fetch] - Trying to import ${libcurlModuleName} for fetch ponyfill`);
66
+ }
67
+ return import(libcurlModuleName).then(libcurl => createFetchCurl(libcurl), () => {
68
+ if (process.env.DEBUG) {
69
+ console.debug(`[@whatwg-node/node-fetch] - Failed to import ${libcurlModuleName}, trying ${undiciModuleName}`);
70
+ }
71
+ return import(undiciModuleName).then((undici) => createFetchUndici(() => undici.getGlobalDispatcher()), () => {
72
+ if (process.env.DEBUG) {
73
+ console.debug(`[@whatwg-node/node-fetch] - Failed to import ${undiciModuleName}, falling back to built-in undici in Node`);
74
+ }
75
+ return createFetchUndici(getNativeGlobalDispatcher);
76
+ });
77
+ });
65
78
  }
66
79
  function fetchNonHttp(fetchRequest) {
67
80
  if (fetchRequest.url.startsWith('data:')) {
@@ -5,168 +5,183 @@ import { fetchNodeHttp } from './fetchNodeHttp.js';
5
5
  import { PonyfillRequest } from './Request.js';
6
6
  import { PonyfillResponse } from './Response.js';
7
7
  import { PonyfillURL } from './URL.js';
8
- import { getHeadersObj, isNodeReadable } from './utils.js';
8
+ import { createDeferredPromise, getHeadersObj, isNodeReadable } from './utils.js';
9
9
  export function createFetchUndici(getGlobalDispatcher) {
10
10
  return function fetchUndici(fetchRequest) {
11
11
  const dispatcher = fetchRequest.dispatcher || getGlobalDispatcher();
12
12
  if (!dispatcher) {
13
+ if (process.env.DEBUG) {
14
+ console.debug('[@whatwg-node/node-fetch] - native undici dispatcher not available, falling back to node:http');
15
+ }
13
16
  return fetchNodeHttp(fetchRequest);
14
17
  }
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;
18
+ const deferred = createDeferredPromise();
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
+ isUint8Array(bodyInit) ||
28
+ bodyInit instanceof Readable) {
29
+ body = bodyInit;
30
+ }
31
+ else if (fetchRequest.body != null) {
32
+ if (isNodeReadable(fetchRequest.body?.readable)) {
33
+ body = fetchRequest.body.readable;
27
34
  }
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
+ else {
36
+ body = Readable.from(fetchRequest.body);
35
37
  }
36
38
  }
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;
39
+ }
40
+ function setPassthrough(contentEncoding) {
41
+ switch (contentEncoding) {
42
+ case 'x-gzip':
43
+ case 'gzip':
44
+ passthrough = createGunzip();
45
+ break;
46
+ case 'x-deflate':
47
+ case 'deflate':
48
+ passthrough = createInflate();
49
+ break;
50
+ case 'x-deflate-raw':
51
+ case 'deflate-raw':
52
+ passthrough = createInflateRaw();
53
+ break;
54
+ case 'br':
55
+ passthrough = createBrotliDecompress();
56
+ break;
57
+ default:
58
+ passthrough = new PassThrough();
58
59
  }
59
- function onAbort(e) {
60
+ return passthrough;
61
+ }
62
+ function onAbort(e) {
63
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
64
+ passthrough?.destroy(e);
65
+ deferred.reject(e);
66
+ }
67
+ const headersSerializer = fetchRequest.headersSerializer || getHeadersObj;
68
+ const nodeHeaders = headersSerializer(fetchRequest.headers);
69
+ if (nodeHeaders['accept-encoding'] == null) {
70
+ nodeHeaders['accept-encoding'] = 'gzip, deflate, br';
71
+ }
72
+ const dispatcherReturn = dispatcher.dispatch({
73
+ origin: fetchRequest.parsedUrl.origin,
74
+ path: fetchRequest.parsedUrl.pathname,
75
+ query: Object.fromEntries(fetchRequest.parsedUrl.searchParams),
76
+ method: fetchRequest.method,
77
+ headers: nodeHeaders,
78
+ body,
79
+ }, {
80
+ onRequestStart(controller) {
81
+ abortListener = function abortListener() {
82
+ onAbort(fetchRequest['_signal']?.reason);
83
+ controller.abort(fetchRequest['_signal']?.reason);
84
+ };
85
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
86
+ },
87
+ onRequestUpgrade(_controller, statusCode, headers, socket) {
88
+ response = new PonyfillResponse(socket, {
89
+ status: statusCode,
90
+ headers: headers,
91
+ url: fetchRequest.url,
92
+ });
93
+ deferred.resolve(response);
60
94
  fetchRequest['_signal']?.removeEventListener('abort', abortListener);
61
- passthrough?.destroy(e);
62
- reject(e);
63
- }
64
- const headersSerializer = fetchRequest.headersSerializer || getHeadersObj;
65
- const nodeHeaders = headersSerializer(fetchRequest.headers);
66
- if (nodeHeaders['accept-encoding'] == null) {
67
- nodeHeaders['accept-encoding'] = 'gzip, deflate, br';
68
- }
69
- (fetchRequest.dispatcher || getGlobalDispatcher()).dispatch({
70
- origin: fetchRequest.parsedUrl.origin,
71
- path: fetchRequest.parsedUrl.pathname,
72
- query: Object.fromEntries(fetchRequest.parsedUrl.searchParams),
73
- method: fetchRequest.method,
74
- headers: nodeHeaders,
75
- body,
76
- }, {
77
- onRequestStart(controller) {
78
- abortListener = function abortListener() {
79
- controller.abort(fetchRequest['_signal']?.reason);
80
- onAbort(fetchRequest['_signal']?.reason);
81
- };
82
- fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
83
- },
84
- onRequestUpgrade(_controller, statusCode, headers, socket) {
85
- response = new PonyfillResponse(socket, {
86
- status: statusCode,
87
- headers: headers,
88
- url: fetchRequest.url,
89
- });
90
- resolve(response);
91
- },
92
- onResponseStart(controller, statusCode, headers, statusMessage) {
93
- if (headers.location) {
94
- if (fetchRequest.redirect === 'error') {
95
- const redirectError = new Error('Redirects are not allowed');
96
- reject(redirectError);
97
- controller.resume();
98
- return;
99
- }
100
- if (fetchRequest.redirect === 'follow') {
101
- const redirectedUrl = new PonyfillURL(headers.location, fetchRequest.parsedUrl || fetchRequest.url);
102
- const redirectResponse$ = fetchUndici(new PonyfillRequest(redirectedUrl, fetchRequest));
103
- resolve(redirectResponse$.then(redirectResponse => {
104
- redirectResponse.redirected = true;
105
- return redirectResponse;
106
- }));
107
- controller.resume();
108
- return;
109
- }
95
+ },
96
+ onResponseStart(controller, statusCode, headers, statusMessage) {
97
+ if (headers.location) {
98
+ if (fetchRequest.redirect === 'error') {
99
+ const redirectError = new Error('Redirects are not allowed');
100
+ deferred.reject(redirectError);
101
+ controller.resume();
102
+ return;
110
103
  }
111
- passthrough = setPassthrough(headers['content-encoding']);
112
- resolve(new PonyfillResponse(passthrough, {
113
- status: statusCode,
114
- statusText: statusMessage,
115
- headers: headers,
116
- url: fetchRequest.url,
117
- }));
118
- },
119
- onResponseData(_controller, chunk) {
120
- passthrough.write(chunk);
121
- },
122
- onResponseEnd(_controller, _trailers) {
123
- passthrough.end();
124
- fetchRequest['_signal']?.removeEventListener('abort', abortListener);
125
- },
126
- onResponseError(_controller, error) {
127
- onAbort(error);
128
- },
129
- // Old Undici support
130
- onConnect(abort) {
131
- abortListener = function abortListener() {
132
- abort(fetchRequest['_signal']?.reason);
133
- onAbort(fetchRequest['_signal']?.reason);
134
- };
135
- fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
136
- },
137
- onError(error) {
138
- onAbort(error);
139
- },
140
- // TODO: onUpgrade
141
- onHeaders(statusCode, headersBuf, _resume, statusText) {
142
- const headers = headersBuf.map(headerBuf => {
143
- const header = headerBuf
144
- .toString('utf-8')
145
- .split(/:\s(.+)/)
146
- .slice(0, 2);
147
- if (header[0] === 'content-encoding') {
148
- const contentEncoding = header[1];
149
- setPassthrough(contentEncoding);
150
- }
151
- return header;
152
- });
153
- passthrough ||= new PassThrough();
154
- resolve(new PonyfillResponse(passthrough, {
155
- status: statusCode,
156
- statusText,
157
- headers,
158
- url: fetchRequest.url,
159
- }));
160
- return true;
161
- },
162
- onData(chunk) {
163
- return passthrough.write(chunk);
164
- },
165
- onComplete() {
104
+ if (fetchRequest.redirect === 'follow') {
105
+ const redirectedUrl = new PonyfillURL(headers.location, fetchRequest.parsedUrl || fetchRequest.url);
106
+ const redirectResponse$ = fetchUndici(new PonyfillRequest(redirectedUrl, fetchRequest));
107
+ deferred.resolve(redirectResponse$.then(redirectResponse => {
108
+ redirectResponse.redirected = true;
109
+ return redirectResponse;
110
+ }));
111
+ controller.resume();
112
+ return;
113
+ }
114
+ }
115
+ passthrough = setPassthrough(headers['content-encoding']);
116
+ deferred.resolve(new PonyfillResponse(passthrough, {
117
+ status: statusCode,
118
+ statusText: statusMessage,
119
+ headers: headers,
120
+ url: fetchRequest.url,
121
+ }));
122
+ },
123
+ onResponseData(controller, chunk) {
124
+ passthrough.write(chunk);
125
+ if (controller.reason) {
126
+ onAbort(controller.reason);
127
+ }
128
+ },
129
+ onResponseEnd(controller, _trailers) {
130
+ if (controller.reason) {
131
+ onAbort(controller.reason);
132
+ }
133
+ else {
166
134
  passthrough.end();
167
135
  fetchRequest['_signal']?.removeEventListener('abort', abortListener);
168
- },
169
- });
136
+ }
137
+ },
138
+ onResponseError(controller, error) {
139
+ onAbort(error || controller.reason);
140
+ },
141
+ // Old Undici support
142
+ onConnect(abort) {
143
+ abortListener = function abortListener() {
144
+ abort(fetchRequest['_signal']?.reason);
145
+ onAbort(fetchRequest['_signal']?.reason);
146
+ };
147
+ fetchRequest['_signal']?.addEventListener('abort', abortListener, { once: true });
148
+ },
149
+ onError(error) {
150
+ onAbort(error);
151
+ },
152
+ // TODO: onUpgrade
153
+ onHeaders(statusCode, headersBuf, _resume, statusText) {
154
+ const headers = headersBuf.map(headerBuf => {
155
+ const header = headerBuf
156
+ .toString('utf-8')
157
+ .split(/:\s(.+)/)
158
+ .slice(0, 2);
159
+ if (header[0] === 'content-encoding') {
160
+ const contentEncoding = header[1];
161
+ setPassthrough(contentEncoding);
162
+ }
163
+ return header;
164
+ });
165
+ passthrough ||= new PassThrough();
166
+ deferred.resolve(new PonyfillResponse(passthrough, {
167
+ status: statusCode,
168
+ statusText,
169
+ headers,
170
+ url: fetchRequest.url,
171
+ }));
172
+ return true;
173
+ },
174
+ onData(chunk) {
175
+ return passthrough.write(chunk);
176
+ },
177
+ onComplete() {
178
+ passthrough.end();
179
+ fetchRequest['_signal']?.removeEventListener('abort', abortListener);
180
+ },
170
181
  });
182
+ if (!dispatcherReturn) {
183
+ console.warn('Undici dispatcher returned false');
184
+ }
185
+ return deferred.promise;
171
186
  };
172
187
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatwg-node/node-fetch",
3
- "version": "0.7.8-alpha-20250122141536-187117d0e771637bc659740c29e4b57339e20311",
3
+ "version": "0.7.8-alpha-20250122150621-99aa3b02dabf84434a687202da321ea8807e453d",
4
4
  "description": "Fetch API implementation for Node",
5
5
  "sideEffects": false,
6
6
  "dependencies": {
@@ -6,7 +6,7 @@ export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
6
6
  export declare function isNodeReadable(obj: any): obj is Readable;
7
7
  export interface DeferredPromise<T = void> {
8
8
  promise: Promise<T>;
9
- resolve: (value: T) => void;
9
+ resolve: (value: T | PromiseLike<T>) => void;
10
10
  reject: (reason: any) => void;
11
11
  }
12
12
  export declare function createDeferredPromise<T = void>(): DeferredPromise<T>;
@@ -6,7 +6,7 @@ export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
6
6
  export declare function isNodeReadable(obj: any): obj is Readable;
7
7
  export interface DeferredPromise<T = void> {
8
8
  promise: Promise<T>;
9
- resolve: (value: T) => void;
9
+ resolve: (value: T | PromiseLike<T>) => void;
10
10
  reject: (reason: any) => void;
11
11
  }
12
12
  export declare function createDeferredPromise<T = void>(): DeferredPromise<T>;