@whatwg-node/node-fetch 0.7.23-alpha-20250726003115-27dea3e7c5dae7285bf9c837cce54f387e269df2 → 0.7.23-alpha-20250726021227-e4372202f654829422254520007390cd597e7720
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/Body.js +27 -0
- package/cjs/Request.js +0 -2
- package/cjs/fetchCurl.js +10 -6
- package/cjs/fetchNodeHttp.js +8 -4
- package/cjs/utils.js +44 -0
- package/esm/Body.js +29 -2
- package/esm/Request.js +0 -2
- package/esm/fetchCurl.js +11 -7
- package/esm/fetchNodeHttp.js +10 -6
- package/esm/utils.js +43 -0
- package/package.json +1 -1
- package/typings/Body.d.cts +1 -0
- package/typings/Body.d.ts +1 -0
- package/typings/Request.d.cts +0 -1
- package/typings/Request.d.ts +0 -1
- package/typings/utils.d.cts +6 -0
- package/typings/utils.d.ts +6 -0
package/cjs/Body.js
CHANGED
|
@@ -27,21 +27,45 @@ class PonyfillBody {
|
|
|
27
27
|
bodyUsed = false;
|
|
28
28
|
contentType = null;
|
|
29
29
|
contentLength = null;
|
|
30
|
+
_signal = null;
|
|
30
31
|
constructor(bodyInit, options = {}) {
|
|
31
32
|
this.bodyInit = bodyInit;
|
|
32
33
|
this.options = options;
|
|
34
|
+
this._signal = options.signal || null;
|
|
33
35
|
const { bodyFactory, contentType, contentLength, bodyType, buffer } = processBodyInit(bodyInit);
|
|
34
36
|
this._bodyFactory = bodyFactory;
|
|
35
37
|
this.contentType = contentType;
|
|
36
38
|
this.contentLength = contentLength;
|
|
37
39
|
this.bodyType = bodyType;
|
|
38
40
|
this._buffer = buffer;
|
|
41
|
+
if (!buffer) {
|
|
42
|
+
this._chunks = this._doCollectChunksFromReadableJob();
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
bodyType;
|
|
41
46
|
_bodyFactory = () => null;
|
|
42
47
|
_generatedBody = null;
|
|
43
48
|
_buffer;
|
|
44
49
|
generateBody() {
|
|
50
|
+
if (!this._buffer && this._chunks) {
|
|
51
|
+
if ((0, promise_helpers_1.isPromise)(this._chunks)) {
|
|
52
|
+
return new ReadableStream_js_1.PonyfillReadableStream({
|
|
53
|
+
start: async (controller) => {
|
|
54
|
+
const chunks = await this._chunks;
|
|
55
|
+
if (!chunks?.length) {
|
|
56
|
+
this._buffer = node_buffer_1.Buffer.alloc(0);
|
|
57
|
+
controller.close();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this._buffer = node_buffer_1.Buffer.concat(chunks);
|
|
61
|
+
for (const chunk of chunks) {
|
|
62
|
+
controller.enqueue(chunk);
|
|
63
|
+
}
|
|
64
|
+
controller.close();
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
45
69
|
if (this._generatedBody?.readable?.destroyed && this._buffer) {
|
|
46
70
|
this._generatedBody.readable = node_stream_1.Readable.from(this._buffer);
|
|
47
71
|
}
|
|
@@ -215,6 +239,9 @@ class PonyfillBody {
|
|
|
215
239
|
limits: formDataLimits,
|
|
216
240
|
defCharset: 'utf-8',
|
|
217
241
|
});
|
|
242
|
+
if (this._signal) {
|
|
243
|
+
(0, node_stream_1.addAbortSignal)(this._signal, bb);
|
|
244
|
+
}
|
|
218
245
|
let completed = false;
|
|
219
246
|
const complete = (err) => {
|
|
220
247
|
if (completed)
|
package/cjs/Request.js
CHANGED
|
@@ -76,7 +76,6 @@ class PonyfillRequest extends Body_js_1.PonyfillBody {
|
|
|
76
76
|
this.agent = requestInit.agent;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
this._signal = requestInit?.signal || undefined;
|
|
80
79
|
}
|
|
81
80
|
headersSerializer;
|
|
82
81
|
cache;
|
|
@@ -92,7 +91,6 @@ class PonyfillRequest extends Body_js_1.PonyfillBody {
|
|
|
92
91
|
referrer;
|
|
93
92
|
referrerPolicy;
|
|
94
93
|
_url;
|
|
95
|
-
_signal;
|
|
96
94
|
get signal() {
|
|
97
95
|
this._signal ||= new AbortController().signal;
|
|
98
96
|
return this._signal;
|
package/cjs/fetchCurl.js
CHANGED
|
@@ -22,7 +22,7 @@ function fetchCurl(fetchRequest) {
|
|
|
22
22
|
}
|
|
23
23
|
curlHandle.enable(CurlFeature.StreamResponse);
|
|
24
24
|
let signal;
|
|
25
|
-
if (fetchRequest._signal
|
|
25
|
+
if (fetchRequest._signal == null) {
|
|
26
26
|
signal = undefined;
|
|
27
27
|
}
|
|
28
28
|
else if (fetchRequest._signal) {
|
|
@@ -104,8 +104,12 @@ function fetchCurl(fetchRequest) {
|
|
|
104
104
|
}
|
|
105
105
|
});
|
|
106
106
|
curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
|
|
107
|
-
const
|
|
108
|
-
|
|
107
|
+
const passThrough = new node_stream_1.PassThrough();
|
|
108
|
+
(0, utils_js_1.pipeThrough)({
|
|
109
|
+
src: stream,
|
|
110
|
+
dest: passThrough,
|
|
111
|
+
signal,
|
|
112
|
+
onError: deferredPromise.reject,
|
|
109
113
|
});
|
|
110
114
|
const headersFlat = headersBuf
|
|
111
115
|
.toString('utf8')
|
|
@@ -118,7 +122,7 @@ function fetchCurl(fetchRequest) {
|
|
|
118
122
|
if (!stream.destroyed) {
|
|
119
123
|
stream.resume();
|
|
120
124
|
}
|
|
121
|
-
|
|
125
|
+
passThrough.destroy();
|
|
122
126
|
deferredPromise.reject(new Error('redirect is not allowed'));
|
|
123
127
|
}
|
|
124
128
|
return true;
|
|
@@ -126,14 +130,14 @@ function fetchCurl(fetchRequest) {
|
|
|
126
130
|
return false;
|
|
127
131
|
});
|
|
128
132
|
const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
|
|
129
|
-
const ponyfillResponse = new Response_js_1.PonyfillResponse(
|
|
133
|
+
const ponyfillResponse = new Response_js_1.PonyfillResponse(passThrough, {
|
|
130
134
|
status,
|
|
131
135
|
headers: headersInit,
|
|
132
136
|
url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
|
|
133
137
|
redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
|
|
134
138
|
});
|
|
135
139
|
deferredPromise.resolve(ponyfillResponse);
|
|
136
|
-
streamResolved =
|
|
140
|
+
streamResolved = passThrough;
|
|
137
141
|
});
|
|
138
142
|
setImmediate(() => {
|
|
139
143
|
curlHandle.perform();
|
package/cjs/fetchNodeHttp.js
CHANGED
|
@@ -92,10 +92,14 @@ function fetchNodeHttp(fetchRequest) {
|
|
|
92
92
|
return;
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
outputStream
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
if (outputStream != null) {
|
|
96
|
+
(0, utils_js_1.pipeThrough)({
|
|
97
|
+
src: nodeResponse,
|
|
98
|
+
dest: outputStream,
|
|
99
|
+
signal,
|
|
100
|
+
onError: reject,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
99
103
|
const statusCode = nodeResponse.statusCode || 200;
|
|
100
104
|
let statusText = nodeResponse.statusMessage || node_http_1.STATUS_CODES[statusCode];
|
|
101
105
|
if (statusText == null) {
|
package/cjs/utils.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.isArrayBufferView = isArrayBufferView;
|
|
|
7
7
|
exports.isNodeReadable = isNodeReadable;
|
|
8
8
|
exports.isIterable = isIterable;
|
|
9
9
|
exports.shouldRedirect = shouldRedirect;
|
|
10
|
+
exports.pipeThrough = pipeThrough;
|
|
10
11
|
exports.endStream = endStream;
|
|
11
12
|
exports.safeWrite = safeWrite;
|
|
12
13
|
const node_events_1 = require("node:events");
|
|
@@ -48,6 +49,42 @@ function isIterable(value) {
|
|
|
48
49
|
function shouldRedirect(status) {
|
|
49
50
|
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
50
51
|
}
|
|
52
|
+
function pipeThrough({ src, dest, signal, onError, }) {
|
|
53
|
+
if (onError) {
|
|
54
|
+
// listen for errors on the destination stream if necessary. if the readable
|
|
55
|
+
// stream (src) emits an error, the writable destination (dest) will be
|
|
56
|
+
// destroyed with that error (see below)
|
|
57
|
+
dest.once('error', onError);
|
|
58
|
+
}
|
|
59
|
+
src.once('error', (e) => {
|
|
60
|
+
// if the readable stream (src) emits an error during pipe, the writable
|
|
61
|
+
// destination (dest) is not closed automatically. that needs to be
|
|
62
|
+
// done manually. the readable stream is closed when error is emitted,
|
|
63
|
+
// so only the writable destination needs to be destroyed
|
|
64
|
+
dest.destroy(e);
|
|
65
|
+
});
|
|
66
|
+
if (signal) {
|
|
67
|
+
// this is faster than `import('node:signal').addAbortSignal(signal, src)`
|
|
68
|
+
const srcRef = new WeakRef(src);
|
|
69
|
+
const signalRef = new WeakRef(signal);
|
|
70
|
+
function cleanup() {
|
|
71
|
+
signalRef.deref()?.removeEventListener('abort', onAbort);
|
|
72
|
+
srcRef.deref()?.removeListener('end', cleanup);
|
|
73
|
+
srcRef.deref()?.removeListener('error', cleanup);
|
|
74
|
+
srcRef.deref()?.removeListener('close', cleanup);
|
|
75
|
+
}
|
|
76
|
+
function onAbort() {
|
|
77
|
+
srcRef.deref()?.destroy(new AbortError());
|
|
78
|
+
cleanup();
|
|
79
|
+
}
|
|
80
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
81
|
+
// this is faster than `import('node:signal').finished(src, cleanup)`
|
|
82
|
+
src.once('end', cleanup);
|
|
83
|
+
src.once('error', cleanup);
|
|
84
|
+
src.once('close', cleanup);
|
|
85
|
+
}
|
|
86
|
+
src.pipe(dest, { end: true /* already default */ });
|
|
87
|
+
}
|
|
51
88
|
function endStream(stream) {
|
|
52
89
|
// @ts-expect-error Avoid arguments adaptor trampoline https://v8.dev/blog/adaptor-frame
|
|
53
90
|
return stream.end(null, null, null);
|
|
@@ -58,3 +95,10 @@ function safeWrite(chunk, stream) {
|
|
|
58
95
|
return (0, node_events_1.once)(stream, 'drain');
|
|
59
96
|
}
|
|
60
97
|
}
|
|
98
|
+
// https://github.com/nodejs/node/blob/f692878dec6354c0a82241f224906981861bc840/lib/internal/errors.js#L961-L973
|
|
99
|
+
class AbortError extends Error {
|
|
100
|
+
constructor(message = 'The operation was aborted', options = undefined) {
|
|
101
|
+
super(message, options);
|
|
102
|
+
this.name = 'AbortError';
|
|
103
|
+
}
|
|
104
|
+
}
|
package/esm/Body.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
2
|
import { Buffer } from 'node:buffer';
|
|
3
|
-
import { Readable } from 'node:stream';
|
|
3
|
+
import { addAbortSignal, Readable } from 'node:stream';
|
|
4
4
|
import { Busboy } from '@fastify/busboy';
|
|
5
|
-
import { handleMaybePromise } from '@whatwg-node/promise-helpers';
|
|
5
|
+
import { handleMaybePromise, isPromise } from '@whatwg-node/promise-helpers';
|
|
6
6
|
import { hasArrayBufferMethod, hasBufferMethod, hasBytesMethod, PonyfillBlob } from './Blob.js';
|
|
7
7
|
import { PonyfillFile } from './File.js';
|
|
8
8
|
import { getStreamFromFormData, PonyfillFormData } from './FormData.js';
|
|
@@ -24,21 +24,45 @@ export class PonyfillBody {
|
|
|
24
24
|
bodyUsed = false;
|
|
25
25
|
contentType = null;
|
|
26
26
|
contentLength = null;
|
|
27
|
+
_signal = null;
|
|
27
28
|
constructor(bodyInit, options = {}) {
|
|
28
29
|
this.bodyInit = bodyInit;
|
|
29
30
|
this.options = options;
|
|
31
|
+
this._signal = options.signal || null;
|
|
30
32
|
const { bodyFactory, contentType, contentLength, bodyType, buffer } = processBodyInit(bodyInit);
|
|
31
33
|
this._bodyFactory = bodyFactory;
|
|
32
34
|
this.contentType = contentType;
|
|
33
35
|
this.contentLength = contentLength;
|
|
34
36
|
this.bodyType = bodyType;
|
|
35
37
|
this._buffer = buffer;
|
|
38
|
+
if (!buffer) {
|
|
39
|
+
this._chunks = this._doCollectChunksFromReadableJob();
|
|
40
|
+
}
|
|
36
41
|
}
|
|
37
42
|
bodyType;
|
|
38
43
|
_bodyFactory = () => null;
|
|
39
44
|
_generatedBody = null;
|
|
40
45
|
_buffer;
|
|
41
46
|
generateBody() {
|
|
47
|
+
if (!this._buffer && this._chunks) {
|
|
48
|
+
if (isPromise(this._chunks)) {
|
|
49
|
+
return new PonyfillReadableStream({
|
|
50
|
+
start: async (controller) => {
|
|
51
|
+
const chunks = await this._chunks;
|
|
52
|
+
if (!chunks?.length) {
|
|
53
|
+
this._buffer = Buffer.alloc(0);
|
|
54
|
+
controller.close();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this._buffer = Buffer.concat(chunks);
|
|
58
|
+
for (const chunk of chunks) {
|
|
59
|
+
controller.enqueue(chunk);
|
|
60
|
+
}
|
|
61
|
+
controller.close();
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
42
66
|
if (this._generatedBody?.readable?.destroyed && this._buffer) {
|
|
43
67
|
this._generatedBody.readable = Readable.from(this._buffer);
|
|
44
68
|
}
|
|
@@ -212,6 +236,9 @@ export class PonyfillBody {
|
|
|
212
236
|
limits: formDataLimits,
|
|
213
237
|
defCharset: 'utf-8',
|
|
214
238
|
});
|
|
239
|
+
if (this._signal) {
|
|
240
|
+
addAbortSignal(this._signal, bb);
|
|
241
|
+
}
|
|
215
242
|
let completed = false;
|
|
216
243
|
const complete = (err) => {
|
|
217
244
|
if (completed)
|
package/esm/Request.js
CHANGED
|
@@ -73,7 +73,6 @@ export class PonyfillRequest extends PonyfillBody {
|
|
|
73
73
|
this.agent = requestInit.agent;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
this._signal = requestInit?.signal || undefined;
|
|
77
76
|
}
|
|
78
77
|
headersSerializer;
|
|
79
78
|
cache;
|
|
@@ -89,7 +88,6 @@ export class PonyfillRequest extends PonyfillBody {
|
|
|
89
88
|
referrer;
|
|
90
89
|
referrerPolicy;
|
|
91
90
|
_url;
|
|
92
|
-
_signal;
|
|
93
91
|
get signal() {
|
|
94
92
|
this._signal ||= new AbortController().signal;
|
|
95
93
|
return this._signal;
|
package/esm/fetchCurl.js
CHANGED
|
@@ -2,7 +2,7 @@ import { PassThrough, Readable } from 'node:stream';
|
|
|
2
2
|
import { rootCertificates } from 'node:tls';
|
|
3
3
|
import { createDeferredPromise } from '@whatwg-node/promise-helpers';
|
|
4
4
|
import { PonyfillResponse } from './Response.js';
|
|
5
|
-
import { defaultHeadersSerializer, isNodeReadable, shouldRedirect } from './utils.js';
|
|
5
|
+
import { defaultHeadersSerializer, isNodeReadable, pipeThrough, shouldRedirect } from './utils.js';
|
|
6
6
|
export function fetchCurl(fetchRequest) {
|
|
7
7
|
const { Curl, CurlFeature, CurlPause, CurlProgressFunc } = globalThis['libcurl'];
|
|
8
8
|
const curlHandle = new Curl();
|
|
@@ -19,7 +19,7 @@ export function fetchCurl(fetchRequest) {
|
|
|
19
19
|
}
|
|
20
20
|
curlHandle.enable(CurlFeature.StreamResponse);
|
|
21
21
|
let signal;
|
|
22
|
-
if (fetchRequest._signal
|
|
22
|
+
if (fetchRequest._signal == null) {
|
|
23
23
|
signal = undefined;
|
|
24
24
|
}
|
|
25
25
|
else if (fetchRequest._signal) {
|
|
@@ -101,8 +101,12 @@ export function fetchCurl(fetchRequest) {
|
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
103
|
curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
|
|
104
|
-
const
|
|
105
|
-
|
|
104
|
+
const passThrough = new PassThrough();
|
|
105
|
+
pipeThrough({
|
|
106
|
+
src: stream,
|
|
107
|
+
dest: passThrough,
|
|
108
|
+
signal,
|
|
109
|
+
onError: deferredPromise.reject,
|
|
106
110
|
});
|
|
107
111
|
const headersFlat = headersBuf
|
|
108
112
|
.toString('utf8')
|
|
@@ -115,7 +119,7 @@ export function fetchCurl(fetchRequest) {
|
|
|
115
119
|
if (!stream.destroyed) {
|
|
116
120
|
stream.resume();
|
|
117
121
|
}
|
|
118
|
-
|
|
122
|
+
passThrough.destroy();
|
|
119
123
|
deferredPromise.reject(new Error('redirect is not allowed'));
|
|
120
124
|
}
|
|
121
125
|
return true;
|
|
@@ -123,14 +127,14 @@ export function fetchCurl(fetchRequest) {
|
|
|
123
127
|
return false;
|
|
124
128
|
});
|
|
125
129
|
const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
|
|
126
|
-
const ponyfillResponse = new PonyfillResponse(
|
|
130
|
+
const ponyfillResponse = new PonyfillResponse(passThrough, {
|
|
127
131
|
status,
|
|
128
132
|
headers: headersInit,
|
|
129
133
|
url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
|
|
130
134
|
redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
|
|
131
135
|
});
|
|
132
136
|
deferredPromise.resolve(ponyfillResponse);
|
|
133
|
-
streamResolved =
|
|
137
|
+
streamResolved = passThrough;
|
|
134
138
|
});
|
|
135
139
|
setImmediate(() => {
|
|
136
140
|
curlHandle.perform();
|
package/esm/fetchNodeHttp.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { request as httpRequest, STATUS_CODES } from 'node:http';
|
|
2
2
|
import { request as httpsRequest } from 'node:https';
|
|
3
|
-
import {
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
4
|
import { createBrotliDecompress, createGunzip, createInflate, createInflateRaw } from 'node:zlib';
|
|
5
5
|
import { handleMaybePromise } from '@whatwg-node/promise-helpers';
|
|
6
6
|
import { PonyfillRequest } from './Request.js';
|
|
7
7
|
import { PonyfillResponse } from './Response.js';
|
|
8
8
|
import { PonyfillURL } from './URL.js';
|
|
9
|
-
import { endStream, getHeadersObj, isNodeReadable, safeWrite, shouldRedirect } from './utils.js';
|
|
9
|
+
import { endStream, getHeadersObj, isNodeReadable, pipeThrough, safeWrite, shouldRedirect, } from './utils.js';
|
|
10
10
|
function getRequestFnForProtocol(url) {
|
|
11
11
|
if (url.startsWith('http:')) {
|
|
12
12
|
return httpRequest;
|
|
@@ -89,10 +89,14 @@ export function fetchNodeHttp(fetchRequest) {
|
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
outputStream
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
if (outputStream != null) {
|
|
93
|
+
pipeThrough({
|
|
94
|
+
src: nodeResponse,
|
|
95
|
+
dest: outputStream,
|
|
96
|
+
signal,
|
|
97
|
+
onError: reject,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
96
100
|
const statusCode = nodeResponse.statusCode || 200;
|
|
97
101
|
let statusText = nodeResponse.statusMessage || STATUS_CODES[statusCode];
|
|
98
102
|
if (statusText == null) {
|
package/esm/utils.js
CHANGED
|
@@ -36,6 +36,42 @@ export function isIterable(value) {
|
|
|
36
36
|
export function shouldRedirect(status) {
|
|
37
37
|
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
38
38
|
}
|
|
39
|
+
export function pipeThrough({ src, dest, signal, onError, }) {
|
|
40
|
+
if (onError) {
|
|
41
|
+
// listen for errors on the destination stream if necessary. if the readable
|
|
42
|
+
// stream (src) emits an error, the writable destination (dest) will be
|
|
43
|
+
// destroyed with that error (see below)
|
|
44
|
+
dest.once('error', onError);
|
|
45
|
+
}
|
|
46
|
+
src.once('error', (e) => {
|
|
47
|
+
// if the readable stream (src) emits an error during pipe, the writable
|
|
48
|
+
// destination (dest) is not closed automatically. that needs to be
|
|
49
|
+
// done manually. the readable stream is closed when error is emitted,
|
|
50
|
+
// so only the writable destination needs to be destroyed
|
|
51
|
+
dest.destroy(e);
|
|
52
|
+
});
|
|
53
|
+
if (signal) {
|
|
54
|
+
// this is faster than `import('node:signal').addAbortSignal(signal, src)`
|
|
55
|
+
const srcRef = new WeakRef(src);
|
|
56
|
+
const signalRef = new WeakRef(signal);
|
|
57
|
+
function cleanup() {
|
|
58
|
+
signalRef.deref()?.removeEventListener('abort', onAbort);
|
|
59
|
+
srcRef.deref()?.removeListener('end', cleanup);
|
|
60
|
+
srcRef.deref()?.removeListener('error', cleanup);
|
|
61
|
+
srcRef.deref()?.removeListener('close', cleanup);
|
|
62
|
+
}
|
|
63
|
+
function onAbort() {
|
|
64
|
+
srcRef.deref()?.destroy(new AbortError());
|
|
65
|
+
cleanup();
|
|
66
|
+
}
|
|
67
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
68
|
+
// this is faster than `import('node:signal').finished(src, cleanup)`
|
|
69
|
+
src.once('end', cleanup);
|
|
70
|
+
src.once('error', cleanup);
|
|
71
|
+
src.once('close', cleanup);
|
|
72
|
+
}
|
|
73
|
+
src.pipe(dest, { end: true /* already default */ });
|
|
74
|
+
}
|
|
39
75
|
export function endStream(stream) {
|
|
40
76
|
// @ts-expect-error Avoid arguments adaptor trampoline https://v8.dev/blog/adaptor-frame
|
|
41
77
|
return stream.end(null, null, null);
|
|
@@ -46,3 +82,10 @@ export function safeWrite(chunk, stream) {
|
|
|
46
82
|
return once(stream, 'drain');
|
|
47
83
|
}
|
|
48
84
|
}
|
|
85
|
+
// https://github.com/nodejs/node/blob/f692878dec6354c0a82241f224906981861bc840/lib/internal/errors.js#L961-L973
|
|
86
|
+
class AbortError extends Error {
|
|
87
|
+
constructor(message = 'The operation was aborted', options = undefined) {
|
|
88
|
+
super(message, options);
|
|
89
|
+
this.name = 'AbortError';
|
|
90
|
+
}
|
|
91
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@whatwg-node/node-fetch",
|
|
3
|
-
"version": "0.7.23-alpha-
|
|
3
|
+
"version": "0.7.23-alpha-20250726021227-e4372202f654829422254520007390cd597e7720",
|
|
4
4
|
"description": "Fetch API implementation for Node",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"dependencies": {
|
package/typings/Body.d.cts
CHANGED
|
@@ -24,6 +24,7 @@ export declare class PonyfillBody<TJSON = any> implements Body {
|
|
|
24
24
|
bodyUsed: boolean;
|
|
25
25
|
contentType: string | null;
|
|
26
26
|
contentLength: number | null;
|
|
27
|
+
_signal?: AbortSignal | null;
|
|
27
28
|
constructor(bodyInit: BodyPonyfillInit | null, options?: PonyfillBodyOptions);
|
|
28
29
|
private bodyType?;
|
|
29
30
|
private _bodyFactory;
|
package/typings/Body.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare class PonyfillBody<TJSON = any> implements Body {
|
|
|
24
24
|
bodyUsed: boolean;
|
|
25
25
|
contentType: string | null;
|
|
26
26
|
contentLength: number | null;
|
|
27
|
+
_signal?: AbortSignal | null;
|
|
27
28
|
constructor(bodyInit: BodyPonyfillInit | null, options?: PonyfillBodyOptions);
|
|
28
29
|
private bodyType?;
|
|
29
30
|
private _bodyFactory;
|
package/typings/Request.d.cts
CHANGED
|
@@ -26,7 +26,6 @@ export declare class PonyfillRequest<TJSON = any> extends PonyfillBody<TJSON> im
|
|
|
26
26
|
referrer: string;
|
|
27
27
|
referrerPolicy: ReferrerPolicy;
|
|
28
28
|
_url: string | undefined;
|
|
29
|
-
_signal: AbortSignal | undefined;
|
|
30
29
|
get signal(): AbortSignal;
|
|
31
30
|
get url(): string;
|
|
32
31
|
_parsedUrl: URL | undefined;
|
package/typings/Request.d.ts
CHANGED
|
@@ -26,7 +26,6 @@ export declare class PonyfillRequest<TJSON = any> extends PonyfillBody<TJSON> im
|
|
|
26
26
|
referrer: string;
|
|
27
27
|
referrerPolicy: ReferrerPolicy;
|
|
28
28
|
_url: string | undefined;
|
|
29
|
-
_signal: AbortSignal | undefined;
|
|
30
29
|
get signal(): AbortSignal;
|
|
31
30
|
get url(): string;
|
|
32
31
|
_parsedUrl: URL | undefined;
|
package/typings/utils.d.cts
CHANGED
|
@@ -6,6 +6,12 @@ export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
|
|
|
6
6
|
export declare function isNodeReadable(obj: any): obj is Readable;
|
|
7
7
|
export declare function isIterable(value: any): value is Iterable<unknown>;
|
|
8
8
|
export declare function shouldRedirect(status?: number): boolean;
|
|
9
|
+
export declare function pipeThrough({ src, dest, signal, onError, }: {
|
|
10
|
+
src: Readable;
|
|
11
|
+
dest: Writable;
|
|
12
|
+
signal?: AbortSignal | undefined;
|
|
13
|
+
onError?: ((e: Error) => void) | undefined;
|
|
14
|
+
}): void;
|
|
9
15
|
export declare function endStream(stream: {
|
|
10
16
|
end: () => void;
|
|
11
17
|
}): void;
|
package/typings/utils.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
|
|
|
6
6
|
export declare function isNodeReadable(obj: any): obj is Readable;
|
|
7
7
|
export declare function isIterable(value: any): value is Iterable<unknown>;
|
|
8
8
|
export declare function shouldRedirect(status?: number): boolean;
|
|
9
|
+
export declare function pipeThrough({ src, dest, signal, onError, }: {
|
|
10
|
+
src: Readable;
|
|
11
|
+
dest: Writable;
|
|
12
|
+
signal?: AbortSignal | undefined;
|
|
13
|
+
onError?: ((e: Error) => void) | undefined;
|
|
14
|
+
}): void;
|
|
9
15
|
export declare function endStream(stream: {
|
|
10
16
|
end: () => void;
|
|
11
17
|
}): void;
|