mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-18 04:23:31 +01:00
refactor(rest): switch api to fetch-like and provide strategies (#9416)
BREAKING CHANGE: NodeJS v18+ is required when using node due to the use of global `fetch` BREAKING CHANGE: The raw method of REST now returns a web compatible `Respone` object. BREAKING CHANGE: The `parseResponse` utility method has been updated to operate on a web compatible `Response` object. BREAKING CHANGE: Many underlying internals have changed, some of which were exported. BREAKING CHANGE: `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead.
This commit is contained in:
70
packages/rest/src/strategies/undiciRequest.ts
Normal file
70
packages/rest/src/strategies/undiciRequest.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Buffer } from 'node:buffer';
|
||||
import { URLSearchParams } from 'node:url';
|
||||
import { types } from 'node:util';
|
||||
import { type RequestInit, request } from 'undici';
|
||||
import type { ResponseLike } from '../index.js';
|
||||
|
||||
export type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>;
|
||||
|
||||
export async function makeRequest(url: string, init: RequestInit): Promise<ResponseLike> {
|
||||
// The cast is necessary because `headers` and `method` are narrower types in `undici.request`
|
||||
// our request path guarantees they are of acceptable type for `undici.request`
|
||||
const options = {
|
||||
...init,
|
||||
body: await resolveBody(init.body),
|
||||
} as RequestOptions;
|
||||
const res = await request(url, options);
|
||||
return {
|
||||
body: res.body,
|
||||
async arrayBuffer() {
|
||||
return res.body.arrayBuffer();
|
||||
},
|
||||
async json() {
|
||||
return res.body.json();
|
||||
},
|
||||
async text() {
|
||||
return res.body.text();
|
||||
},
|
||||
get bodyUsed() {
|
||||
return res.body.bodyUsed;
|
||||
},
|
||||
headers: new Headers(res.headers as Record<string, string[] | string>),
|
||||
status: res.statusCode,
|
||||
ok: res.statusCode >= 200 && res.statusCode < 300,
|
||||
};
|
||||
}
|
||||
|
||||
export async function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>> {
|
||||
// eslint-disable-next-line no-eq-null, eqeqeq
|
||||
if (body == null) {
|
||||
return null;
|
||||
} else if (typeof body === 'string') {
|
||||
return body;
|
||||
} else if (types.isUint8Array(body)) {
|
||||
return body;
|
||||
} else if (types.isArrayBuffer(body)) {
|
||||
return new Uint8Array(body);
|
||||
} else if (body instanceof URLSearchParams) {
|
||||
return body.toString();
|
||||
} else if (body instanceof DataView) {
|
||||
return new Uint8Array(body.buffer);
|
||||
} else if (body instanceof Blob) {
|
||||
return new Uint8Array(await body.arrayBuffer());
|
||||
} else if (body instanceof FormData) {
|
||||
return body;
|
||||
} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {
|
||||
const chunks = [...(body as Iterable<Uint8Array>)];
|
||||
|
||||
return Buffer.concat(chunks);
|
||||
} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {
|
||||
const chunks: Uint8Array[] = [];
|
||||
|
||||
for await (const chunk of body as AsyncIterable<Uint8Array>) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
throw new TypeError(`Unable to resolve body.`);
|
||||
}
|
||||
Reference in New Issue
Block a user