Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@whatwg-node/fetch

Package Overview
Dependencies
Maintainers
1
Versions
475
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@whatwg-node/fetch - npm Package Compare versions

Comparing version 0.5.3 to 0.5.4-alpha-20221225155445-dfcb269

6

CHANGELOG.md
# @whatwg-node/fetch
## 0.5.4-alpha-20221225155445-dfcb269
### Patch Changes
- [#154](https://github.com/ardatan/whatwg-node/pull/154) [`8324adc`](https://github.com/ardatan/whatwg-node/commit/8324adcc1383eb16fd6d0a6417842e0b8d9b82ba) Thanks [@ardatan](https://github.com/ardatan)! - New Fetch API implementation for Node
## 0.5.3

@@ -4,0 +10,0 @@

284

dist/create-node-ponyfill.js

@@ -11,74 +11,25 @@ const handleFileRequest = require("./handle-file-request");

const newNodeFetch = require('@whatwg-node/node-fetch');
const ponyfills = {};
if (!opts.useNodeFetch) {
ponyfills.fetch = globalThis.fetch;
ponyfills.Headers = globalThis.Headers;
ponyfills.Request = globalThis.Request;
ponyfills.Response = globalThis.Response;
ponyfills.FormData = globalThis.FormData;
ponyfills.File = globalThis.File;
}
ponyfills.AbortController = newNodeFetch.AbortController;
ponyfills.AbortError = newNodeFetch.AbortError;
ponyfills.AbortSignal = newNodeFetch.AbortSignal;
ponyfills.Blob = newNodeFetch.Blob;
ponyfills.Body = newNodeFetch.Body;
ponyfills.fetch = newNodeFetch.fetch;
ponyfills.File = newNodeFetch.File;
ponyfills.FormData = newNodeFetch.FormData;
ponyfills.Headers = newNodeFetch.Headers;
ponyfills.ReadableStream = newNodeFetch.ReadableStream;
ponyfills.Request = newNodeFetch.Request;
ponyfills.Response = newNodeFetch.Response;
ponyfills.TextEncoder = newNodeFetch.TextEncoder;
ponyfills.TextDecoder = newNodeFetch.TextDecoder;
ponyfills.btoa = newNodeFetch.btoa;
ponyfills.AbortController = globalThis.AbortController;
ponyfills.ReadableStream = globalThis.ReadableStream;
ponyfills.WritableStream = globalThis.WritableStream;
ponyfills.TransformStream = globalThis.TransformStream;
ponyfills.Blob = globalThis.Blob;
ponyfills.crypto = globalThis.crypto;
const getFormDataMethod = require("./getFormDataMethod");
ponyfills.Body.prototype.formData = getFormDataMethod(ponyfills.File, opts.formDataLimits)
if (!ponyfills.AbortController) {
const abortControllerModule = require("abort-controller");
ponyfills.AbortController =
abortControllerModule.default || abortControllerModule;
}
if (!ponyfills.Blob) {
const bufferModule = require('buffer')
ponyfills.Blob = bufferModule.Blob;
}
if (!ponyfills.Blob) {
const formDataModule = require("formdata-node");
ponyfills.Blob = formDataModule.Blob
}
if (!ponyfills.ReadableStream) {
try {
const streamsWeb = require("stream/web");
ponyfills.ReadableStream = streamsWeb.ReadableStream;
ponyfills.WritableStream = streamsWeb.WritableStream;
ponyfills.TransformStream = streamsWeb.TransformStream;
} catch (e) {
const streamsWeb = require("web-streams-polyfill/ponyfill");
ponyfills.ReadableStream = streamsWeb.ReadableStream;
ponyfills.WritableStream = streamsWeb.WritableStream;
ponyfills.TransformStream = streamsWeb.TransformStream;
}
}
ponyfills.btoa = globalThis.btoa
if (!ponyfills.btoa) {
ponyfills.btoa = function btoa(data) {
return Buffer.from(data, 'binary').toString('base64');
};
}
ponyfills.TextEncoder = function TextEncoder(encoding = 'utf-8') {
return {
encode(str) {
return Buffer.from(str, encoding);
}
}
}
ponyfills.TextDecoder = function TextDecoder(encoding = 'utf-8') {
return {
decode(buf) {
return Buffer.from(buf).toString(encoding);
}
}
}
if (!ponyfills.crypto) {

@@ -94,200 +45,3 @@ const cryptoModule = require("crypto");

// If any of classes of Fetch API is missing, we need to ponyfill them.
if (!ponyfills.fetch ||
!ponyfills.Request ||
!ponyfills.Headers ||
!ponyfills.Response ||
!ponyfills.FormData ||
!ponyfills.File ||
opts.useNodeFetch) {
const [
nodeMajorStr,
nodeMinorStr
] = process.versions.node.split('.');
const nodeMajor = parseInt(nodeMajorStr);
const nodeMinor = parseInt(nodeMinorStr);
const getFormDataMethod = require('./getFormDataMethod');
if (!opts.useNodeFetch && (nodeMajor > 16 || (nodeMajor === 16 && nodeMinor >= 5))) {
const undici = require("undici");
if (!ponyfills.Headers) {
ponyfills.Headers = undici.Headers;
}
const streams = require("stream");
const OriginalRequest = ponyfills.Request || undici.Request;
class Request extends OriginalRequest {
constructor(requestOrUrl, options) {
if (typeof requestOrUrl === "string" || requestOrUrl instanceof URL) {
if (options != null && typeof options === "object" && !options.duplex) {
options.duplex = 'half';
}
super(requestOrUrl, options);
const contentType = this.headers.get("content-type");
if (contentType && contentType.startsWith("multipart/form-data")) {
this.headers.set("content-type", contentType.split(', ')[0]);
}
} else {
super(requestOrUrl);
}
this.formData = getFormDataMethod(undici.File, opts.formDataLimits);
}
}
ponyfills.Request = Request;
const originalFetch = ponyfills.fetch || undici.fetch;
const fetch = function (requestOrUrl, options) {
if (typeof requestOrUrl === "string" || requestOrUrl instanceof URL) {
if (options != null && typeof options === "object" && !options.duplex) {
options.duplex = 'half';
}
// We cannot use our ctor because it leaks on Node 18's global fetch
return originalFetch(requestOrUrl, options);
}
if (requestOrUrl.url.startsWith('file:')) {
return handleFileRequest(requestOrUrl.url, ponyfills.Response);
}
return originalFetch(requestOrUrl);
};
ponyfills.fetch = fetch;
if (!ponyfills.Response) {
ponyfills.Response = undici.Response;
}
if (!ponyfills.FormData) {
ponyfills.FormData = undici.FormData;
}
if (!ponyfills.File) {
ponyfills.File = undici.File
}
} else {
const nodeFetch = require("node-fetch");
const realFetch = ponyfills.fetch || nodeFetch.default || nodeFetch;
if (!ponyfills.Headers) {
ponyfills.Headers = nodeFetch.Headers;
// Sveltekit
if (globalThis.Headers && nodeMajor < 18) {
Object.defineProperty(globalThis.Headers, Symbol.hasInstance, {
value(obj) {
return obj && obj.get && obj.set && obj.delete && obj.has && obj.append;
},
configurable: true,
})
}
}
const formDataEncoderModule = require("form-data-encoder");
const streams = require("stream");
const formDataModule = require("formdata-node");
if (!ponyfills.FormData) {
ponyfills.FormData = formDataModule.FormData
}
if (!ponyfills.File) {
ponyfills.File = formDataModule.File
}
const OriginalRequest = ponyfills.Request || nodeFetch.Request;
class Request extends OriginalRequest {
constructor(requestOrUrl, options) {
if (typeof requestOrUrl === "string" || requestOrUrl instanceof URL) {
// Support schemaless URIs on the server for parity with the browser.
// Ex: //github.com/ -> https://github.com/
if (/^\/\//.test(requestOrUrl.toString())) {
requestOrUrl = "https:" + requestOrUrl.toString();
}
const fixedOptions = {
...options
};
fixedOptions.headers = new ponyfills.Headers(fixedOptions.headers || {});
fixedOptions.headers.set('Connection', 'keep-alive');
if (fixedOptions.body != null) {
if (fixedOptions.body[Symbol.toStringTag] === 'FormData') {
const encoder = new formDataEncoderModule.FormDataEncoder(fixedOptions.body)
for (const headerKey in encoder.headers) {
fixedOptions.headers.set(headerKey, encoder.headers[headerKey])
}
fixedOptions.body = streams.Readable.from(encoder);
} else if (fixedOptions.body[Symbol.toStringTag] === 'ReadableStream') {
fixedOptions.body = readableStreamToReadable(fixedOptions.body);
}
}
super(requestOrUrl, fixedOptions);
} else {
super(requestOrUrl);
}
this.formData = getFormDataMethod(formDataModule.File, opts.formDataLimits);
}
}
ponyfills.Request = Request;
const fetch = function (requestOrUrl, options) {
if (typeof requestOrUrl === "string" || requestOrUrl instanceof URL) {
return fetch(new Request(requestOrUrl, options));
}
if (requestOrUrl.url.startsWith('file:')) {
return handleFileRequest(requestOrUrl.url, ponyfills.Response);
}
const abortCtrl = new ponyfills.AbortController();
return realFetch(requestOrUrl, {
...options,
signal: abortCtrl.signal
}).then(res => {
return new Proxy(res, {
get(target, prop, receiver) {
if (prop === 'body') {
return new Proxy(res.body, {
get(target, prop, receiver) {
if (prop === Symbol.asyncIterator) {
return () => {
const originalAsyncIterator = target[Symbol.asyncIterator]();
return {
next() {
return originalAsyncIterator.next();
},
return() {
abortCtrl.abort();
return originalAsyncIterator.return();
},
throw(error) {
abortCtrl.abort(error);
return originalAsyncIterator.throw(error);
}
}
}
}
return Reflect.get(target, prop, receiver);
}
})
}
return Reflect.get(target, prop, receiver);
}
})
});
};
ponyfills.fetch = fetch;
const OriginalResponse = ponyfills.Response || nodeFetch.Response;
ponyfills.Response = function Response(body, init) {
if (body != null && body[Symbol.toStringTag] === 'ReadableStream') {
const actualBody = readableStreamToReadable(body);
// Polyfill ReadableStream is not working well with node-fetch's Response
return new OriginalResponse(actualBody, init);
}
return new OriginalResponse(body, init);
};
}
}
if (!ponyfills.Response.redirect) {

@@ -294,0 +48,0 @@ ponyfills.Response.redirect = function (url, status = 302) {

const busboy = require('busboy');
const { resolve } = require('path');
const streams = require("stream");

@@ -4,0 +3,0 @@

{
"name": "@whatwg-node/fetch",
"version": "0.5.3",
"version": "0.5.4-alpha-20221225155445-dfcb269",
"description": "Cross Platform Smart Fetch Ponyfill",

@@ -22,9 +22,3 @@ "author": "Arda TANRIKULU <ardatanrikulu@gmail.com>",

"@peculiar/webcrypto": "^1.4.0",
"abort-controller": "^3.0.0",
"busboy": "^1.6.0",
"form-data-encoder": "^1.7.1",
"formdata-node": "^4.3.1",
"node-fetch": "^2.6.7",
"undici": "^5.12.0",
"web-streams-polyfill": "^3.2.0"
"busboy": "^1.6.0"
},

@@ -31,0 +25,0 @@ "publishConfig": {

@@ -1,36 +0,34 @@

import { createTestContainer } from '../../server/test/create-test-container';
import * as fetchAPI from '@whatwg-node/fetch'
describe('getFormDataMethod', () => {
createTestContainer(fetchAPI => {
it('should parse fields correctly', async () => {
const formData = new fetchAPI.FormData();
formData.append('greetings', 'Hello world!');
formData.append('bye', 'Goodbye world!');
const request = new fetchAPI.Request('http://localhost:8080', {
method: 'POST',
body: formData,
});
const formdata = await request.formData();
expect(formdata.get('greetings')).toBe('Hello world!');
expect(formdata.get('bye')).toBe('Goodbye world!');
it('should parse fields correctly', async () => {
const formData = new fetchAPI.FormData();
formData.append('greetings', 'Hello world!');
formData.append('bye', 'Goodbye world!');
const request = new fetchAPI.Request('http://localhost:8080', {
method: 'POST',
body: formData,
});
it('should parse and receive text files correctly', async () => {
const formData = new fetchAPI.FormData();
const greetingsFile = new fetchAPI.File(['Hello world!'], 'greetings.txt', { type: 'text/plain' });
const byeFile = new fetchAPI.File(['Goodbye world!'], 'bye.txt', { type: 'text/plain' });
formData.append('greetings', greetingsFile);
formData.append('bye', byeFile);
const request = new fetchAPI.Request('http://localhost:8080', {
method: 'POST',
body: formData,
});
const formdata = await request.formData();
const receivedGreetingsFile = formdata.get('greetings') as File;
const receivedGreetingsText = await receivedGreetingsFile.text();
expect(receivedGreetingsText).toBe('Hello world!');
const receivedByeFile = formdata.get('bye') as File;
const receivedByeText = await receivedByeFile.text();
expect(receivedByeText).toBe('Goodbye world!');
const formdata = await request.formData();
expect(formdata.get('greetings')).toBe('Hello world!');
expect(formdata.get('bye')).toBe('Goodbye world!');
});
it('should parse and receive text files correctly', async () => {
const formData = new fetchAPI.FormData();
const greetingsFile = new fetchAPI.File(['Hello world!'], 'greetings.txt', { type: 'text/plain' });
const byeFile = new fetchAPI.File(['Goodbye world!'], 'bye.txt', { type: 'text/plain' });
formData.append('greetings', greetingsFile);
formData.append('bye', byeFile);
const request = new fetchAPI.Request('http://localhost:8080', {
method: 'POST',
body: formData,
});
const formdata = await request.formData();
const receivedGreetingsFile = formdata.get('greetings') as File;
const receivedGreetingsText = await receivedGreetingsFile.text();
expect(receivedGreetingsText).toBe('Hello world!');
const receivedByeFile = formdata.get('bye') as File;
const receivedByeText = await receivedByeFile.text();
expect(receivedByeText).toBe('Goodbye world!');
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc