@whatwg-node/node-fetch 0.7.22-alpha-20250710160716-6df7209d12299dba404ac539d834654be5d43990 → 0.7.23-alpha-20250725190806-5df0ede70a22656416fd7a0f626f8d5ba8238197

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 CHANGED
@@ -457,8 +457,10 @@ function processBodyInit(bodyInit, signal) {
457
457
  };
458
458
  }
459
459
  if (bodyInit instanceof node_http_1.IncomingMessage) {
460
- const passThrough = (0, utils_js_1.wrapIncomingMessageWithPassthrough)({
461
- incomingMessage: bodyInit,
460
+ const passThrough = new node_stream_1.PassThrough();
461
+ (0, utils_js_1.pipeThrough)({
462
+ src: bodyInit,
463
+ dest: passThrough,
462
464
  signal,
463
465
  });
464
466
  return {
package/cjs/fetchCurl.js CHANGED
@@ -107,8 +107,10 @@ function fetchCurl(fetchRequest) {
107
107
  }
108
108
  });
109
109
  curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
110
- const outputStream = (0, utils_js_1.wrapIncomingMessageWithPassthrough)({
111
- incomingMessage: stream,
110
+ const passThrough = new node_stream_1.PassThrough();
111
+ (0, utils_js_1.pipeThrough)({
112
+ src: stream,
113
+ dest: passThrough,
112
114
  signal,
113
115
  onError: deferredPromise.reject,
114
116
  });
@@ -123,7 +125,7 @@ function fetchCurl(fetchRequest) {
123
125
  if (!stream.destroyed) {
124
126
  stream.resume();
125
127
  }
126
- outputStream.destroy();
128
+ passThrough.destroy();
127
129
  deferredPromise.reject(new Error('redirect is not allowed'));
128
130
  }
129
131
  return true;
@@ -131,14 +133,14 @@ function fetchCurl(fetchRequest) {
131
133
  return false;
132
134
  });
133
135
  const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
134
- const ponyfillResponse = new Response_js_1.PonyfillResponse(outputStream, {
136
+ const ponyfillResponse = new Response_js_1.PonyfillResponse(passThrough, {
135
137
  status,
136
138
  headers: headersInit,
137
139
  url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
138
140
  redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
139
141
  });
140
142
  deferredPromise.resolve(ponyfillResponse);
141
- streamResolved = outputStream;
143
+ streamResolved = passThrough;
142
144
  });
143
145
  setImmediate(() => {
144
146
  curlHandle.perform();
@@ -96,9 +96,9 @@ function fetchNodeHttp(fetchRequest) {
96
96
  }
97
97
  }
98
98
  if (outputStream != null) {
99
- outputStream = (0, utils_js_1.wrapIncomingMessageWithPassthrough)({
100
- incomingMessage: nodeResponse,
101
- passThrough: outputStream,
99
+ (0, utils_js_1.pipeThrough)({
100
+ src: nodeResponse,
101
+ dest: outputStream,
102
102
  signal,
103
103
  onError: reject,
104
104
  });
package/cjs/utils.js CHANGED
@@ -7,12 +7,10 @@ exports.isArrayBufferView = isArrayBufferView;
7
7
  exports.isNodeReadable = isNodeReadable;
8
8
  exports.isIterable = isIterable;
9
9
  exports.shouldRedirect = shouldRedirect;
10
- exports.wrapIncomingMessageWithPassthrough = wrapIncomingMessageWithPassthrough;
10
+ exports.pipeThrough = pipeThrough;
11
11
  exports.endStream = endStream;
12
12
  exports.safeWrite = safeWrite;
13
13
  const node_events_1 = require("node:events");
14
- const node_stream_1 = require("node:stream");
15
- const promises_1 = require("node:stream/promises");
16
14
  function isHeadersInstance(obj) {
17
15
  return obj?.forEach != null;
18
16
  }
@@ -51,20 +49,39 @@ function isIterable(value) {
51
49
  function shouldRedirect(status) {
52
50
  return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
53
51
  }
54
- function wrapIncomingMessageWithPassthrough({ incomingMessage, signal, passThrough = new node_stream_1.PassThrough(), onError = (e) => {
55
- passThrough.destroy(e);
56
- }, }) {
57
- (0, promises_1.pipeline)(incomingMessage, passThrough, {
58
- signal,
59
- end: true,
60
- })
61
- .then(() => {
62
- if (!incomingMessage.destroyed) {
63
- incomingMessage.resume();
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
+ function handleAbort() {
68
+ try {
69
+ signal.throwIfAborted();
70
+ }
71
+ catch (abortError) {
72
+ // destroying the src stream will destroy the dest stream as well
73
+ src.destroy(abortError);
74
+ }
64
75
  }
65
- })
66
- .catch(onError);
67
- return passThrough;
76
+ if (signal.aborted) {
77
+ // if the signal is already aborted, we can just destroy the
78
+ // src stream and not start pipe at all
79
+ handleAbort();
80
+ return;
81
+ }
82
+ signal.addEventListener('abort', handleAbort, { once: true });
83
+ }
84
+ src.pipe(dest, { end: true /* already default */ });
68
85
  }
69
86
  function endStream(stream) {
70
87
  // @ts-expect-error Avoid arguments adaptor trampoline https://v8.dev/blog/adaptor-frame
package/esm/Body.js CHANGED
@@ -1,14 +1,14 @@
1
1
  /* eslint-disable @typescript-eslint/ban-ts-comment */
2
2
  import { Buffer } from 'node:buffer';
3
3
  import { IncomingMessage } from 'node:http';
4
- import { addAbortSignal, Readable } from 'node:stream';
4
+ import { addAbortSignal, PassThrough, Readable } from 'node:stream';
5
5
  import { Busboy } from '@fastify/busboy';
6
6
  import { handleMaybePromise } from '@whatwg-node/promise-helpers';
7
7
  import { hasArrayBufferMethod, hasBufferMethod, hasBytesMethod, PonyfillBlob } from './Blob.js';
8
8
  import { PonyfillFile } from './File.js';
9
9
  import { getStreamFromFormData, PonyfillFormData } from './FormData.js';
10
10
  import { PonyfillReadableStream } from './ReadableStream.js';
11
- import { fakePromise, isArrayBufferView, wrapIncomingMessageWithPassthrough } from './utils.js';
11
+ import { fakePromise, isArrayBufferView, pipeThrough } from './utils.js';
12
12
  var BodyInitType;
13
13
  (function (BodyInitType) {
14
14
  BodyInitType["ReadableStream"] = "ReadableStream";
@@ -453,8 +453,10 @@ function processBodyInit(bodyInit, signal) {
453
453
  };
454
454
  }
455
455
  if (bodyInit instanceof IncomingMessage) {
456
- const passThrough = wrapIncomingMessageWithPassthrough({
457
- incomingMessage: bodyInit,
456
+ const passThrough = new PassThrough();
457
+ pipeThrough({
458
+ src: bodyInit,
459
+ dest: passThrough,
458
460
  signal,
459
461
  });
460
462
  return {
package/esm/fetchCurl.js CHANGED
@@ -1,8 +1,8 @@
1
- import { Readable } from 'node:stream';
1
+ 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, wrapIncomingMessageWithPassthrough, } 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();
@@ -104,8 +104,10 @@ export function fetchCurl(fetchRequest) {
104
104
  }
105
105
  });
106
106
  curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
107
- const outputStream = wrapIncomingMessageWithPassthrough({
108
- incomingMessage: stream,
107
+ const passThrough = new PassThrough();
108
+ pipeThrough({
109
+ src: stream,
110
+ dest: passThrough,
109
111
  signal,
110
112
  onError: deferredPromise.reject,
111
113
  });
@@ -120,7 +122,7 @@ export function fetchCurl(fetchRequest) {
120
122
  if (!stream.destroyed) {
121
123
  stream.resume();
122
124
  }
123
- outputStream.destroy();
125
+ passThrough.destroy();
124
126
  deferredPromise.reject(new Error('redirect is not allowed'));
125
127
  }
126
128
  return true;
@@ -128,14 +130,14 @@ export function fetchCurl(fetchRequest) {
128
130
  return false;
129
131
  });
130
132
  const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
131
- const ponyfillResponse = new PonyfillResponse(outputStream, {
133
+ const ponyfillResponse = new PonyfillResponse(passThrough, {
132
134
  status,
133
135
  headers: headersInit,
134
136
  url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
135
137
  redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
136
138
  });
137
139
  deferredPromise.resolve(ponyfillResponse);
138
- streamResolved = outputStream;
140
+ streamResolved = passThrough;
139
141
  });
140
142
  setImmediate(() => {
141
143
  curlHandle.perform();
@@ -6,7 +6,7 @@ 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, wrapIncomingMessageWithPassthrough, } 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;
@@ -93,9 +93,9 @@ export function fetchNodeHttp(fetchRequest) {
93
93
  }
94
94
  }
95
95
  if (outputStream != null) {
96
- outputStream = wrapIncomingMessageWithPassthrough({
97
- incomingMessage: nodeResponse,
98
- passThrough: outputStream,
96
+ pipeThrough({
97
+ src: nodeResponse,
98
+ dest: outputStream,
99
99
  signal,
100
100
  onError: reject,
101
101
  });
package/esm/utils.js CHANGED
@@ -1,6 +1,4 @@
1
1
  import { once } from 'node:events';
2
- import { PassThrough } from 'node:stream';
3
- import { pipeline } from 'node:stream/promises';
4
2
  function isHeadersInstance(obj) {
5
3
  return obj?.forEach != null;
6
4
  }
@@ -38,20 +36,39 @@ export function isIterable(value) {
38
36
  export function shouldRedirect(status) {
39
37
  return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
40
38
  }
41
- export function wrapIncomingMessageWithPassthrough({ incomingMessage, signal, passThrough = new PassThrough(), onError = (e) => {
42
- passThrough.destroy(e);
43
- }, }) {
44
- pipeline(incomingMessage, passThrough, {
45
- signal,
46
- end: true,
47
- })
48
- .then(() => {
49
- if (!incomingMessage.destroyed) {
50
- incomingMessage.resume();
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
+ function handleAbort() {
55
+ try {
56
+ signal.throwIfAborted();
57
+ }
58
+ catch (abortError) {
59
+ // destroying the src stream will destroy the dest stream as well
60
+ src.destroy(abortError);
61
+ }
51
62
  }
52
- })
53
- .catch(onError);
54
- return passThrough;
63
+ if (signal.aborted) {
64
+ // if the signal is already aborted, we can just destroy the
65
+ // src stream and not start pipe at all
66
+ handleAbort();
67
+ return;
68
+ }
69
+ signal.addEventListener('abort', handleAbort, { once: true });
70
+ }
71
+ src.pipe(dest, { end: true /* already default */ });
55
72
  }
56
73
  export function endStream(stream) {
57
74
  // @ts-expect-error Avoid arguments adaptor trampoline https://v8.dev/blog/adaptor-frame
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatwg-node/node-fetch",
3
- "version": "0.7.22-alpha-20250710160716-6df7209d12299dba404ac539d834654be5d43990",
3
+ "version": "0.7.23-alpha-20250725190806-5df0ede70a22656416fd7a0f626f8d5ba8238197",
4
4
  "description": "Fetch API implementation for Node",
5
5
  "sideEffects": false,
6
6
  "dependencies": {
@@ -1,5 +1,4 @@
1
- import { IncomingMessage } from 'node:http';
2
- import { PassThrough, Readable, Writable } from 'node:stream';
1
+ import { Readable, Writable } from 'node:stream';
3
2
  export declare function getHeadersObj(headers: Headers): Record<string, string>;
4
3
  export declare function defaultHeadersSerializer(headers: Headers, onContentLength?: (value: string) => void): string[];
5
4
  export { fakePromise } from '@whatwg-node/promise-helpers';
@@ -7,12 +6,12 @@ export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
7
6
  export declare function isNodeReadable(obj: any): obj is Readable;
8
7
  export declare function isIterable(value: any): value is Iterable<unknown>;
9
8
  export declare function shouldRedirect(status?: number): boolean;
10
- export declare function wrapIncomingMessageWithPassthrough({ incomingMessage, signal, passThrough, onError, }: {
11
- incomingMessage: IncomingMessage;
12
- passThrough?: PassThrough | undefined;
9
+ export declare function pipeThrough({ src, dest, signal, onError, }: {
10
+ src: Readable;
11
+ dest: Writable;
13
12
  signal?: AbortSignal | undefined;
14
- onError?: (e: Error) => void;
15
- }): PassThrough;
13
+ onError?: ((e: Error) => void) | undefined;
14
+ }): void;
16
15
  export declare function endStream(stream: {
17
16
  end: () => void;
18
17
  }): void;
@@ -1,5 +1,4 @@
1
- import { IncomingMessage } from 'node:http';
2
- import { PassThrough, Readable, Writable } from 'node:stream';
1
+ import { Readable, Writable } from 'node:stream';
3
2
  export declare function getHeadersObj(headers: Headers): Record<string, string>;
4
3
  export declare function defaultHeadersSerializer(headers: Headers, onContentLength?: (value: string) => void): string[];
5
4
  export { fakePromise } from '@whatwg-node/promise-helpers';
@@ -7,12 +6,12 @@ export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
7
6
  export declare function isNodeReadable(obj: any): obj is Readable;
8
7
  export declare function isIterable(value: any): value is Iterable<unknown>;
9
8
  export declare function shouldRedirect(status?: number): boolean;
10
- export declare function wrapIncomingMessageWithPassthrough({ incomingMessage, signal, passThrough, onError, }: {
11
- incomingMessage: IncomingMessage;
12
- passThrough?: PassThrough | undefined;
9
+ export declare function pipeThrough({ src, dest, signal, onError, }: {
10
+ src: Readable;
11
+ dest: Writable;
13
12
  signal?: AbortSignal | undefined;
14
- onError?: (e: Error) => void;
15
- }): PassThrough;
13
+ onError?: ((e: Error) => void) | undefined;
14
+ }): void;
16
15
  export declare function endStream(stream: {
17
16
  end: () => void;
18
17
  }): void;