@whatwg-node/node-fetch 0.7.22-alpha-20250526145249-5592a2aa5cd5a8603f5016376c1e6ef0f84f7aab → 0.7.22-alpha-20250527001401-318441d4ecce8b4db24c1d2d9a90cfb84928b021

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
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PonyfillBody = void 0;
4
4
  /* eslint-disable @typescript-eslint/ban-ts-comment */
5
5
  const node_buffer_1 = require("node:buffer");
6
- const node_http_1 = require("node:http");
7
6
  const node_stream_1 = require("node:stream");
7
+ const promises_1 = require("node:stream/promises");
8
8
  const busboy_1 = require("@fastify/busboy");
9
9
  const promise_helpers_1 = require("@whatwg-node/promise-helpers");
10
10
  const Blob_js_1 = require("./Blob.js");
@@ -33,7 +33,7 @@ class PonyfillBody {
33
33
  this.bodyInit = bodyInit;
34
34
  this.options = options;
35
35
  this._signal = options.signal || null;
36
- const { bodyFactory, contentType, contentLength, bodyType, buffer } = processBodyInit(bodyInit, options?.signal);
36
+ const { bodyFactory, contentType, contentLength, bodyType, buffer } = processBodyInit(bodyInit);
37
37
  this._bodyFactory = bodyFactory;
38
38
  this.contentType = contentType;
39
39
  this.contentLength = contentLength;
@@ -133,6 +133,11 @@ class PonyfillBody {
133
133
  this._chunks = [];
134
134
  return this._chunks;
135
135
  }
136
+ if (_body.readable.destroyed) {
137
+ // If the stream is already destroyed, we can resolve immediately
138
+ this._chunks = [];
139
+ return this._chunks;
140
+ }
136
141
  const chunks = [];
137
142
  const deferred = (0, promise_helpers_1.createDeferredPromise)();
138
143
  _body.readable.on('data', function nextChunk(chunk) {
@@ -204,93 +209,57 @@ class PonyfillBody {
204
209
  ...this.options.formDataLimits,
205
210
  ...opts?.formDataLimits,
206
211
  };
207
- return new Promise((resolve, reject) => {
208
- const stream = this.body?.readable;
209
- if (!stream) {
210
- return reject(new Error('No stream available'));
212
+ const stream = this.body?.readable;
213
+ if (!stream) {
214
+ return (0, promise_helpers_1.fakeRejectPromise)(new Error('No stream available'));
215
+ }
216
+ const bb = new busboy_1.Busboy({
217
+ headers: {
218
+ 'content-length': typeof this.contentLength === 'number'
219
+ ? this.contentLength.toString()
220
+ : this.contentLength || '',
221
+ 'content-type': this.contentType || '',
222
+ },
223
+ limits: formDataLimits,
224
+ defCharset: 'utf-8',
225
+ });
226
+ bb.on('field', (name, value, fieldnameTruncated, valueTruncated) => {
227
+ if (fieldnameTruncated) {
228
+ throw new Error(`Field name size exceeded: ${formDataLimits?.fieldNameSize} bytes`);
211
229
  }
212
- // form data file that is currently being processed, it's
213
- // important to keep track of it in case the stream ends early
214
- let currFile = null;
215
- const bb = new busboy_1.Busboy({
216
- headers: {
217
- 'content-length': typeof this.contentLength === 'number'
218
- ? this.contentLength.toString()
219
- : this.contentLength || '',
220
- 'content-type': this.contentType || '',
221
- },
222
- limits: formDataLimits,
223
- defCharset: 'utf-8',
224
- });
225
- if (this._signal) {
226
- (0, node_stream_1.addAbortSignal)(this._signal, bb);
230
+ if (valueTruncated) {
231
+ throw new Error(`Field value size exceeded: ${formDataLimits?.fieldSize} bytes`);
227
232
  }
228
- let completed = false;
229
- const complete = (err) => {
230
- if (completed)
231
- return;
232
- completed = true;
233
- stream.unpipe(bb);
234
- bb.destroy();
235
- if (currFile) {
236
- currFile.destroy();
237
- currFile = null;
238
- }
239
- if (err) {
240
- reject(err);
241
- }
242
- else {
243
- // no error occured, this is a successful end/complete/finish
244
- resolve(this._formData);
245
- }
246
- };
247
- // we dont need to listen to the stream close event because bb will close or error when necessary
248
- // stream.on('close', complete);
249
- // stream can be aborted, for example
250
- stream.on('error', complete);
251
- bb.on('field', (name, value, fieldnameTruncated, valueTruncated) => {
252
- if (fieldnameTruncated) {
253
- return complete(new Error(`Field name size exceeded: ${formDataLimits?.fieldNameSize} bytes`));
254
- }
255
- if (valueTruncated) {
256
- return complete(new Error(`Field value size exceeded: ${formDataLimits?.fieldSize} bytes`));
257
- }
258
- this._formData.set(name, value);
259
- });
260
- bb.on('file', (name, fileStream, filename, _transferEncoding, mimeType) => {
261
- currFile = fileStream;
262
- const chunks = [];
263
- fileStream.on('data', chunk => {
264
- chunks.push(chunk);
265
- });
266
- fileStream.on('error', complete);
267
- fileStream.on('limit', () => {
268
- complete(new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`));
269
- });
270
- fileStream.on('close', () => {
271
- if (fileStream.truncated) {
272
- complete(new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`));
273
- }
274
- currFile = null;
275
- const file = new File_js_1.PonyfillFile(chunks, filename, { type: mimeType });
276
- this._formData.set(name, file);
277
- });
278
- });
279
- bb.on('fieldsLimit', () => {
280
- complete(new Error(`Fields limit exceeded: ${formDataLimits?.fields}`));
233
+ this._formData.set(name, value);
234
+ });
235
+ bb.on('file', (name, fileStream, filename, _transferEncoding, mimeType) => {
236
+ const chunks = [];
237
+ fileStream.on('data', chunk => {
238
+ chunks.push(chunk);
281
239
  });
282
- bb.on('filesLimit', () => {
283
- complete(new Error(`Files limit exceeded: ${formDataLimits?.files}`));
240
+ fileStream.on('limit', () => {
241
+ throw new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`);
284
242
  });
285
- bb.on('partsLimit', () => {
286
- complete(new Error(`Parts limit exceeded: ${formDataLimits?.parts}`));
243
+ fileStream.on('close', () => {
244
+ if (fileStream.truncated) {
245
+ throw new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`);
246
+ }
247
+ const file = new File_js_1.PonyfillFile(chunks, filename, { type: mimeType });
248
+ this._formData.set(name, file);
287
249
  });
288
- bb.on('end', complete);
289
- bb.on('finish', complete);
290
- bb.on('close', complete);
291
- bb.on('error', complete);
292
- stream.pipe(bb);
293
250
  });
251
+ bb.on('fieldsLimit', () => {
252
+ throw new Error(`Fields limit exceeded: ${formDataLimits?.fields}`);
253
+ });
254
+ bb.on('filesLimit', () => {
255
+ throw new Error(`Files limit exceeded: ${formDataLimits?.files}`);
256
+ });
257
+ bb.on('partsLimit', () => {
258
+ throw new Error(`Parts limit exceeded: ${formDataLimits?.parts}`);
259
+ });
260
+ return (0, promises_1.pipeline)(stream, bb, {
261
+ signal: this._signal || undefined,
262
+ }).then(() => this._formData);
294
263
  }
295
264
  buffer() {
296
265
  if (this._buffer) {
@@ -379,7 +348,7 @@ class PonyfillBody {
379
348
  }
380
349
  }
381
350
  exports.PonyfillBody = PonyfillBody;
382
- function processBodyInit(bodyInit, signal) {
351
+ function processBodyInit(bodyInit) {
383
352
  if (bodyInit == null) {
384
353
  return {
385
354
  bodyFactory: () => null,
@@ -462,20 +431,6 @@ function processBodyInit(bodyInit, signal) {
462
431
  },
463
432
  };
464
433
  }
465
- if (bodyInit instanceof node_http_1.IncomingMessage) {
466
- const passThrough = (0, utils_js_1.wrapIncomingMessageWithPassthrough)({
467
- incomingMessage: bodyInit,
468
- signal,
469
- });
470
- return {
471
- bodyType: BodyInitType.Readable,
472
- contentType: null,
473
- contentLength: null,
474
- bodyFactory() {
475
- return new ReadableStream_js_1.PonyfillReadableStream(passThrough);
476
- },
477
- };
478
- }
479
434
  if (bodyInit instanceof node_stream_1.Readable) {
480
435
  return {
481
436
  bodyType: BodyInitType.Readable,
@@ -95,14 +95,12 @@ function fetchNodeHttp(fetchRequest) {
95
95
  return;
96
96
  }
97
97
  }
98
- if (outputStream != null) {
99
- outputStream = (0, utils_js_1.wrapIncomingMessageWithPassthrough)({
100
- incomingMessage: nodeResponse,
101
- passThrough: outputStream,
102
- signal,
103
- onError: reject,
104
- });
105
- }
98
+ outputStream = (0, utils_js_1.wrapIncomingMessageWithPassthrough)({
99
+ incomingMessage: nodeResponse,
100
+ passThrough: outputStream,
101
+ signal,
102
+ onError: reject,
103
+ });
106
104
  const statusCode = nodeResponse.statusCode || 200;
107
105
  let statusText = nodeResponse.statusMessage || node_http_1.STATUS_CODES[statusCode];
108
106
  if (statusText == null) {
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
- import { IncomingMessage } from 'node:http';
4
- import { addAbortSignal, Readable } from 'node:stream';
3
+ import { Readable } from 'node:stream';
4
+ import { pipeline } from 'node:stream/promises';
5
5
  import { Busboy } from '@fastify/busboy';
6
- import { createDeferredPromise } from '@whatwg-node/promise-helpers';
6
+ import { createDeferredPromise, fakeRejectPromise, } 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 } from './utils.js';
12
12
  var BodyInitType;
13
13
  (function (BodyInitType) {
14
14
  BodyInitType["ReadableStream"] = "ReadableStream";
@@ -30,7 +30,7 @@ export class PonyfillBody {
30
30
  this.bodyInit = bodyInit;
31
31
  this.options = options;
32
32
  this._signal = options.signal || null;
33
- const { bodyFactory, contentType, contentLength, bodyType, buffer } = processBodyInit(bodyInit, options?.signal);
33
+ const { bodyFactory, contentType, contentLength, bodyType, buffer } = processBodyInit(bodyInit);
34
34
  this._bodyFactory = bodyFactory;
35
35
  this.contentType = contentType;
36
36
  this.contentLength = contentLength;
@@ -130,6 +130,11 @@ export class PonyfillBody {
130
130
  this._chunks = [];
131
131
  return this._chunks;
132
132
  }
133
+ if (_body.readable.destroyed) {
134
+ // If the stream is already destroyed, we can resolve immediately
135
+ this._chunks = [];
136
+ return this._chunks;
137
+ }
133
138
  const chunks = [];
134
139
  const deferred = createDeferredPromise();
135
140
  _body.readable.on('data', function nextChunk(chunk) {
@@ -201,93 +206,57 @@ export class PonyfillBody {
201
206
  ...this.options.formDataLimits,
202
207
  ...opts?.formDataLimits,
203
208
  };
204
- return new Promise((resolve, reject) => {
205
- const stream = this.body?.readable;
206
- if (!stream) {
207
- return reject(new Error('No stream available'));
209
+ const stream = this.body?.readable;
210
+ if (!stream) {
211
+ return fakeRejectPromise(new Error('No stream available'));
212
+ }
213
+ const bb = new Busboy({
214
+ headers: {
215
+ 'content-length': typeof this.contentLength === 'number'
216
+ ? this.contentLength.toString()
217
+ : this.contentLength || '',
218
+ 'content-type': this.contentType || '',
219
+ },
220
+ limits: formDataLimits,
221
+ defCharset: 'utf-8',
222
+ });
223
+ bb.on('field', (name, value, fieldnameTruncated, valueTruncated) => {
224
+ if (fieldnameTruncated) {
225
+ throw new Error(`Field name size exceeded: ${formDataLimits?.fieldNameSize} bytes`);
208
226
  }
209
- // form data file that is currently being processed, it's
210
- // important to keep track of it in case the stream ends early
211
- let currFile = null;
212
- const bb = new Busboy({
213
- headers: {
214
- 'content-length': typeof this.contentLength === 'number'
215
- ? this.contentLength.toString()
216
- : this.contentLength || '',
217
- 'content-type': this.contentType || '',
218
- },
219
- limits: formDataLimits,
220
- defCharset: 'utf-8',
221
- });
222
- if (this._signal) {
223
- addAbortSignal(this._signal, bb);
227
+ if (valueTruncated) {
228
+ throw new Error(`Field value size exceeded: ${formDataLimits?.fieldSize} bytes`);
224
229
  }
225
- let completed = false;
226
- const complete = (err) => {
227
- if (completed)
228
- return;
229
- completed = true;
230
- stream.unpipe(bb);
231
- bb.destroy();
232
- if (currFile) {
233
- currFile.destroy();
234
- currFile = null;
235
- }
236
- if (err) {
237
- reject(err);
238
- }
239
- else {
240
- // no error occured, this is a successful end/complete/finish
241
- resolve(this._formData);
242
- }
243
- };
244
- // we dont need to listen to the stream close event because bb will close or error when necessary
245
- // stream.on('close', complete);
246
- // stream can be aborted, for example
247
- stream.on('error', complete);
248
- bb.on('field', (name, value, fieldnameTruncated, valueTruncated) => {
249
- if (fieldnameTruncated) {
250
- return complete(new Error(`Field name size exceeded: ${formDataLimits?.fieldNameSize} bytes`));
251
- }
252
- if (valueTruncated) {
253
- return complete(new Error(`Field value size exceeded: ${formDataLimits?.fieldSize} bytes`));
254
- }
255
- this._formData.set(name, value);
256
- });
257
- bb.on('file', (name, fileStream, filename, _transferEncoding, mimeType) => {
258
- currFile = fileStream;
259
- const chunks = [];
260
- fileStream.on('data', chunk => {
261
- chunks.push(chunk);
262
- });
263
- fileStream.on('error', complete);
264
- fileStream.on('limit', () => {
265
- complete(new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`));
266
- });
267
- fileStream.on('close', () => {
268
- if (fileStream.truncated) {
269
- complete(new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`));
270
- }
271
- currFile = null;
272
- const file = new PonyfillFile(chunks, filename, { type: mimeType });
273
- this._formData.set(name, file);
274
- });
275
- });
276
- bb.on('fieldsLimit', () => {
277
- complete(new Error(`Fields limit exceeded: ${formDataLimits?.fields}`));
230
+ this._formData.set(name, value);
231
+ });
232
+ bb.on('file', (name, fileStream, filename, _transferEncoding, mimeType) => {
233
+ const chunks = [];
234
+ fileStream.on('data', chunk => {
235
+ chunks.push(chunk);
278
236
  });
279
- bb.on('filesLimit', () => {
280
- complete(new Error(`Files limit exceeded: ${formDataLimits?.files}`));
237
+ fileStream.on('limit', () => {
238
+ throw new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`);
281
239
  });
282
- bb.on('partsLimit', () => {
283
- complete(new Error(`Parts limit exceeded: ${formDataLimits?.parts}`));
240
+ fileStream.on('close', () => {
241
+ if (fileStream.truncated) {
242
+ throw new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`);
243
+ }
244
+ const file = new PonyfillFile(chunks, filename, { type: mimeType });
245
+ this._formData.set(name, file);
284
246
  });
285
- bb.on('end', complete);
286
- bb.on('finish', complete);
287
- bb.on('close', complete);
288
- bb.on('error', complete);
289
- stream.pipe(bb);
290
247
  });
248
+ bb.on('fieldsLimit', () => {
249
+ throw new Error(`Fields limit exceeded: ${formDataLimits?.fields}`);
250
+ });
251
+ bb.on('filesLimit', () => {
252
+ throw new Error(`Files limit exceeded: ${formDataLimits?.files}`);
253
+ });
254
+ bb.on('partsLimit', () => {
255
+ throw new Error(`Parts limit exceeded: ${formDataLimits?.parts}`);
256
+ });
257
+ return pipeline(stream, bb, {
258
+ signal: this._signal || undefined,
259
+ }).then(() => this._formData);
291
260
  }
292
261
  buffer() {
293
262
  if (this._buffer) {
@@ -375,7 +344,7 @@ export class PonyfillBody {
375
344
  });
376
345
  }
377
346
  }
378
- function processBodyInit(bodyInit, signal) {
347
+ function processBodyInit(bodyInit) {
379
348
  if (bodyInit == null) {
380
349
  return {
381
350
  bodyFactory: () => null,
@@ -458,20 +427,6 @@ function processBodyInit(bodyInit, signal) {
458
427
  },
459
428
  };
460
429
  }
461
- if (bodyInit instanceof IncomingMessage) {
462
- const passThrough = wrapIncomingMessageWithPassthrough({
463
- incomingMessage: bodyInit,
464
- signal,
465
- });
466
- return {
467
- bodyType: BodyInitType.Readable,
468
- contentType: null,
469
- contentLength: null,
470
- bodyFactory() {
471
- return new PonyfillReadableStream(passThrough);
472
- },
473
- };
474
- }
475
430
  if (bodyInit instanceof Readable) {
476
431
  return {
477
432
  bodyType: BodyInitType.Readable,
@@ -92,14 +92,12 @@ export function fetchNodeHttp(fetchRequest) {
92
92
  return;
93
93
  }
94
94
  }
95
- if (outputStream != null) {
96
- outputStream = wrapIncomingMessageWithPassthrough({
97
- incomingMessage: nodeResponse,
98
- passThrough: outputStream,
99
- signal,
100
- onError: reject,
101
- });
102
- }
95
+ outputStream = wrapIncomingMessageWithPassthrough({
96
+ incomingMessage: nodeResponse,
97
+ passThrough: outputStream,
98
+ signal,
99
+ onError: reject,
100
+ });
103
101
  const statusCode = nodeResponse.statusCode || 200;
104
102
  let statusText = nodeResponse.statusMessage || STATUS_CODES[statusCode];
105
103
  if (statusText == null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatwg-node/node-fetch",
3
- "version": "0.7.22-alpha-20250526145249-5592a2aa5cd5a8603f5016376c1e6ef0f84f7aab",
3
+ "version": "0.7.22-alpha-20250527001401-318441d4ecce8b4db24c1d2d9a90cfb84928b021",
4
4
  "description": "Fetch API implementation for Node",
5
5
  "sideEffects": false,
6
6
  "dependencies": {