@whatwg-node/fetch 0.4.7 → 0.5.1-alpha-20221028013012-a9e07ae
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/CHANGELOG.md +12 -0
- package/dist/create-node-ponyfill.js +6 -0
- package/dist/getFormDataMethod.js +13 -74
- package/dist/index.d.ts +0 -2
- package/package.json +2 -2
- package/tests/getFormDataMethod.spec.ts +30 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @whatwg-node/fetch
|
|
2
2
|
|
|
3
|
+
## 0.5.1-alpha-20221028013012-a9e07ae
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`a8a7cfc`](https://github.com/ardatan/whatwg-node/commit/a8a7cfcbb98c5ca8fff3b4a6d8638e9208690b61) Thanks [@ardatan](https://github.com/ardatan)! - Fix for new undici
|
|
8
|
+
|
|
9
|
+
## 0.5.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [`ab5fb52`](https://github.com/ardatan/whatwg-node/commit/ab5fb524753bc7a210b1aaf2e1580566907d4713) Thanks [@ardatan](https://github.com/ardatan)! - Drop broken `fieldsFirst` flag
|
|
14
|
+
|
|
3
15
|
## 0.4.7
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -122,6 +122,9 @@ module.exports = function createNodePonyfill(opts = {}) {
|
|
|
122
122
|
class Request extends OriginalRequest {
|
|
123
123
|
constructor(requestOrUrl, options) {
|
|
124
124
|
if (typeof requestOrUrl === "string" || requestOrUrl instanceof URL) {
|
|
125
|
+
if (options != null && typeof options === "object" && !options.duplex) {
|
|
126
|
+
options.duplex = 'half';
|
|
127
|
+
}
|
|
125
128
|
super(requestOrUrl, options);
|
|
126
129
|
const contentType = this.headers.get("content-type");
|
|
127
130
|
if (contentType && contentType.startsWith("multipart/form-data")) {
|
|
@@ -140,6 +143,9 @@ module.exports = function createNodePonyfill(opts = {}) {
|
|
|
140
143
|
|
|
141
144
|
const fetch = function (requestOrUrl, options) {
|
|
142
145
|
if (typeof requestOrUrl === "string" || requestOrUrl instanceof URL) {
|
|
146
|
+
if (options != null && typeof options === "object" && !options.duplex) {
|
|
147
|
+
options.duplex = 'half';
|
|
148
|
+
}
|
|
143
149
|
// We cannot use our ctor because it leaks on Node 18's global fetch
|
|
144
150
|
return originalFetch(requestOrUrl, options);
|
|
145
151
|
}
|
|
@@ -3,31 +3,6 @@ const { resolve } = require('path');
|
|
|
3
3
|
const streams = require("stream");
|
|
4
4
|
|
|
5
5
|
module.exports = function getFormDataMethod(File, limits) {
|
|
6
|
-
function consumeStreamAsFile({
|
|
7
|
-
name,
|
|
8
|
-
filename,
|
|
9
|
-
mimeType,
|
|
10
|
-
fileStream,
|
|
11
|
-
formData,
|
|
12
|
-
}) {
|
|
13
|
-
return new Promise((resolve, reject) => {
|
|
14
|
-
const chunks = [];
|
|
15
|
-
fileStream.on('limit', () => {
|
|
16
|
-
reject(new Error(`File size limit exceeded: ${limits.fileSize} bytes`));
|
|
17
|
-
})
|
|
18
|
-
fileStream.on('data', (chunk) => {
|
|
19
|
-
chunks.push(...chunk);
|
|
20
|
-
})
|
|
21
|
-
fileStream.on('close', () => {
|
|
22
|
-
if (fileStream.truncated) {
|
|
23
|
-
reject(new Error(`File size limit exceeded: ${limits.fileSize} bytes`));
|
|
24
|
-
}
|
|
25
|
-
const file = new File([new Uint8Array(chunks)], filename, { type: mimeType });
|
|
26
|
-
formData.set(name, file);
|
|
27
|
-
resolve(file);
|
|
28
|
-
});
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
6
|
|
|
32
7
|
return function formData() {
|
|
33
8
|
if (this.body == null) {
|
|
@@ -57,56 +32,20 @@ module.exports = function getFormDataMethod(File, limits) {
|
|
|
57
32
|
reject(new Error(`Fields limit exceeded: ${limits.fields}`));
|
|
58
33
|
})
|
|
59
34
|
bb.on('file', (name, fileStream, { filename, mimeType }) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
switch(prop) {
|
|
71
|
-
case 'name':
|
|
72
|
-
return filename;
|
|
73
|
-
case 'type':
|
|
74
|
-
return mimeType;
|
|
75
|
-
case 'stream':
|
|
76
|
-
return () => fileStream;
|
|
77
|
-
case 'size':
|
|
78
|
-
throw new Error(`Cannot access file size before consuming the stream.`);
|
|
79
|
-
case 'slice':
|
|
80
|
-
throw new Error(`Cannot slice file before consuming the stream.`);
|
|
81
|
-
case 'text':
|
|
82
|
-
case 'arrayBuffer':
|
|
83
|
-
return () => {
|
|
84
|
-
if (!file$) {
|
|
85
|
-
file$ = consumeStreamAsFile({
|
|
86
|
-
name,
|
|
87
|
-
filename,
|
|
88
|
-
mimeType,
|
|
89
|
-
fileStream,
|
|
90
|
-
formData,
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
return file$.then(file => file[prop]());
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
}))
|
|
98
|
-
} else {
|
|
99
|
-
if (!file$) {
|
|
100
|
-
file$ = consumeStreamAsFile({
|
|
101
|
-
name,
|
|
102
|
-
filename,
|
|
103
|
-
mimeType,
|
|
104
|
-
fileStream,
|
|
105
|
-
formData,
|
|
106
|
-
})
|
|
35
|
+
const chunks = [];
|
|
36
|
+
fileStream.on('limit', () => {
|
|
37
|
+
reject(new Error(`File size limit exceeded: ${limits.fileSize} bytes`));
|
|
38
|
+
})
|
|
39
|
+
fileStream.on('data', (chunk) => {
|
|
40
|
+
chunks.push(Buffer.from(chunk));
|
|
41
|
+
})
|
|
42
|
+
fileStream.on('close', () => {
|
|
43
|
+
if (fileStream.truncated) {
|
|
44
|
+
reject(new Error(`File size limit exceeded: ${limits.fileSize} bytes`));
|
|
107
45
|
}
|
|
108
|
-
file
|
|
109
|
-
|
|
46
|
+
const file = new File(chunks, filename, { type: mimeType });
|
|
47
|
+
formData.set(name, file);
|
|
48
|
+
});
|
|
110
49
|
})
|
|
111
50
|
bb.on('filesLimit', () => {
|
|
112
51
|
reject(new Error(`Files limit exceeded: ${limits.files}`));
|
package/dist/index.d.ts
CHANGED
|
@@ -47,8 +47,6 @@ declare module "@whatwg-node/fetch" {
|
|
|
47
47
|
parts?: number;
|
|
48
48
|
/* For multipart forms, the max number of header key-value pairs to parse. Default: 2000. */
|
|
49
49
|
headerSize?: number;
|
|
50
|
-
/* For multipart forms, enable this if your data has fields first, then files. Default: false. */
|
|
51
|
-
fieldsFirst?: boolean;
|
|
52
50
|
}
|
|
53
51
|
export const createFetch: (opts?: { useNodeFetch?: boolean; formDataLimits?: FormDataLimits }) => ({
|
|
54
52
|
fetch: typeof _fetch,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@whatwg-node/fetch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1-alpha-20221028013012-a9e07ae",
|
|
4
4
|
"description": "Cross Platform Smart Fetch Ponyfill",
|
|
5
5
|
"author": "Arda TANRIKULU <ardatanrikulu@gmail.com>",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"form-data-encoder": "^1.7.1",
|
|
25
25
|
"formdata-node": "^4.3.1",
|
|
26
26
|
"node-fetch": "^2.6.7",
|
|
27
|
-
"undici": "^5.
|
|
27
|
+
"undici": "^5.12.0",
|
|
28
28
|
"web-streams-polyfill": "^3.2.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
@@ -1,47 +1,36 @@
|
|
|
1
1
|
import { createTestContainer } from '../../server/test/create-test-container';
|
|
2
2
|
|
|
3
3
|
describe('getFormDataMethod', () => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const receivedByeFile = formdata.get('bye') as File;
|
|
35
|
-
const receivedByeText = await receivedByeFile.text();
|
|
36
|
-
expect(receivedByeText).toBe('Goodbye world!');
|
|
37
|
-
});
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
formDataLimits: {
|
|
41
|
-
fieldsFirst: fieldsFirstFlag === 'fieldsFirst:true',
|
|
42
|
-
},
|
|
43
|
-
}
|
|
44
|
-
);
|
|
4
|
+
createTestContainer(fetchAPI => {
|
|
5
|
+
it('should parse fields correctly', async () => {
|
|
6
|
+
const formData = new fetchAPI.FormData();
|
|
7
|
+
formData.append('greetings', 'Hello world!');
|
|
8
|
+
formData.append('bye', 'Goodbye world!');
|
|
9
|
+
const request = new fetchAPI.Request('http://localhost:8080', {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
body: formData,
|
|
12
|
+
});
|
|
13
|
+
const formdata = await request.formData();
|
|
14
|
+
expect(formdata.get('greetings')).toBe('Hello world!');
|
|
15
|
+
expect(formdata.get('bye')).toBe('Goodbye world!');
|
|
16
|
+
});
|
|
17
|
+
it('should parse and receive text files correctly', async () => {
|
|
18
|
+
const formData = new fetchAPI.FormData();
|
|
19
|
+
const greetingsFile = new fetchAPI.File(['Hello world!'], 'greetings.txt', { type: 'text/plain' });
|
|
20
|
+
const byeFile = new fetchAPI.File(['Goodbye world!'], 'bye.txt', { type: 'text/plain' });
|
|
21
|
+
formData.append('greetings', greetingsFile);
|
|
22
|
+
formData.append('bye', byeFile);
|
|
23
|
+
const request = new fetchAPI.Request('http://localhost:8080', {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
body: formData,
|
|
26
|
+
});
|
|
27
|
+
const formdata = await request.formData();
|
|
28
|
+
const receivedGreetingsFile = formdata.get('greetings') as File;
|
|
29
|
+
const receivedGreetingsText = await receivedGreetingsFile.text();
|
|
30
|
+
expect(receivedGreetingsText).toBe('Hello world!');
|
|
31
|
+
const receivedByeFile = formdata.get('bye') as File;
|
|
32
|
+
const receivedByeText = await receivedByeFile.text();
|
|
33
|
+
expect(receivedByeText).toBe('Goodbye world!');
|
|
45
34
|
});
|
|
46
35
|
});
|
|
47
36
|
});
|