refactor: migrate from node-fetch to undici and clean up dependencies

This commit is contained in:
Elysia
2024-11-27 16:10:54 +07:00
parent d1df7cbca2
commit 38bff20b1b
8 changed files with 44 additions and 50 deletions

View File

@@ -58,12 +58,11 @@
"discord-api-types": "^0.37.103", "discord-api-types": "^0.37.103",
"fetch-cookie": "^2.1.0", "fetch-cookie": "^2.1.0",
"find-process": "^1.4.7", "find-process": "^1.4.7",
"form-data": "^4.0.1",
"node-fetch": "^2.6.9",
"prism-media": "^1.3.5", "prism-media": "^1.3.5",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"tough-cookie": "^4.1.4", "tough-cookie": "^4.1.4",
"tree-kill": "^1.2.2", "tree-kill": "^1.2.2",
"undici": "^6.21.0",
"ws": "^8.16.0" "ws": "^8.16.0"
}, },
"engines": { "engines": {
@@ -76,7 +75,6 @@
"@discordjs/docgen": "^0.11.1", "@discordjs/docgen": "^0.11.1",
"@favware/npm-deprecate": "^1.0.7", "@favware/npm-deprecate": "^1.0.7",
"@types/node": "^20.14.12", "@types/node": "^20.14.12",
"@types/node-fetch": "^2.6.11",
"@types/ws": "^8.5.10", "@types/ws": "^8.5.10",
"conventional-changelog-cli": "^2.2.2", "conventional-changelog-cli": "^2.2.2",
"dtslint": "^4.2.1", "dtslint": "^4.2.1",

56
pnpm-lock.yaml generated
View File

@@ -29,12 +29,6 @@ importers:
find-process: find-process:
specifier: ^1.4.7 specifier: ^1.4.7
version: 1.4.7 version: 1.4.7
form-data:
specifier: ^4.0.1
version: 4.0.1
node-fetch:
specifier: ^2.6.9
version: 2.7.0(encoding@0.1.13)
prism-media: prism-media:
specifier: ^1.3.5 specifier: ^1.3.5
version: 1.3.5 version: 1.3.5
@@ -47,6 +41,9 @@ importers:
tree-kill: tree-kill:
specifier: ^1.2.2 specifier: ^1.2.2
version: 1.2.2 version: 1.2.2
undici:
specifier: ^6.21.0
version: 6.21.0
ws: ws:
specifier: ^8.16.0 specifier: ^8.16.0
version: 8.18.0 version: 8.18.0
@@ -66,9 +63,6 @@ importers:
'@types/node': '@types/node':
specifier: ^20.14.12 specifier: ^20.14.12
version: 20.14.12 version: 20.14.12
'@types/node-fetch':
specifier: ^2.6.11
version: 2.6.11
'@types/ws': '@types/ws':
specifier: ^8.5.10 specifier: ^8.5.10
version: 8.5.11 version: 8.5.11
@@ -359,12 +353,12 @@ packages:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'} engines: {node: '>=12'}
'@definitelytyped/header-parser@0.2.13': '@definitelytyped/header-parser@0.2.16':
resolution: {integrity: sha512-m7YEtGhwAjmQyJQFQ7q8+hTGTiC/WrdRATvw8fyTwgW+RiWUt8MAeehuFj4txnCYXDcLO0ozuW5gNrLoYR4Ubg==} resolution: {integrity: sha512-UFsgPft5bhZn07UNGz/9ck4AhdKgLFEOmi2DNr7gXcGL89zbe3u5oVafKUT8j1HOtSBjT8ZEQsXHKlbq+wwF/Q==}
engines: {node: '>=18.18.0'} engines: {node: '>=18.18.0'}
'@definitelytyped/typescript-versions@0.1.4': '@definitelytyped/typescript-versions@0.1.6':
resolution: {integrity: sha512-4Rz5kCpyxofwXCtBQaNfmWYXZcH0sMJxpbIgJzS+PAxgFCAa9W+2Jil7rrkpzsjx9E7+zOPukbXBXjyXohcyuQ==} resolution: {integrity: sha512-gQpXFteIKrOw4ldmBZQfBrD3WobaIG1SwOr/3alXWkcYbkOWa2NRxQbiaYQ2IvYTGaZK26miJw0UOAFiuIs4gA==}
engines: {node: '>=18.18.0'} engines: {node: '>=18.18.0'}
'@definitelytyped/utils@0.1.8': '@definitelytyped/utils@0.1.8':
@@ -653,9 +647,6 @@ packages:
'@types/minimist@1.2.5': '@types/minimist@1.2.5':
resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
'@types/node-fetch@2.6.11':
resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==}
'@types/node@18.19.41': '@types/node@18.19.41':
resolution: {integrity: sha512-LX84pRJ+evD2e2nrgYCHObGWkiQJ1mL+meAgbvnwk/US6vmMY7S2ygBTGV2Jw91s9vUsLSXeDEkUHZIJGLrhsg==} resolution: {integrity: sha512-LX84pRJ+evD2e2nrgYCHObGWkiQJ1mL+meAgbvnwk/US6vmMY7S2ygBTGV2Jw91s9vUsLSXeDEkUHZIJGLrhsg==}
@@ -1698,10 +1689,6 @@ packages:
resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
engines: {node: '>= 0.12'} engines: {node: '>= 0.12'}
form-data@4.0.1:
resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
engines: {node: '>= 6'}
fs-extra@10.1.0: fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -3697,6 +3684,10 @@ packages:
undici-types@5.26.5: undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
undici@6.21.0:
resolution: {integrity: sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==}
engines: {node: '>=18.17'}
unique-filename@3.0.0: unique-filename@3.0.0:
resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -4243,13 +4234,13 @@ snapshots:
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.9 '@jridgewell/trace-mapping': 0.3.9
'@definitelytyped/header-parser@0.2.13': '@definitelytyped/header-parser@0.2.16':
dependencies: dependencies:
'@definitelytyped/typescript-versions': 0.1.4 '@definitelytyped/typescript-versions': 0.1.6
'@definitelytyped/utils': 0.1.8 '@definitelytyped/utils': 0.1.8
semver: 7.6.3 semver: 7.6.3
'@definitelytyped/typescript-versions@0.1.4': {} '@definitelytyped/typescript-versions@0.1.6': {}
'@definitelytyped/utils@0.1.8': '@definitelytyped/utils@0.1.8':
dependencies: dependencies:
@@ -4679,11 +4670,6 @@ snapshots:
'@types/minimist@1.2.5': {} '@types/minimist@1.2.5': {}
'@types/node-fetch@2.6.11':
dependencies:
'@types/node': 18.19.41
form-data: 4.0.1
'@types/node@18.19.41': '@types/node@18.19.41':
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
@@ -5477,7 +5463,7 @@ snapshots:
dts-critic@3.3.11(typescript@5.5.4): dts-critic@3.3.11(typescript@5.5.4):
dependencies: dependencies:
'@definitelytyped/header-parser': 0.2.13 '@definitelytyped/header-parser': 0.2.16
command-exists: 1.2.9 command-exists: 1.2.9
rimraf: 3.0.2 rimraf: 3.0.2
semver: 6.3.1 semver: 6.3.1
@@ -5487,8 +5473,8 @@ snapshots:
dtslint@4.2.1(typescript@5.5.4): dtslint@4.2.1(typescript@5.5.4):
dependencies: dependencies:
'@definitelytyped/header-parser': 0.2.13 '@definitelytyped/header-parser': 0.2.16
'@definitelytyped/typescript-versions': 0.1.4 '@definitelytyped/typescript-versions': 0.1.6
'@definitelytyped/utils': 0.1.8 '@definitelytyped/utils': 0.1.8
dts-critic: 3.3.11(typescript@5.5.4) dts-critic: 3.3.11(typescript@5.5.4)
fs-extra: 6.0.1 fs-extra: 6.0.1
@@ -5962,12 +5948,6 @@ snapshots:
combined-stream: 1.0.8 combined-stream: 1.0.8
mime-types: 2.1.35 mime-types: 2.1.35
form-data@4.0.1:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
fs-extra@10.1.0: fs-extra@10.1.0:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@@ -8248,6 +8228,8 @@ snapshots:
undici-types@5.26.5: {} undici-types@5.26.5: {}
undici@6.21.0: {}
unique-filename@3.0.0: unique-filename@3.0.0:
dependencies: dependencies:
unique-slug: 4.0.0 unique-slug: 4.0.0

View File

@@ -4,9 +4,8 @@ const Buffer = require('node:buffer').Buffer;
const https = require('node:https'); const https = require('node:https');
const { setTimeout } = require('node:timers'); const { setTimeout } = require('node:timers');
const makeFetchCookie = require('fetch-cookie'); const makeFetchCookie = require('fetch-cookie');
const FormData = require('form-data');
const fetchOriginal = require('node-fetch');
const { CookieJar } = require('tough-cookie'); const { CookieJar } = require('tough-cookie');
const { fetch: fetchOriginal, FormData } = require('undici');
const { ciphers } = require('../util/Constants'); const { ciphers } = require('../util/Constants');
const Util = require('../util/Util'); const Util = require('../util/Util');
@@ -69,7 +68,6 @@ class APIRequest {
const url = API + this.path; const url = API + this.path;
let headers = { let headers = {
authority: 'discord.com',
accept: '*/*', accept: '*/*',
'accept-language': 'en-US', 'accept-language': 'en-US',
'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108"', 'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108"',
@@ -84,9 +82,8 @@ class APIRequest {
'x-super-properties': `${Buffer.from(JSON.stringify(this.client.options.ws.properties), 'ascii').toString( 'x-super-properties': `${Buffer.from(JSON.stringify(this.client.options.ws.properties), 'ascii').toString(
'base64', 'base64',
)}`, )}`,
Referer: 'https://discord.com/channels/@me', referer: 'https://discord.com/channels/@me',
origin: 'https://discord.com', origin: 'https://discord.com',
'Referrer-Policy': 'strict-origin-when-cross-origin',
...this.client.options.http.headers, ...this.client.options.http.headers,
'User-Agent': this.fullUserAgent, 'User-Agent': this.fullUserAgent,
}; };
@@ -152,6 +149,7 @@ class APIRequest {
agent, agent,
body, body,
signal: controller.signal, signal: controller.signal,
redirect: 'follow',
}).finally(() => clearTimeout(timeout)); }).finally(() => clearTimeout(timeout));
} }
} }

View File

@@ -67,6 +67,21 @@ class DiscordAPIError extends Error {
this.captcha = error?.captcha_service ? error : null; this.captcha = error?.captcha_service ? error : null;
} }
/**
* A special `40333` JSON error code is returned if your request is blocked by Cloudflare.
* This may be due to a malformed request or improper user agent.
* The response resembles a normal error structure:
* @type {boolean}
* @example
* {
* "message": "internal network error",
* "code": 40333
* }
*/
get isBlockedByCloudflare() {
return this.code === 40333;
}
/** /**
* Flattens an errors object returned from the API into an array. * Flattens an errors object returned from the API into an array.
* @param {APIError} obj Discord errors object * @param {APIError} obj Discord errors object

View File

@@ -4,7 +4,7 @@ const { Buffer } = require('node:buffer');
const fs = require('node:fs'); const fs = require('node:fs');
const path = require('node:path'); const path = require('node:path');
const stream = require('node:stream'); const stream = require('node:stream');
const fetch = require('node-fetch'); const { fetch } = require('undici');
const { Error: DiscordError, TypeError } = require('../errors'); const { Error: DiscordError, TypeError } = require('../errors');
const Invite = require('../structures/Invite'); const Invite = require('../structures/Invite');

View File

@@ -5,7 +5,7 @@ const crypto = require('node:crypto');
const EventEmitter = require('node:events'); const EventEmitter = require('node:events');
const { StringDecoder } = require('node:string_decoder'); const { StringDecoder } = require('node:string_decoder');
const { setTimeout } = require('node:timers'); const { setTimeout } = require('node:timers');
const fetch = require('node-fetch'); const { fetch } = require('undici');
const WebSocket = require('ws'); const WebSocket = require('ws');
const { UserAgent } = require('./Constants'); const { UserAgent } = require('./Constants');
const Options = require('./Options'); const Options = require('./Options');

View File

@@ -5,7 +5,7 @@ const { parse } = require('node:path');
const process = require('node:process'); const process = require('node:process');
const { setTimeout } = require('node:timers'); const { setTimeout } = require('node:timers');
const { Collection } = require('@discordjs/collection'); const { Collection } = require('@discordjs/collection');
const fetch = require('node-fetch'); const { fetch } = require('undici');
const { Colors, Events } = require('./Constants'); const { Colors, Events } = require('./Constants');
const { Error: DiscordError, RangeError, TypeError } = require('../errors'); const { Error: DiscordError, RangeError, TypeError } = require('../errors');
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k); const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);

5
typings/index.d.ts vendored
View File

@@ -61,7 +61,7 @@ import {
import { ChildProcess, ChildProcessWithoutNullStreams } from 'node:child_process'; import { ChildProcess, ChildProcessWithoutNullStreams } from 'node:child_process';
import { EventEmitter } from 'node:events'; import { EventEmitter } from 'node:events';
import { AgentOptions } from 'node:https'; import { AgentOptions } from 'node:https';
import { Response } from 'node-fetch'; import { Response } from 'undici';
import { Readable, Writable, Stream } from 'node:stream'; import { Readable, Writable, Stream } from 'node:stream';
import { MessagePort, Worker } from 'node:worker_threads'; import { MessagePort, Worker } from 'node:worker_threads';
import * as WebSocket from 'ws'; import * as WebSocket from 'ws';
@@ -778,7 +778,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
public fetchPremiumStickerPacks(): Promise<Collection<Snowflake, StickerPack>>; public fetchPremiumStickerPacks(): Promise<Collection<Snowflake, StickerPack>>;
public fetchWebhook(id: Snowflake, token?: string): Promise<Webhook>; public fetchWebhook(id: Snowflake, token?: string): Promise<Webhook>;
public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>; public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>;
public refreshAttachmentURL(urls: string[]): Promise<{ original: string, refreshed: string }[]>; public refreshAttachmentURL(urls: string[]): Promise<{ original: string; refreshed: string }[]>;
public sleep(timeout: number): Promise<void>; public sleep(timeout: number): Promise<void>;
public login(token?: string): Promise<string>; public login(token?: string): Promise<string>;
/** @deprecated This method will not be updated until I find the most convenient way to implement MFA. */ /** @deprecated This method will not be updated until I find the most convenient way to implement MFA. */
@@ -1382,6 +1382,7 @@ export class DiscordAPIError extends Error {
public requestData: HTTPErrorData; public requestData: HTTPErrorData;
public retries: number; public retries: number;
public captcha: Captcha | null; public captcha: Captcha | null;
public readonly isBlockedByCloudflare: boolean;
} }
export interface Captcha { export interface Captcha {