@whatwg-node/node-fetch 0.0.1-alpha-20221228083733-4041c71 → 0.0.1-alpha-20221228110541-2aa6aea

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/Body.d.ts CHANGED
@@ -4,13 +4,26 @@ import { Readable } from 'stream';
4
4
  import { PonyfillFormData } from './FormData';
5
5
  import { PonyfillReadableStream } from './ReadableStream';
6
6
  export type BodyPonyfillInit = XMLHttpRequestBodyInit | Readable | PonyfillReadableStream<Uint8Array>;
7
+ export interface FormDataLimits {
8
+ fieldNameSize?: number;
9
+ fieldSize?: number;
10
+ fields?: number;
11
+ fileSize?: number;
12
+ files?: number;
13
+ parts?: number;
14
+ headerSize?: number;
15
+ }
16
+ export interface PonyfillBodyOptions {
17
+ formDataLimits?: FormDataLimits;
18
+ }
7
19
  export declare class PonyfillBody implements Body {
8
20
  private bodyInit;
21
+ private options;
9
22
  bodyUsed: boolean;
10
23
  private _body;
11
24
  contentType: string | null;
12
25
  contentLength: number | null;
13
- constructor(bodyInit: BodyPonyfillInit | null);
26
+ constructor(bodyInit: BodyPonyfillInit | null, options?: PonyfillBodyOptions);
14
27
  private bodyType?;
15
28
  get body(): PonyfillReadableStream<Uint8Array> | null;
16
29
  arrayBuffer(): Promise<ArrayBuffer>;
package/Request.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { PonyfillBody, BodyPonyfillInit } from './Body';
1
+ import { PonyfillBody, BodyPonyfillInit, PonyfillBodyOptions } from './Body';
2
2
  import { PonyfillHeadersInit } from './Headers';
3
- export type RequestPonyfillInit = Omit<RequestInit, 'body' | 'headers'> & {
3
+ export type RequestPonyfillInit = PonyfillBodyOptions & Omit<RequestInit, 'body' | 'headers'> & {
4
4
  body?: BodyPonyfillInit | null;
5
5
  headers?: PonyfillHeadersInit;
6
6
  };
package/Response.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { PonyfillBody, BodyPonyfillInit } from './Body';
1
+ import { PonyfillBody, BodyPonyfillInit, PonyfillBodyOptions } from './Body';
2
2
  import { PonyfillHeadersInit } from './Headers';
3
- export type ResponsePonyfilInit = Omit<ResponseInit, 'headers'> & {
3
+ export type ResponsePonyfilInit = PonyfillBodyOptions & Omit<ResponseInit, 'headers'> & {
4
4
  url?: string;
5
5
  redirected?: boolean;
6
6
  headers?: PonyfillHeadersInit;
package/index.js CHANGED
@@ -2,11 +2,14 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
5
7
  const http = require('http');
6
8
  const https = require('https');
7
9
  const events = require('@whatwg-node/events');
8
10
  const buffer = require('buffer');
9
11
  const stream = require('stream');
12
+ const busboy = _interopDefault(require('busboy'));
10
13
  const url = require('url');
11
14
  const fs = require('fs');
12
15
 
@@ -291,8 +294,9 @@ var BodyInitType;
291
294
  BodyInitType["Readable"] = "Readable";
292
295
  })(BodyInitType || (BodyInitType = {}));
293
296
  class PonyfillBody {
294
- constructor(bodyInit) {
297
+ constructor(bodyInit, options = {}) {
295
298
  this.bodyInit = bodyInit;
299
+ this.options = options;
296
300
  this.bodyUsed = false;
297
301
  this._body = null;
298
302
  this.contentType = null;
@@ -393,7 +397,7 @@ class PonyfillBody {
393
397
  }
394
398
  return readableProp;
395
399
  }
396
- }
400
+ },
397
401
  });
398
402
  }
399
403
  return null;
@@ -417,11 +421,66 @@ class PonyfillBody {
417
421
  }
418
422
  return new PonyfillBlob(chunks);
419
423
  }
420
- async formData() {
424
+ formData() {
421
425
  if (this.bodyType === BodyInitType.FormData) {
422
- return this.bodyInit;
423
- }
424
- throw new Error('Not implemented');
426
+ return Promise.resolve(this.bodyInit);
427
+ }
428
+ const formData = new PonyfillFormData();
429
+ if (this._body == null) {
430
+ return Promise.resolve(formData);
431
+ }
432
+ const formDataLimits = this.options.formDataLimits;
433
+ return new Promise((resolve, reject) => {
434
+ var _a;
435
+ const bb = busboy({
436
+ headers: {
437
+ 'content-type': this.contentType || '',
438
+ },
439
+ limits: formDataLimits,
440
+ defParamCharset: 'utf-8',
441
+ });
442
+ bb.on('field', (name, value, { nameTruncated, valueTruncated }) => {
443
+ if (nameTruncated) {
444
+ reject(new Error(`Field name size exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fieldNameSize} bytes`));
445
+ }
446
+ if (valueTruncated) {
447
+ reject(new Error(`Field value size exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fieldSize} bytes`));
448
+ }
449
+ formData.set(name, value);
450
+ });
451
+ bb.on('fieldsLimit', () => {
452
+ reject(new Error(`Fields limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fields}`));
453
+ });
454
+ bb.on('file', (name, fileStream, { filename, mimeType }) => {
455
+ const chunks = [];
456
+ fileStream.on('limit', () => {
457
+ reject(new Error(`File size limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fileSize} bytes`));
458
+ });
459
+ fileStream.on('data', chunk => {
460
+ chunks.push(Buffer.from(chunk));
461
+ });
462
+ fileStream.on('close', () => {
463
+ if (fileStream.truncated) {
464
+ reject(new Error(`File size limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fileSize} bytes`));
465
+ }
466
+ const file = new PonyfillFile(chunks, filename, { type: mimeType });
467
+ formData.set(name, file);
468
+ });
469
+ });
470
+ bb.on('filesLimit', () => {
471
+ reject(new Error(`Files limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.files}`));
472
+ });
473
+ bb.on('partsLimit', () => {
474
+ reject(new Error(`Parts limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.parts}`));
475
+ });
476
+ bb.on('close', () => {
477
+ resolve(formData);
478
+ });
479
+ bb.on('error', err => {
480
+ reject(err);
481
+ });
482
+ (_a = this._body) === null || _a === void 0 ? void 0 : _a.readable.pipe(bb);
483
+ });
425
484
  }
426
485
  async json() {
427
486
  const text = await this.text();
@@ -540,7 +599,7 @@ class PonyfillRequest extends PonyfillBody {
540
599
  bodyInit = options.body || null;
541
600
  requestInit = options;
542
601
  }
543
- super(bodyInit);
602
+ super(bodyInit, options);
544
603
  this.destination = '';
545
604
  this.priority = 'auto';
546
605
  this.cache = (requestInit === null || requestInit === void 0 ? void 0 : requestInit.cache) || 'default';
@@ -560,16 +619,24 @@ class PonyfillRequest extends PonyfillBody {
560
619
  this.headers.set('connection', 'keep-alive');
561
620
  }
562
621
  }
563
- if (!this.headers.has('content-type')) {
622
+ const contentTypeInHeaders = this.headers.get('content-type');
623
+ if (!contentTypeInHeaders) {
564
624
  if (this.contentType) {
565
625
  this.headers.set('content-type', this.contentType);
566
626
  }
567
627
  }
568
- if (!this.headers.has('content-length')) {
628
+ else {
629
+ this.contentType = contentTypeInHeaders;
630
+ }
631
+ const contentLengthInHeaders = this.headers.get('content-length');
632
+ if (!contentLengthInHeaders) {
569
633
  if (this.contentLength) {
570
634
  this.headers.set('content-length', this.contentLength.toString());
571
635
  }
572
636
  }
637
+ else {
638
+ this.contentLength = parseInt(contentLengthInHeaders, 10);
639
+ }
573
640
  }
574
641
  clone() {
575
642
  return new Request(this);
@@ -578,7 +645,7 @@ class PonyfillRequest extends PonyfillBody {
578
645
 
579
646
  class PonyfillResponse extends PonyfillBody {
580
647
  constructor(body, init) {
581
- super(body || null);
648
+ super(body || null, init);
582
649
  this.headers = new PonyfillHeaders();
583
650
  this.status = 200;
584
651
  this.statusText = 'OK';
package/index.mjs CHANGED
@@ -3,6 +3,7 @@ import { request } from 'https';
3
3
  import { EventTarget, CustomEvent } from '@whatwg-node/events';
4
4
  import { Blob } from 'buffer';
5
5
  import { Readable } from 'stream';
6
+ import busboy from 'busboy';
6
7
  import { fileURLToPath } from 'url';
7
8
  import { createReadStream } from 'fs';
8
9
 
@@ -287,8 +288,9 @@ var BodyInitType;
287
288
  BodyInitType["Readable"] = "Readable";
288
289
  })(BodyInitType || (BodyInitType = {}));
289
290
  class PonyfillBody {
290
- constructor(bodyInit) {
291
+ constructor(bodyInit, options = {}) {
291
292
  this.bodyInit = bodyInit;
293
+ this.options = options;
292
294
  this.bodyUsed = false;
293
295
  this._body = null;
294
296
  this.contentType = null;
@@ -389,7 +391,7 @@ class PonyfillBody {
389
391
  }
390
392
  return readableProp;
391
393
  }
392
- }
394
+ },
393
395
  });
394
396
  }
395
397
  return null;
@@ -413,11 +415,66 @@ class PonyfillBody {
413
415
  }
414
416
  return new PonyfillBlob(chunks);
415
417
  }
416
- async formData() {
418
+ formData() {
417
419
  if (this.bodyType === BodyInitType.FormData) {
418
- return this.bodyInit;
419
- }
420
- throw new Error('Not implemented');
420
+ return Promise.resolve(this.bodyInit);
421
+ }
422
+ const formData = new PonyfillFormData();
423
+ if (this._body == null) {
424
+ return Promise.resolve(formData);
425
+ }
426
+ const formDataLimits = this.options.formDataLimits;
427
+ return new Promise((resolve, reject) => {
428
+ var _a;
429
+ const bb = busboy({
430
+ headers: {
431
+ 'content-type': this.contentType || '',
432
+ },
433
+ limits: formDataLimits,
434
+ defParamCharset: 'utf-8',
435
+ });
436
+ bb.on('field', (name, value, { nameTruncated, valueTruncated }) => {
437
+ if (nameTruncated) {
438
+ reject(new Error(`Field name size exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fieldNameSize} bytes`));
439
+ }
440
+ if (valueTruncated) {
441
+ reject(new Error(`Field value size exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fieldSize} bytes`));
442
+ }
443
+ formData.set(name, value);
444
+ });
445
+ bb.on('fieldsLimit', () => {
446
+ reject(new Error(`Fields limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fields}`));
447
+ });
448
+ bb.on('file', (name, fileStream, { filename, mimeType }) => {
449
+ const chunks = [];
450
+ fileStream.on('limit', () => {
451
+ reject(new Error(`File size limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fileSize} bytes`));
452
+ });
453
+ fileStream.on('data', chunk => {
454
+ chunks.push(Buffer.from(chunk));
455
+ });
456
+ fileStream.on('close', () => {
457
+ if (fileStream.truncated) {
458
+ reject(new Error(`File size limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.fileSize} bytes`));
459
+ }
460
+ const file = new PonyfillFile(chunks, filename, { type: mimeType });
461
+ formData.set(name, file);
462
+ });
463
+ });
464
+ bb.on('filesLimit', () => {
465
+ reject(new Error(`Files limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.files}`));
466
+ });
467
+ bb.on('partsLimit', () => {
468
+ reject(new Error(`Parts limit exceeded: ${formDataLimits === null || formDataLimits === void 0 ? void 0 : formDataLimits.parts}`));
469
+ });
470
+ bb.on('close', () => {
471
+ resolve(formData);
472
+ });
473
+ bb.on('error', err => {
474
+ reject(err);
475
+ });
476
+ (_a = this._body) === null || _a === void 0 ? void 0 : _a.readable.pipe(bb);
477
+ });
421
478
  }
422
479
  async json() {
423
480
  const text = await this.text();
@@ -536,7 +593,7 @@ class PonyfillRequest extends PonyfillBody {
536
593
  bodyInit = options.body || null;
537
594
  requestInit = options;
538
595
  }
539
- super(bodyInit);
596
+ super(bodyInit, options);
540
597
  this.destination = '';
541
598
  this.priority = 'auto';
542
599
  this.cache = (requestInit === null || requestInit === void 0 ? void 0 : requestInit.cache) || 'default';
@@ -556,16 +613,24 @@ class PonyfillRequest extends PonyfillBody {
556
613
  this.headers.set('connection', 'keep-alive');
557
614
  }
558
615
  }
559
- if (!this.headers.has('content-type')) {
616
+ const contentTypeInHeaders = this.headers.get('content-type');
617
+ if (!contentTypeInHeaders) {
560
618
  if (this.contentType) {
561
619
  this.headers.set('content-type', this.contentType);
562
620
  }
563
621
  }
564
- if (!this.headers.has('content-length')) {
622
+ else {
623
+ this.contentType = contentTypeInHeaders;
624
+ }
625
+ const contentLengthInHeaders = this.headers.get('content-length');
626
+ if (!contentLengthInHeaders) {
565
627
  if (this.contentLength) {
566
628
  this.headers.set('content-length', this.contentLength.toString());
567
629
  }
568
630
  }
631
+ else {
632
+ this.contentLength = parseInt(contentLengthInHeaders, 10);
633
+ }
569
634
  }
570
635
  clone() {
571
636
  return new Request(this);
@@ -574,7 +639,7 @@ class PonyfillRequest extends PonyfillBody {
574
639
 
575
640
  class PonyfillResponse extends PonyfillBody {
576
641
  constructor(body, init) {
577
- super(body || null);
642
+ super(body || null, init);
578
643
  this.headers = new PonyfillHeaders();
579
644
  this.status = 200;
580
645
  this.statusText = 'OK';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatwg-node/node-fetch",
3
- "version": "0.0.1-alpha-20221228083733-4041c71",
3
+ "version": "0.0.1-alpha-20221228110541-2aa6aea",
4
4
  "description": "Fetch API implementation for Node",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -8,6 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@whatwg-node/events": "0.0.2",
11
+ "busboy": "1.6.0",
11
12
  "tslib": "^2.3.1"
12
13
  },
13
14
  "repository": {