Skip to content

Commit c3dc581

Browse files
almeidxJiralite
andauthored
fix: attachment sending (#11015)
* fix: attachment sending * test: add tests --------- Co-authored-by: Jiralite <[email protected]>
1 parent 593369d commit c3dc581

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

packages/rest/__tests__/UndiciRequest.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Blob, Buffer } from 'node:buffer';
22
import { URLSearchParams } from 'node:url';
3-
import { MockAgent, setGlobalDispatcher } from 'undici';
3+
import { MockAgent, setGlobalDispatcher, FormData as UndiciFormData } from 'undici';
44
import type { Interceptable, MockInterceptor } from 'undici/types/mock-interceptor.js';
55
import { beforeEach, afterEach, test, expect, vitest } from 'vitest';
66
import { REST } from '../src/index.js';
@@ -77,6 +77,26 @@ test('resolveBody', async () => {
7777
};
7878
await expect(resolveBody(asyncIterable)).resolves.toStrictEqual(Buffer.from([1, 2, 3, 1, 2, 3, 1, 2, 3]));
7979

80+
{
81+
const fd = new globalThis.FormData();
82+
fd.append('key', 'value');
83+
84+
const resolved = await resolveBody(fd);
85+
86+
expect(resolved).toBeInstanceOf(UndiciFormData);
87+
expect([...(resolved as UndiciFormData).entries()]).toStrictEqual([['key', 'value']]);
88+
}
89+
90+
{
91+
const ufd = new UndiciFormData();
92+
ufd.append('key', 'value');
93+
94+
const resolved = await resolveBody(ufd);
95+
96+
expect(resolved).toBeInstanceOf(UndiciFormData);
97+
expect([...(resolved as UndiciFormData).entries()]).toStrictEqual([['key', 'value']]);
98+
}
99+
80100
// Unknown type
81101
// @ts-expect-error: This test is ensuring that this throws
82102
await expect(resolveBody(true)).rejects.toThrow(TypeError);

packages/rest/src/strategies/undiciRequest.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { STATUS_CODES } from 'node:http';
22
import { URLSearchParams } from 'node:url';
33
import { types } from 'node:util';
4-
import { type RequestInit, request, Headers } from 'undici';
4+
import { type RequestInit, request, Headers, FormData as UndiciFormData } from 'undici';
55
import type { HeaderRecord } from 'undici/types/header.js';
66
import type { ResponseLike } from '../shared.js';
77

@@ -52,8 +52,10 @@ export async function resolveBody(body: RequestInit['body']): Promise<Exclude<Re
5252
return new Uint8Array(body.buffer);
5353
} else if (body instanceof Blob) {
5454
return new Uint8Array(await body.arrayBuffer());
55-
} else if (body instanceof FormData) {
55+
} else if (body instanceof UndiciFormData) {
5656
return body;
57+
} else if (body instanceof FormData) {
58+
return globalToUndiciFormData(body);
5759
} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {
5860
const chunks = [...(body as Iterable<Uint8Array>)];
5961

@@ -70,3 +72,17 @@ export async function resolveBody(body: RequestInit['body']): Promise<Exclude<Re
7072

7173
throw new TypeError(`Unable to resolve body.`);
7274
}
75+
76+
function globalToUndiciFormData(fd: globalThis.FormData): UndiciFormData {
77+
const clone = new UndiciFormData();
78+
79+
for (const [name, value] of fd.entries()) {
80+
if (typeof value === 'string') {
81+
clone.append(name, value);
82+
} else {
83+
clone.append(name, value, value.name);
84+
}
85+
}
86+
87+
return clone;
88+
}

0 commit comments

Comments
 (0)