@discordjs/rest 1.2.0-dev.1661213496-2ecb862.0 → 1.2.0-dev.1662250232-d08a57c.0
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/dist/index.d.ts +839 -9
- package/dist/index.js +1009 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +965 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -21
- package/dist/index.cjs +0 -31
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/CDN.cjs +0 -87
- package/dist/lib/CDN.cjs.map +0 -1
- package/dist/lib/CDN.d.ts +0 -199
- package/dist/lib/CDN.d.ts.map +0 -1
- package/dist/lib/CDN.mjs +0 -83
- package/dist/lib/CDN.mjs.map +0 -1
- package/dist/lib/REST.cjs +0 -61
- package/dist/lib/REST.cjs.map +0 -1
- package/dist/lib/REST.d.ts +0 -279
- package/dist/lib/REST.d.ts.map +0 -1
- package/dist/lib/REST.mjs +0 -57
- package/dist/lib/REST.mjs.map +0 -1
- package/dist/lib/RequestManager.cjs +0 -223
- package/dist/lib/RequestManager.cjs.map +0 -1
- package/dist/lib/RequestManager.d.ts +0 -232
- package/dist/lib/RequestManager.d.ts.map +0 -1
- package/dist/lib/RequestManager.mjs +0 -218
- package/dist/lib/RequestManager.mjs.map +0 -1
- package/dist/lib/errors/DiscordAPIError.cjs +0 -55
- package/dist/lib/errors/DiscordAPIError.cjs.map +0 -1
- package/dist/lib/errors/DiscordAPIError.d.ts +0 -53
- package/dist/lib/errors/DiscordAPIError.d.ts.map +0 -1
- package/dist/lib/errors/DiscordAPIError.mjs +0 -51
- package/dist/lib/errors/DiscordAPIError.mjs.map +0 -1
- package/dist/lib/errors/HTTPError.cjs +0 -17
- package/dist/lib/errors/HTTPError.cjs.map +0 -1
- package/dist/lib/errors/HTTPError.d.ts +0 -21
- package/dist/lib/errors/HTTPError.d.ts.map +0 -1
- package/dist/lib/errors/HTTPError.mjs +0 -13
- package/dist/lib/errors/HTTPError.mjs.map +0 -1
- package/dist/lib/errors/RateLimitError.cjs +0 -23
- package/dist/lib/errors/RateLimitError.cjs.map +0 -1
- package/dist/lib/errors/RateLimitError.d.ts +0 -17
- package/dist/lib/errors/RateLimitError.d.ts.map +0 -1
- package/dist/lib/errors/RateLimitError.mjs +0 -19
- package/dist/lib/errors/RateLimitError.mjs.map +0 -1
- package/dist/lib/handlers/IHandler.d.ts +0 -23
- package/dist/lib/handlers/IHandler.d.ts.map +0 -1
- package/dist/lib/handlers/SequentialHandler.cjs +0 -305
- package/dist/lib/handlers/SequentialHandler.cjs.map +0 -1
- package/dist/lib/handlers/SequentialHandler.d.ts +0 -83
- package/dist/lib/handlers/SequentialHandler.d.ts.map +0 -1
- package/dist/lib/handlers/SequentialHandler.mjs +0 -301
- package/dist/lib/handlers/SequentialHandler.mjs.map +0 -1
- package/dist/lib/utils/constants.cjs +0 -49
- package/dist/lib/utils/constants.cjs.map +0 -1
- package/dist/lib/utils/constants.d.ts +0 -21
- package/dist/lib/utils/constants.d.ts.map +0 -1
- package/dist/lib/utils/constants.mjs +0 -49
- package/dist/lib/utils/constants.mjs.map +0 -1
- package/dist/lib/utils/utils.cjs +0 -111
- package/dist/lib/utils/utils.cjs.map +0 -1
- package/dist/lib/utils/utils.d.ts +0 -32
- package/dist/lib/utils/utils.d.ts.map +0 -1
- package/dist/lib/utils/utils.mjs +0 -103
- package/dist/lib/utils/utils.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,965 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
5
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// package.json
|
|
9
|
+
var require_package = __commonJS({
|
|
10
|
+
"package.json"(exports, module) {
|
|
11
|
+
module.exports = {
|
|
12
|
+
name: "@discordjs/rest",
|
|
13
|
+
version: "1.2.0-dev.1662250232-d08a57c.0",
|
|
14
|
+
description: "The REST API for discord.js",
|
|
15
|
+
scripts: {
|
|
16
|
+
test: "vitest run",
|
|
17
|
+
build: "tsup",
|
|
18
|
+
lint: "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
|
19
|
+
format: "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
|
20
|
+
fmt: "yarn format",
|
|
21
|
+
docs: "downlevel-dts dist docs/dist --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
|
22
|
+
prepack: "yarn lint && yarn test && yarn build",
|
|
23
|
+
changelog: "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/rest/*'",
|
|
24
|
+
release: "cliff-jumper"
|
|
25
|
+
},
|
|
26
|
+
main: "./dist/index.js",
|
|
27
|
+
module: "./dist/index.mjs",
|
|
28
|
+
typings: "./dist/index.d.ts",
|
|
29
|
+
exports: {
|
|
30
|
+
import: "./dist/index.mjs",
|
|
31
|
+
require: "./dist/index.js",
|
|
32
|
+
types: "./dist/index.d.ts"
|
|
33
|
+
},
|
|
34
|
+
directories: {
|
|
35
|
+
lib: "src",
|
|
36
|
+
test: "__tests__"
|
|
37
|
+
},
|
|
38
|
+
files: [
|
|
39
|
+
"dist"
|
|
40
|
+
],
|
|
41
|
+
contributors: [
|
|
42
|
+
"Crawl <icrawltogo@gmail.com>",
|
|
43
|
+
"Amish Shah <amishshah.2k@gmail.com>",
|
|
44
|
+
"SpaceEEC <spaceeec@yahoo.com>",
|
|
45
|
+
"Vlad Frangu <kingdgrizzle@gmail.com>",
|
|
46
|
+
"Antonio Roman <kyradiscord@gmail.com>"
|
|
47
|
+
],
|
|
48
|
+
license: "Apache-2.0",
|
|
49
|
+
keywords: [
|
|
50
|
+
"discord",
|
|
51
|
+
"api",
|
|
52
|
+
"rest",
|
|
53
|
+
"discordapp",
|
|
54
|
+
"discordjs"
|
|
55
|
+
],
|
|
56
|
+
repository: {
|
|
57
|
+
type: "git",
|
|
58
|
+
url: "git+https://github.com/discordjs/discord.js.git"
|
|
59
|
+
},
|
|
60
|
+
bugs: {
|
|
61
|
+
url: "https://github.com/discordjs/discord.js/issues"
|
|
62
|
+
},
|
|
63
|
+
homepage: "https://discord.js.org",
|
|
64
|
+
dependencies: {
|
|
65
|
+
"@discordjs/collection": "workspace:^",
|
|
66
|
+
"@sapphire/async-queue": "^1.5.0",
|
|
67
|
+
"@sapphire/snowflake": "^3.2.2",
|
|
68
|
+
"discord-api-types": "^0.37.5",
|
|
69
|
+
"file-type": "^18.0.0",
|
|
70
|
+
tslib: "^2.4.0",
|
|
71
|
+
undici: "^5.10.0"
|
|
72
|
+
},
|
|
73
|
+
devDependencies: {
|
|
74
|
+
"@discordjs/docgen": "workspace:^",
|
|
75
|
+
"@favware/cliff-jumper": "^1.8.7",
|
|
76
|
+
"@microsoft/api-extractor": "^7.30.0",
|
|
77
|
+
"@types/node": "^16.11.56",
|
|
78
|
+
"@vitest/coverage-c8": "^0.22.1",
|
|
79
|
+
"downlevel-dts": "^0.10.1",
|
|
80
|
+
eslint: "^8.23.0",
|
|
81
|
+
"eslint-config-neon": "^0.1.31",
|
|
82
|
+
prettier: "^2.7.1",
|
|
83
|
+
tsup: "^6.2.3",
|
|
84
|
+
typescript: "^4.8.2",
|
|
85
|
+
vitest: "^0.22.1"
|
|
86
|
+
},
|
|
87
|
+
engines: {
|
|
88
|
+
node: ">=16.9.0"
|
|
89
|
+
},
|
|
90
|
+
publishConfig: {
|
|
91
|
+
access: "public"
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// src/lib/CDN.ts
|
|
98
|
+
import { URL } from "node:url";
|
|
99
|
+
|
|
100
|
+
// src/lib/utils/constants.ts
|
|
101
|
+
import process from "node:process";
|
|
102
|
+
import { APIVersion } from "discord-api-types/v10";
|
|
103
|
+
import { getGlobalDispatcher } from "undici";
|
|
104
|
+
var Package = require_package();
|
|
105
|
+
var DefaultUserAgent = `DiscordBot (${Package.homepage}, ${Package.version})`;
|
|
106
|
+
var DefaultRestOptions = {
|
|
107
|
+
get agent() {
|
|
108
|
+
return getGlobalDispatcher();
|
|
109
|
+
},
|
|
110
|
+
api: "https://discord.com/api",
|
|
111
|
+
authPrefix: "Bot",
|
|
112
|
+
cdn: "https://cdn.discordapp.com",
|
|
113
|
+
headers: {},
|
|
114
|
+
invalidRequestWarningInterval: 0,
|
|
115
|
+
globalRequestsPerSecond: 50,
|
|
116
|
+
offset: 50,
|
|
117
|
+
rejectOnRateLimit: null,
|
|
118
|
+
retries: 3,
|
|
119
|
+
timeout: 15e3,
|
|
120
|
+
userAgentAppendix: `Node.js ${process.version}`,
|
|
121
|
+
version: APIVersion,
|
|
122
|
+
hashSweepInterval: 144e5,
|
|
123
|
+
hashLifetime: 864e5,
|
|
124
|
+
handlerSweepInterval: 36e5
|
|
125
|
+
};
|
|
126
|
+
var RESTEvents = /* @__PURE__ */ ((RESTEvents2) => {
|
|
127
|
+
RESTEvents2["Debug"] = "restDebug";
|
|
128
|
+
RESTEvents2["HandlerSweep"] = "handlerSweep";
|
|
129
|
+
RESTEvents2["HashSweep"] = "hashSweep";
|
|
130
|
+
RESTEvents2["InvalidRequestWarning"] = "invalidRequestWarning";
|
|
131
|
+
RESTEvents2["RateLimited"] = "rateLimited";
|
|
132
|
+
RESTEvents2["Response"] = "response";
|
|
133
|
+
return RESTEvents2;
|
|
134
|
+
})(RESTEvents || {});
|
|
135
|
+
var ALLOWED_EXTENSIONS = ["webp", "png", "jpg", "jpeg", "gif"];
|
|
136
|
+
var ALLOWED_STICKER_EXTENSIONS = ["png", "json"];
|
|
137
|
+
var ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
|
|
138
|
+
|
|
139
|
+
// src/lib/CDN.ts
|
|
140
|
+
var CDN = class {
|
|
141
|
+
constructor(base = DefaultRestOptions.cdn) {
|
|
142
|
+
this.base = base;
|
|
143
|
+
}
|
|
144
|
+
appAsset(clientId, assetHash, options) {
|
|
145
|
+
return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);
|
|
146
|
+
}
|
|
147
|
+
appIcon(clientId, iconHash, options) {
|
|
148
|
+
return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);
|
|
149
|
+
}
|
|
150
|
+
avatar(id, avatarHash, options) {
|
|
151
|
+
return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);
|
|
152
|
+
}
|
|
153
|
+
banner(id, bannerHash, options) {
|
|
154
|
+
return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);
|
|
155
|
+
}
|
|
156
|
+
channelIcon(channelId, iconHash, options) {
|
|
157
|
+
return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);
|
|
158
|
+
}
|
|
159
|
+
defaultAvatar(discriminator) {
|
|
160
|
+
return this.makeURL(`/embed/avatars/${discriminator}`, { extension: "png" });
|
|
161
|
+
}
|
|
162
|
+
discoverySplash(guildId, splashHash, options) {
|
|
163
|
+
return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);
|
|
164
|
+
}
|
|
165
|
+
emoji(emojiId, extension) {
|
|
166
|
+
return this.makeURL(`/emojis/${emojiId}`, { extension });
|
|
167
|
+
}
|
|
168
|
+
guildMemberAvatar(guildId, userId, avatarHash, options) {
|
|
169
|
+
return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);
|
|
170
|
+
}
|
|
171
|
+
guildMemberBanner(guildId, userId, bannerHash, options) {
|
|
172
|
+
return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options);
|
|
173
|
+
}
|
|
174
|
+
icon(id, iconHash, options) {
|
|
175
|
+
return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);
|
|
176
|
+
}
|
|
177
|
+
roleIcon(roleId, roleIconHash, options) {
|
|
178
|
+
return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);
|
|
179
|
+
}
|
|
180
|
+
splash(guildId, splashHash, options) {
|
|
181
|
+
return this.makeURL(`/splashes/${guildId}/${splashHash}`, options);
|
|
182
|
+
}
|
|
183
|
+
sticker(stickerId, extension) {
|
|
184
|
+
return this.makeURL(`/stickers/${stickerId}`, {
|
|
185
|
+
allowedExtensions: ALLOWED_STICKER_EXTENSIONS,
|
|
186
|
+
extension: extension ?? "png"
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
stickerPackBanner(bannerId, options) {
|
|
190
|
+
return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);
|
|
191
|
+
}
|
|
192
|
+
teamIcon(teamId, iconHash, options) {
|
|
193
|
+
return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);
|
|
194
|
+
}
|
|
195
|
+
guildScheduledEventCover(scheduledEventId, coverHash, options) {
|
|
196
|
+
return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);
|
|
197
|
+
}
|
|
198
|
+
dynamicMakeURL(route, hash, { forceStatic = false, ...options } = {}) {
|
|
199
|
+
return this.makeURL(route, !forceStatic && hash.startsWith("a_") ? { ...options, extension: "gif" } : options);
|
|
200
|
+
}
|
|
201
|
+
makeURL(route, { allowedExtensions = ALLOWED_EXTENSIONS, extension = "webp", size } = {}) {
|
|
202
|
+
extension = String(extension).toLowerCase();
|
|
203
|
+
if (!allowedExtensions.includes(extension)) {
|
|
204
|
+
throw new RangeError(`Invalid extension provided: ${extension}
|
|
205
|
+
Must be one of: ${allowedExtensions.join(", ")}`);
|
|
206
|
+
}
|
|
207
|
+
if (size && !ALLOWED_SIZES.includes(size)) {
|
|
208
|
+
throw new RangeError(`Invalid size provided: ${size}
|
|
209
|
+
Must be one of: ${ALLOWED_SIZES.join(", ")}`);
|
|
210
|
+
}
|
|
211
|
+
const url = new URL(`${this.base}${route}.${extension}`);
|
|
212
|
+
if (size) {
|
|
213
|
+
url.searchParams.set("size", String(size));
|
|
214
|
+
}
|
|
215
|
+
return url.toString();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
__name(CDN, "CDN");
|
|
219
|
+
|
|
220
|
+
// src/lib/errors/DiscordAPIError.ts
|
|
221
|
+
function isErrorGroupWrapper(error) {
|
|
222
|
+
return Reflect.has(error, "_errors");
|
|
223
|
+
}
|
|
224
|
+
__name(isErrorGroupWrapper, "isErrorGroupWrapper");
|
|
225
|
+
function isErrorResponse(error) {
|
|
226
|
+
return typeof Reflect.get(error, "message") === "string";
|
|
227
|
+
}
|
|
228
|
+
__name(isErrorResponse, "isErrorResponse");
|
|
229
|
+
var DiscordAPIError = class extends Error {
|
|
230
|
+
constructor(rawError, code, status, method, url, bodyData) {
|
|
231
|
+
super(DiscordAPIError.getMessage(rawError));
|
|
232
|
+
this.rawError = rawError;
|
|
233
|
+
this.code = code;
|
|
234
|
+
this.status = status;
|
|
235
|
+
this.method = method;
|
|
236
|
+
this.url = url;
|
|
237
|
+
this.requestBody = { files: bodyData.files, json: bodyData.body };
|
|
238
|
+
}
|
|
239
|
+
requestBody;
|
|
240
|
+
get name() {
|
|
241
|
+
return `${DiscordAPIError.name}[${this.code}]`;
|
|
242
|
+
}
|
|
243
|
+
static getMessage(error) {
|
|
244
|
+
let flattened = "";
|
|
245
|
+
if ("code" in error) {
|
|
246
|
+
if (error.errors) {
|
|
247
|
+
flattened = [...this.flattenDiscordError(error.errors)].join("\n");
|
|
248
|
+
}
|
|
249
|
+
return error.message && flattened ? `${error.message}
|
|
250
|
+
${flattened}` : error.message || flattened || "Unknown Error";
|
|
251
|
+
}
|
|
252
|
+
return error.error_description ?? "No Description";
|
|
253
|
+
}
|
|
254
|
+
static *flattenDiscordError(obj, key = "") {
|
|
255
|
+
if (isErrorResponse(obj)) {
|
|
256
|
+
return yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim();
|
|
257
|
+
}
|
|
258
|
+
for (const [otherKey, val] of Object.entries(obj)) {
|
|
259
|
+
const nextKey = otherKey.startsWith("_") ? key : key ? Number.isNaN(Number(otherKey)) ? `${key}.${otherKey}` : `${key}[${otherKey}]` : otherKey;
|
|
260
|
+
if (typeof val === "string") {
|
|
261
|
+
yield val;
|
|
262
|
+
} else if (isErrorGroupWrapper(val)) {
|
|
263
|
+
for (const error of val._errors) {
|
|
264
|
+
yield* this.flattenDiscordError(error, nextKey);
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
yield* this.flattenDiscordError(val, nextKey);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
__name(DiscordAPIError, "DiscordAPIError");
|
|
273
|
+
|
|
274
|
+
// src/lib/errors/HTTPError.ts
|
|
275
|
+
var HTTPError = class extends Error {
|
|
276
|
+
constructor(name, status, method, url, bodyData) {
|
|
277
|
+
super();
|
|
278
|
+
this.name = name;
|
|
279
|
+
this.status = status;
|
|
280
|
+
this.method = method;
|
|
281
|
+
this.url = url;
|
|
282
|
+
this.requestBody = { files: bodyData.files, json: bodyData.body };
|
|
283
|
+
}
|
|
284
|
+
requestBody;
|
|
285
|
+
};
|
|
286
|
+
__name(HTTPError, "HTTPError");
|
|
287
|
+
|
|
288
|
+
// src/lib/errors/RateLimitError.ts
|
|
289
|
+
var RateLimitError = class extends Error {
|
|
290
|
+
timeToReset;
|
|
291
|
+
limit;
|
|
292
|
+
method;
|
|
293
|
+
hash;
|
|
294
|
+
url;
|
|
295
|
+
route;
|
|
296
|
+
majorParameter;
|
|
297
|
+
global;
|
|
298
|
+
constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }) {
|
|
299
|
+
super();
|
|
300
|
+
this.timeToReset = timeToReset;
|
|
301
|
+
this.limit = limit;
|
|
302
|
+
this.method = method;
|
|
303
|
+
this.hash = hash;
|
|
304
|
+
this.url = url;
|
|
305
|
+
this.route = route;
|
|
306
|
+
this.majorParameter = majorParameter;
|
|
307
|
+
this.global = global;
|
|
308
|
+
}
|
|
309
|
+
get name() {
|
|
310
|
+
return `${RateLimitError.name}[${this.route}]`;
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
__name(RateLimitError, "RateLimitError");
|
|
314
|
+
|
|
315
|
+
// src/lib/RequestManager.ts
|
|
316
|
+
import { Blob as Blob2, Buffer as Buffer3 } from "node:buffer";
|
|
317
|
+
import { EventEmitter } from "node:events";
|
|
318
|
+
import { setInterval, clearInterval } from "node:timers";
|
|
319
|
+
import { Collection } from "@discordjs/collection";
|
|
320
|
+
import { DiscordSnowflake } from "@sapphire/snowflake";
|
|
321
|
+
import { FormData as FormData2 } from "undici";
|
|
322
|
+
|
|
323
|
+
// src/lib/handlers/SequentialHandler.ts
|
|
324
|
+
import { setTimeout, clearTimeout } from "node:timers";
|
|
325
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
326
|
+
import { AsyncQueue } from "@sapphire/async-queue";
|
|
327
|
+
import { request } from "undici";
|
|
328
|
+
|
|
329
|
+
// src/lib/utils/utils.ts
|
|
330
|
+
import { Blob, Buffer as Buffer2 } from "node:buffer";
|
|
331
|
+
import { URLSearchParams } from "node:url";
|
|
332
|
+
import { types } from "node:util";
|
|
333
|
+
import { FormData } from "undici";
|
|
334
|
+
function parseHeader(header) {
|
|
335
|
+
if (header === void 0 || typeof header === "string") {
|
|
336
|
+
return header;
|
|
337
|
+
}
|
|
338
|
+
return header.join(";");
|
|
339
|
+
}
|
|
340
|
+
__name(parseHeader, "parseHeader");
|
|
341
|
+
function serializeSearchParam(value) {
|
|
342
|
+
switch (typeof value) {
|
|
343
|
+
case "string":
|
|
344
|
+
return value;
|
|
345
|
+
case "number":
|
|
346
|
+
case "bigint":
|
|
347
|
+
case "boolean":
|
|
348
|
+
return value.toString();
|
|
349
|
+
case "object":
|
|
350
|
+
if (value === null)
|
|
351
|
+
return null;
|
|
352
|
+
if (value instanceof Date) {
|
|
353
|
+
return Number.isNaN(value.getTime()) ? null : value.toISOString();
|
|
354
|
+
}
|
|
355
|
+
if (typeof value.toString === "function" && value.toString !== Object.prototype.toString)
|
|
356
|
+
return value.toString();
|
|
357
|
+
return null;
|
|
358
|
+
default:
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
__name(serializeSearchParam, "serializeSearchParam");
|
|
363
|
+
function makeURLSearchParams(options) {
|
|
364
|
+
const params = new URLSearchParams();
|
|
365
|
+
if (!options)
|
|
366
|
+
return params;
|
|
367
|
+
for (const [key, value] of Object.entries(options)) {
|
|
368
|
+
const serialized = serializeSearchParam(value);
|
|
369
|
+
if (serialized !== null)
|
|
370
|
+
params.append(key, serialized);
|
|
371
|
+
}
|
|
372
|
+
return params;
|
|
373
|
+
}
|
|
374
|
+
__name(makeURLSearchParams, "makeURLSearchParams");
|
|
375
|
+
async function parseResponse(res) {
|
|
376
|
+
const header = parseHeader(res.headers["content-type"]);
|
|
377
|
+
if (header?.startsWith("application/json")) {
|
|
378
|
+
return res.body.json();
|
|
379
|
+
}
|
|
380
|
+
return res.body.arrayBuffer();
|
|
381
|
+
}
|
|
382
|
+
__name(parseResponse, "parseResponse");
|
|
383
|
+
function hasSublimit(bucketRoute, body, method) {
|
|
384
|
+
if (bucketRoute === "/channels/:id") {
|
|
385
|
+
if (typeof body !== "object" || body === null)
|
|
386
|
+
return false;
|
|
387
|
+
if (method !== "PATCH" /* Patch */)
|
|
388
|
+
return false;
|
|
389
|
+
const castedBody = body;
|
|
390
|
+
return ["name", "topic"].some((key) => Reflect.has(castedBody, key));
|
|
391
|
+
}
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
__name(hasSublimit, "hasSublimit");
|
|
395
|
+
async function resolveBody(body) {
|
|
396
|
+
if (body == null) {
|
|
397
|
+
return null;
|
|
398
|
+
} else if (typeof body === "string") {
|
|
399
|
+
return body;
|
|
400
|
+
} else if (types.isUint8Array(body)) {
|
|
401
|
+
return body;
|
|
402
|
+
} else if (types.isArrayBuffer(body)) {
|
|
403
|
+
return new Uint8Array(body);
|
|
404
|
+
} else if (body instanceof URLSearchParams) {
|
|
405
|
+
return body.toString();
|
|
406
|
+
} else if (body instanceof DataView) {
|
|
407
|
+
return new Uint8Array(body.buffer);
|
|
408
|
+
} else if (body instanceof Blob) {
|
|
409
|
+
return new Uint8Array(await body.arrayBuffer());
|
|
410
|
+
} else if (body instanceof FormData) {
|
|
411
|
+
return body;
|
|
412
|
+
} else if (body[Symbol.iterator]) {
|
|
413
|
+
const chunks = [...body];
|
|
414
|
+
const length = chunks.reduce((a, b) => a + b.length, 0);
|
|
415
|
+
const uint8 = new Uint8Array(length);
|
|
416
|
+
let lengthUsed = 0;
|
|
417
|
+
return chunks.reduce((a, b) => {
|
|
418
|
+
a.set(b, lengthUsed);
|
|
419
|
+
lengthUsed += b.length;
|
|
420
|
+
return a;
|
|
421
|
+
}, uint8);
|
|
422
|
+
} else if (body[Symbol.asyncIterator]) {
|
|
423
|
+
const chunks = [];
|
|
424
|
+
for await (const chunk of body) {
|
|
425
|
+
chunks.push(chunk);
|
|
426
|
+
}
|
|
427
|
+
return Buffer2.concat(chunks);
|
|
428
|
+
}
|
|
429
|
+
throw new TypeError(`Unable to resolve body.`);
|
|
430
|
+
}
|
|
431
|
+
__name(resolveBody, "resolveBody");
|
|
432
|
+
|
|
433
|
+
// src/lib/handlers/SequentialHandler.ts
|
|
434
|
+
var invalidCount = 0;
|
|
435
|
+
var invalidCountResetTime = null;
|
|
436
|
+
var SequentialHandler = class {
|
|
437
|
+
constructor(manager, hash, majorParameter) {
|
|
438
|
+
this.manager = manager;
|
|
439
|
+
this.hash = hash;
|
|
440
|
+
this.majorParameter = majorParameter;
|
|
441
|
+
this.id = `${hash}:${majorParameter}`;
|
|
442
|
+
}
|
|
443
|
+
id;
|
|
444
|
+
reset = -1;
|
|
445
|
+
remaining = 1;
|
|
446
|
+
limit = Number.POSITIVE_INFINITY;
|
|
447
|
+
#asyncQueue = new AsyncQueue();
|
|
448
|
+
#sublimitedQueue = null;
|
|
449
|
+
#sublimitPromise = null;
|
|
450
|
+
#shiftSublimit = false;
|
|
451
|
+
get inactive() {
|
|
452
|
+
return this.#asyncQueue.remaining === 0 && (this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) && !this.limited;
|
|
453
|
+
}
|
|
454
|
+
get globalLimited() {
|
|
455
|
+
return this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset;
|
|
456
|
+
}
|
|
457
|
+
get localLimited() {
|
|
458
|
+
return this.remaining <= 0 && Date.now() < this.reset;
|
|
459
|
+
}
|
|
460
|
+
get limited() {
|
|
461
|
+
return this.globalLimited || this.localLimited;
|
|
462
|
+
}
|
|
463
|
+
get timeToReset() {
|
|
464
|
+
return this.reset + this.manager.options.offset - Date.now();
|
|
465
|
+
}
|
|
466
|
+
debug(message) {
|
|
467
|
+
this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`);
|
|
468
|
+
}
|
|
469
|
+
async globalDelayFor(time) {
|
|
470
|
+
await sleep(time, void 0, { ref: false });
|
|
471
|
+
this.manager.globalDelay = null;
|
|
472
|
+
}
|
|
473
|
+
async onRateLimit(rateLimitData) {
|
|
474
|
+
const { options } = this.manager;
|
|
475
|
+
if (!options.rejectOnRateLimit)
|
|
476
|
+
return;
|
|
477
|
+
const shouldThrow = typeof options.rejectOnRateLimit === "function" ? await options.rejectOnRateLimit(rateLimitData) : options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase()));
|
|
478
|
+
if (shouldThrow) {
|
|
479
|
+
throw new RateLimitError(rateLimitData);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
async queueRequest(routeId, url, options, requestData) {
|
|
483
|
+
let queue = this.#asyncQueue;
|
|
484
|
+
let queueType = 0 /* Standard */;
|
|
485
|
+
if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {
|
|
486
|
+
queue = this.#sublimitedQueue;
|
|
487
|
+
queueType = 1 /* Sublimit */;
|
|
488
|
+
}
|
|
489
|
+
await queue.wait();
|
|
490
|
+
if (queueType === 0 /* Standard */) {
|
|
491
|
+
if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {
|
|
492
|
+
queue = this.#sublimitedQueue;
|
|
493
|
+
const wait = queue.wait();
|
|
494
|
+
this.#asyncQueue.shift();
|
|
495
|
+
await wait;
|
|
496
|
+
} else if (this.#sublimitPromise) {
|
|
497
|
+
await this.#sublimitPromise.promise;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
return await this.runRequest(routeId, url, options, requestData);
|
|
502
|
+
} finally {
|
|
503
|
+
queue.shift();
|
|
504
|
+
if (this.#shiftSublimit) {
|
|
505
|
+
this.#shiftSublimit = false;
|
|
506
|
+
this.#sublimitedQueue?.shift();
|
|
507
|
+
}
|
|
508
|
+
if (this.#sublimitedQueue?.remaining === 0) {
|
|
509
|
+
this.#sublimitPromise?.resolve();
|
|
510
|
+
this.#sublimitedQueue = null;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
async runRequest(routeId, url, options, requestData, retries = 0) {
|
|
515
|
+
while (this.limited) {
|
|
516
|
+
const isGlobal = this.globalLimited;
|
|
517
|
+
let limit2;
|
|
518
|
+
let timeout2;
|
|
519
|
+
let delay;
|
|
520
|
+
if (isGlobal) {
|
|
521
|
+
limit2 = this.manager.options.globalRequestsPerSecond;
|
|
522
|
+
timeout2 = this.manager.globalReset + this.manager.options.offset - Date.now();
|
|
523
|
+
if (!this.manager.globalDelay) {
|
|
524
|
+
this.manager.globalDelay = this.globalDelayFor(timeout2);
|
|
525
|
+
}
|
|
526
|
+
delay = this.manager.globalDelay;
|
|
527
|
+
} else {
|
|
528
|
+
limit2 = this.limit;
|
|
529
|
+
timeout2 = this.timeToReset;
|
|
530
|
+
delay = sleep(timeout2);
|
|
531
|
+
}
|
|
532
|
+
const rateLimitData = {
|
|
533
|
+
timeToReset: timeout2,
|
|
534
|
+
limit: limit2,
|
|
535
|
+
method: options.method ?? "get",
|
|
536
|
+
hash: this.hash,
|
|
537
|
+
url,
|
|
538
|
+
route: routeId.bucketRoute,
|
|
539
|
+
majorParameter: this.majorParameter,
|
|
540
|
+
global: isGlobal
|
|
541
|
+
};
|
|
542
|
+
this.manager.emit("rateLimited" /* RateLimited */, rateLimitData);
|
|
543
|
+
await this.onRateLimit(rateLimitData);
|
|
544
|
+
if (isGlobal) {
|
|
545
|
+
this.debug(`Global rate limit hit, blocking all requests for ${timeout2}ms`);
|
|
546
|
+
} else {
|
|
547
|
+
this.debug(`Waiting ${timeout2}ms for rate limit to pass`);
|
|
548
|
+
}
|
|
549
|
+
await delay;
|
|
550
|
+
}
|
|
551
|
+
if (!this.manager.globalReset || this.manager.globalReset < Date.now()) {
|
|
552
|
+
this.manager.globalReset = Date.now() + 1e3;
|
|
553
|
+
this.manager.globalRemaining = this.manager.options.globalRequestsPerSecond;
|
|
554
|
+
}
|
|
555
|
+
this.manager.globalRemaining--;
|
|
556
|
+
const method = options.method ?? "get";
|
|
557
|
+
const controller = new AbortController();
|
|
558
|
+
const timeout = setTimeout(() => controller.abort(), this.manager.options.timeout).unref();
|
|
559
|
+
let res;
|
|
560
|
+
try {
|
|
561
|
+
res = await request(url, { ...options, signal: controller.signal });
|
|
562
|
+
} catch (error) {
|
|
563
|
+
if (error instanceof Error && error.name === "AbortError" && retries !== this.manager.options.retries) {
|
|
564
|
+
return await this.runRequest(routeId, url, options, requestData, ++retries);
|
|
565
|
+
}
|
|
566
|
+
throw error;
|
|
567
|
+
} finally {
|
|
568
|
+
clearTimeout(timeout);
|
|
569
|
+
}
|
|
570
|
+
if (this.manager.listenerCount("response" /* Response */)) {
|
|
571
|
+
this.manager.emit(
|
|
572
|
+
"response" /* Response */,
|
|
573
|
+
{
|
|
574
|
+
method,
|
|
575
|
+
path: routeId.original,
|
|
576
|
+
route: routeId.bucketRoute,
|
|
577
|
+
options,
|
|
578
|
+
data: requestData,
|
|
579
|
+
retries
|
|
580
|
+
},
|
|
581
|
+
{ ...res }
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
const status = res.statusCode;
|
|
585
|
+
let retryAfter = 0;
|
|
586
|
+
const limit = parseHeader(res.headers["x-ratelimit-limit"]);
|
|
587
|
+
const remaining = parseHeader(res.headers["x-ratelimit-remaining"]);
|
|
588
|
+
const reset = parseHeader(res.headers["x-ratelimit-reset-after"]);
|
|
589
|
+
const hash = parseHeader(res.headers["x-ratelimit-bucket"]);
|
|
590
|
+
const retry = parseHeader(res.headers["retry-after"]);
|
|
591
|
+
this.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY;
|
|
592
|
+
this.remaining = remaining ? Number(remaining) : 1;
|
|
593
|
+
this.reset = reset ? Number(reset) * 1e3 + Date.now() + this.manager.options.offset : Date.now();
|
|
594
|
+
if (retry)
|
|
595
|
+
retryAfter = Number(retry) * 1e3 + this.manager.options.offset;
|
|
596
|
+
if (hash && hash !== this.hash) {
|
|
597
|
+
this.debug(["Received bucket hash update", ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join("\n"));
|
|
598
|
+
this.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() });
|
|
599
|
+
} else if (hash) {
|
|
600
|
+
const hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`);
|
|
601
|
+
if (hashData) {
|
|
602
|
+
hashData.lastAccess = Date.now();
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
let sublimitTimeout = null;
|
|
606
|
+
if (retryAfter > 0) {
|
|
607
|
+
if (res.headers["x-ratelimit-global"] !== void 0) {
|
|
608
|
+
this.manager.globalRemaining = 0;
|
|
609
|
+
this.manager.globalReset = Date.now() + retryAfter;
|
|
610
|
+
} else if (!this.localLimited) {
|
|
611
|
+
sublimitTimeout = retryAfter;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (status === 401 || status === 403 || status === 429) {
|
|
615
|
+
if (!invalidCountResetTime || invalidCountResetTime < Date.now()) {
|
|
616
|
+
invalidCountResetTime = Date.now() + 1e3 * 60 * 10;
|
|
617
|
+
invalidCount = 0;
|
|
618
|
+
}
|
|
619
|
+
invalidCount++;
|
|
620
|
+
const emitInvalid = this.manager.options.invalidRequestWarningInterval > 0 && invalidCount % this.manager.options.invalidRequestWarningInterval === 0;
|
|
621
|
+
if (emitInvalid) {
|
|
622
|
+
this.manager.emit("invalidRequestWarning" /* InvalidRequestWarning */, {
|
|
623
|
+
count: invalidCount,
|
|
624
|
+
remainingTime: invalidCountResetTime - Date.now()
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (status >= 200 && status < 300) {
|
|
629
|
+
return res;
|
|
630
|
+
} else if (status === 429) {
|
|
631
|
+
const isGlobal = this.globalLimited;
|
|
632
|
+
let limit2;
|
|
633
|
+
let timeout2;
|
|
634
|
+
if (isGlobal) {
|
|
635
|
+
limit2 = this.manager.options.globalRequestsPerSecond;
|
|
636
|
+
timeout2 = this.manager.globalReset + this.manager.options.offset - Date.now();
|
|
637
|
+
} else {
|
|
638
|
+
limit2 = this.limit;
|
|
639
|
+
timeout2 = this.timeToReset;
|
|
640
|
+
}
|
|
641
|
+
await this.onRateLimit({
|
|
642
|
+
timeToReset: timeout2,
|
|
643
|
+
limit: limit2,
|
|
644
|
+
method,
|
|
645
|
+
hash: this.hash,
|
|
646
|
+
url,
|
|
647
|
+
route: routeId.bucketRoute,
|
|
648
|
+
majorParameter: this.majorParameter,
|
|
649
|
+
global: isGlobal
|
|
650
|
+
});
|
|
651
|
+
this.debug(
|
|
652
|
+
[
|
|
653
|
+
"Encountered unexpected 429 rate limit",
|
|
654
|
+
` Global : ${isGlobal.toString()}`,
|
|
655
|
+
` Method : ${method}`,
|
|
656
|
+
` URL : ${url}`,
|
|
657
|
+
` Bucket : ${routeId.bucketRoute}`,
|
|
658
|
+
` Major parameter: ${routeId.majorParameter}`,
|
|
659
|
+
` Hash : ${this.hash}`,
|
|
660
|
+
` Limit : ${limit2}`,
|
|
661
|
+
` Retry After : ${retryAfter}ms`,
|
|
662
|
+
` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : "None"}`
|
|
663
|
+
].join("\n")
|
|
664
|
+
);
|
|
665
|
+
if (sublimitTimeout) {
|
|
666
|
+
const firstSublimit = !this.#sublimitedQueue;
|
|
667
|
+
if (firstSublimit) {
|
|
668
|
+
this.#sublimitedQueue = new AsyncQueue();
|
|
669
|
+
void this.#sublimitedQueue.wait();
|
|
670
|
+
this.#asyncQueue.shift();
|
|
671
|
+
}
|
|
672
|
+
this.#sublimitPromise?.resolve();
|
|
673
|
+
this.#sublimitPromise = null;
|
|
674
|
+
await sleep(sublimitTimeout, void 0, { ref: false });
|
|
675
|
+
let resolve;
|
|
676
|
+
const promise = new Promise((res2) => resolve = res2);
|
|
677
|
+
this.#sublimitPromise = { promise, resolve };
|
|
678
|
+
if (firstSublimit) {
|
|
679
|
+
await this.#asyncQueue.wait();
|
|
680
|
+
this.#shiftSublimit = true;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return this.runRequest(routeId, url, options, requestData, retries);
|
|
684
|
+
} else if (status >= 500 && status < 600) {
|
|
685
|
+
if (retries !== this.manager.options.retries) {
|
|
686
|
+
return this.runRequest(routeId, url, options, requestData, ++retries);
|
|
687
|
+
}
|
|
688
|
+
throw new HTTPError(res.constructor.name, status, method, url, requestData);
|
|
689
|
+
} else {
|
|
690
|
+
if (status >= 400 && status < 500) {
|
|
691
|
+
if (status === 401 && requestData.auth) {
|
|
692
|
+
this.manager.setToken(null);
|
|
693
|
+
}
|
|
694
|
+
const data = await parseResponse(res);
|
|
695
|
+
throw new DiscordAPIError(data, "code" in data ? data.code : data.error, status, method, url, requestData);
|
|
696
|
+
}
|
|
697
|
+
return res;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
__name(SequentialHandler, "SequentialHandler");
|
|
702
|
+
|
|
703
|
+
// src/lib/RequestManager.ts
|
|
704
|
+
var getFileType = /* @__PURE__ */ __name(async () => {
|
|
705
|
+
let cached;
|
|
706
|
+
return cached ??= import("file-type");
|
|
707
|
+
}, "getFileType");
|
|
708
|
+
var RequestMethod = /* @__PURE__ */ ((RequestMethod2) => {
|
|
709
|
+
RequestMethod2["Delete"] = "DELETE";
|
|
710
|
+
RequestMethod2["Get"] = "GET";
|
|
711
|
+
RequestMethod2["Patch"] = "PATCH";
|
|
712
|
+
RequestMethod2["Post"] = "POST";
|
|
713
|
+
RequestMethod2["Put"] = "PUT";
|
|
714
|
+
return RequestMethod2;
|
|
715
|
+
})(RequestMethod || {});
|
|
716
|
+
var RequestManager = class extends EventEmitter {
|
|
717
|
+
agent = null;
|
|
718
|
+
globalRemaining;
|
|
719
|
+
globalDelay = null;
|
|
720
|
+
globalReset = -1;
|
|
721
|
+
hashes = new Collection();
|
|
722
|
+
handlers = new Collection();
|
|
723
|
+
#token = null;
|
|
724
|
+
hashTimer;
|
|
725
|
+
handlerTimer;
|
|
726
|
+
options;
|
|
727
|
+
constructor(options) {
|
|
728
|
+
super();
|
|
729
|
+
this.options = { ...DefaultRestOptions, ...options };
|
|
730
|
+
this.options.offset = Math.max(0, this.options.offset);
|
|
731
|
+
this.globalRemaining = this.options.globalRequestsPerSecond;
|
|
732
|
+
this.agent = options.agent ?? null;
|
|
733
|
+
this.setupSweepers();
|
|
734
|
+
}
|
|
735
|
+
setupSweepers() {
|
|
736
|
+
const validateMaxInterval = /* @__PURE__ */ __name((interval) => {
|
|
737
|
+
if (interval > 144e5) {
|
|
738
|
+
throw new Error("Cannot set an interval greater than 4 hours");
|
|
739
|
+
}
|
|
740
|
+
}, "validateMaxInterval");
|
|
741
|
+
if (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) {
|
|
742
|
+
validateMaxInterval(this.options.hashSweepInterval);
|
|
743
|
+
this.hashTimer = setInterval(() => {
|
|
744
|
+
const sweptHashes = new Collection();
|
|
745
|
+
const currentDate = Date.now();
|
|
746
|
+
this.hashes.sweep((val, key) => {
|
|
747
|
+
if (val.lastAccess === -1)
|
|
748
|
+
return false;
|
|
749
|
+
const shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime;
|
|
750
|
+
if (shouldSweep) {
|
|
751
|
+
sweptHashes.set(key, val);
|
|
752
|
+
}
|
|
753
|
+
this.emit("restDebug" /* Debug */, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`);
|
|
754
|
+
return shouldSweep;
|
|
755
|
+
});
|
|
756
|
+
this.emit("hashSweep" /* HashSweep */, sweptHashes);
|
|
757
|
+
}, this.options.hashSweepInterval).unref();
|
|
758
|
+
}
|
|
759
|
+
if (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) {
|
|
760
|
+
validateMaxInterval(this.options.handlerSweepInterval);
|
|
761
|
+
this.handlerTimer = setInterval(() => {
|
|
762
|
+
const sweptHandlers = new Collection();
|
|
763
|
+
this.handlers.sweep((val, key) => {
|
|
764
|
+
const { inactive } = val;
|
|
765
|
+
if (inactive) {
|
|
766
|
+
sweptHandlers.set(key, val);
|
|
767
|
+
}
|
|
768
|
+
this.emit("restDebug" /* Debug */, `Handler ${val.id} for ${key} swept due to being inactive`);
|
|
769
|
+
return inactive;
|
|
770
|
+
});
|
|
771
|
+
this.emit("handlerSweep" /* HandlerSweep */, sweptHandlers);
|
|
772
|
+
}, this.options.handlerSweepInterval).unref();
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
setAgent(agent) {
|
|
776
|
+
this.agent = agent;
|
|
777
|
+
return this;
|
|
778
|
+
}
|
|
779
|
+
setToken(token) {
|
|
780
|
+
this.#token = token;
|
|
781
|
+
return this;
|
|
782
|
+
}
|
|
783
|
+
async queueRequest(request2) {
|
|
784
|
+
const routeId = RequestManager.generateRouteData(request2.fullRoute, request2.method);
|
|
785
|
+
const hash = this.hashes.get(`${request2.method}:${routeId.bucketRoute}`) ?? {
|
|
786
|
+
value: `Global(${request2.method}:${routeId.bucketRoute})`,
|
|
787
|
+
lastAccess: -1
|
|
788
|
+
};
|
|
789
|
+
const handler = this.handlers.get(`${hash.value}:${routeId.majorParameter}`) ?? this.createHandler(hash.value, routeId.majorParameter);
|
|
790
|
+
const { url, fetchOptions } = await this.resolveRequest(request2);
|
|
791
|
+
return handler.queueRequest(routeId, url, fetchOptions, {
|
|
792
|
+
body: request2.body,
|
|
793
|
+
files: request2.files,
|
|
794
|
+
auth: request2.auth !== false
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
createHandler(hash, majorParameter) {
|
|
798
|
+
const queue = new SequentialHandler(this, hash, majorParameter);
|
|
799
|
+
this.handlers.set(queue.id, queue);
|
|
800
|
+
return queue;
|
|
801
|
+
}
|
|
802
|
+
async resolveRequest(request2) {
|
|
803
|
+
const { options } = this;
|
|
804
|
+
let query = "";
|
|
805
|
+
if (request2.query) {
|
|
806
|
+
const resolvedQuery = request2.query.toString();
|
|
807
|
+
if (resolvedQuery !== "") {
|
|
808
|
+
query = `?${resolvedQuery}`;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
const headers = {
|
|
812
|
+
...this.options.headers,
|
|
813
|
+
"User-Agent": `${DefaultUserAgent} ${options.userAgentAppendix}`.trim()
|
|
814
|
+
};
|
|
815
|
+
if (request2.auth !== false) {
|
|
816
|
+
if (!this.#token) {
|
|
817
|
+
throw new Error("Expected token to be set for this request, but none was present");
|
|
818
|
+
}
|
|
819
|
+
headers.Authorization = `${request2.authPrefix ?? this.options.authPrefix} ${this.#token}`;
|
|
820
|
+
}
|
|
821
|
+
if (request2.reason?.length) {
|
|
822
|
+
headers["X-Audit-Log-Reason"] = encodeURIComponent(request2.reason);
|
|
823
|
+
}
|
|
824
|
+
const url = `${options.api}${request2.versioned === false ? "" : `/v${options.version}`}${request2.fullRoute}${query}`;
|
|
825
|
+
let finalBody;
|
|
826
|
+
let additionalHeaders = {};
|
|
827
|
+
if (request2.files?.length) {
|
|
828
|
+
const formData = new FormData2();
|
|
829
|
+
for (const [index, file] of request2.files.entries()) {
|
|
830
|
+
const fileKey = file.key ?? `files[${index}]`;
|
|
831
|
+
if (Buffer3.isBuffer(file.data)) {
|
|
832
|
+
const { fileTypeFromBuffer } = await getFileType();
|
|
833
|
+
const contentType = file.contentType ?? (await fileTypeFromBuffer(file.data))?.mime;
|
|
834
|
+
formData.append(fileKey, new Blob2([file.data], { type: contentType }), file.name);
|
|
835
|
+
} else {
|
|
836
|
+
formData.append(fileKey, new Blob2([`${file.data}`], { type: file.contentType }), file.name);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
if (request2.body != null) {
|
|
840
|
+
if (request2.appendToFormData) {
|
|
841
|
+
for (const [key, value] of Object.entries(request2.body)) {
|
|
842
|
+
formData.append(key, value);
|
|
843
|
+
}
|
|
844
|
+
} else {
|
|
845
|
+
formData.append("payload_json", JSON.stringify(request2.body));
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
finalBody = formData;
|
|
849
|
+
} else if (request2.body != null) {
|
|
850
|
+
if (request2.passThroughBody) {
|
|
851
|
+
finalBody = request2.body;
|
|
852
|
+
} else {
|
|
853
|
+
finalBody = JSON.stringify(request2.body);
|
|
854
|
+
additionalHeaders = { "Content-Type": "application/json" };
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
finalBody = await resolveBody(finalBody);
|
|
858
|
+
const fetchOptions = {
|
|
859
|
+
headers: { ...request2.headers, ...additionalHeaders, ...headers },
|
|
860
|
+
method: request2.method.toUpperCase()
|
|
861
|
+
};
|
|
862
|
+
if (finalBody !== void 0) {
|
|
863
|
+
fetchOptions.body = finalBody;
|
|
864
|
+
}
|
|
865
|
+
fetchOptions.dispatcher = request2.dispatcher ?? this.agent ?? void 0;
|
|
866
|
+
return { url, fetchOptions };
|
|
867
|
+
}
|
|
868
|
+
clearHashSweeper() {
|
|
869
|
+
clearInterval(this.hashTimer);
|
|
870
|
+
}
|
|
871
|
+
clearHandlerSweeper() {
|
|
872
|
+
clearInterval(this.handlerTimer);
|
|
873
|
+
}
|
|
874
|
+
static generateRouteData(endpoint, method) {
|
|
875
|
+
const majorIdMatch = /^\/(?:channels|guilds|webhooks)\/(\d{16,19})/.exec(endpoint);
|
|
876
|
+
const majorId = majorIdMatch?.[1] ?? "global";
|
|
877
|
+
const baseRoute = endpoint.replace(/\d{16,19}/g, ":id").replace(/\/reactions\/(.*)/, "/reactions/:reaction");
|
|
878
|
+
let exceptions = "";
|
|
879
|
+
if (method === "DELETE" /* Delete */ && baseRoute === "/channels/:id/messages/:id") {
|
|
880
|
+
const id = /\d{16,19}$/.exec(endpoint)[0];
|
|
881
|
+
const timestamp = DiscordSnowflake.timestampFrom(id);
|
|
882
|
+
if (Date.now() - timestamp > 1e3 * 60 * 60 * 24 * 14) {
|
|
883
|
+
exceptions += "/Delete Old Message";
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
return {
|
|
887
|
+
majorParameter: majorId,
|
|
888
|
+
bucketRoute: baseRoute + exceptions,
|
|
889
|
+
original: endpoint
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
__name(RequestManager, "RequestManager");
|
|
894
|
+
|
|
895
|
+
// src/lib/REST.ts
|
|
896
|
+
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
897
|
+
var REST = class extends EventEmitter2 {
|
|
898
|
+
cdn;
|
|
899
|
+
requestManager;
|
|
900
|
+
constructor(options = {}) {
|
|
901
|
+
super();
|
|
902
|
+
this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn);
|
|
903
|
+
this.requestManager = new RequestManager(options).on("restDebug" /* Debug */, this.emit.bind(this, "restDebug" /* Debug */)).on("rateLimited" /* RateLimited */, this.emit.bind(this, "rateLimited" /* RateLimited */)).on("invalidRequestWarning" /* InvalidRequestWarning */, this.emit.bind(this, "invalidRequestWarning" /* InvalidRequestWarning */)).on("hashSweep" /* HashSweep */, this.emit.bind(this, "hashSweep" /* HashSweep */));
|
|
904
|
+
this.on("newListener", (name, listener) => {
|
|
905
|
+
if (name === "response" /* Response */)
|
|
906
|
+
this.requestManager.on(name, listener);
|
|
907
|
+
});
|
|
908
|
+
this.on("removeListener", (name, listener) => {
|
|
909
|
+
if (name === "response" /* Response */)
|
|
910
|
+
this.requestManager.off(name, listener);
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
getAgent() {
|
|
914
|
+
return this.requestManager.agent;
|
|
915
|
+
}
|
|
916
|
+
setAgent(agent) {
|
|
917
|
+
this.requestManager.setAgent(agent);
|
|
918
|
+
return this;
|
|
919
|
+
}
|
|
920
|
+
setToken(token) {
|
|
921
|
+
this.requestManager.setToken(token);
|
|
922
|
+
return this;
|
|
923
|
+
}
|
|
924
|
+
async get(fullRoute, options = {}) {
|
|
925
|
+
return this.request({ ...options, fullRoute, method: "GET" /* Get */ });
|
|
926
|
+
}
|
|
927
|
+
async delete(fullRoute, options = {}) {
|
|
928
|
+
return this.request({ ...options, fullRoute, method: "DELETE" /* Delete */ });
|
|
929
|
+
}
|
|
930
|
+
async post(fullRoute, options = {}) {
|
|
931
|
+
return this.request({ ...options, fullRoute, method: "POST" /* Post */ });
|
|
932
|
+
}
|
|
933
|
+
async put(fullRoute, options = {}) {
|
|
934
|
+
return this.request({ ...options, fullRoute, method: "PUT" /* Put */ });
|
|
935
|
+
}
|
|
936
|
+
async patch(fullRoute, options = {}) {
|
|
937
|
+
return this.request({ ...options, fullRoute, method: "PATCH" /* Patch */ });
|
|
938
|
+
}
|
|
939
|
+
async request(options) {
|
|
940
|
+
const response = await this.raw(options);
|
|
941
|
+
return parseResponse(response);
|
|
942
|
+
}
|
|
943
|
+
async raw(options) {
|
|
944
|
+
return this.requestManager.queueRequest(options);
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
__name(REST, "REST");
|
|
948
|
+
export {
|
|
949
|
+
ALLOWED_EXTENSIONS,
|
|
950
|
+
ALLOWED_SIZES,
|
|
951
|
+
ALLOWED_STICKER_EXTENSIONS,
|
|
952
|
+
CDN,
|
|
953
|
+
DefaultRestOptions,
|
|
954
|
+
DefaultUserAgent,
|
|
955
|
+
DiscordAPIError,
|
|
956
|
+
HTTPError,
|
|
957
|
+
REST,
|
|
958
|
+
RESTEvents,
|
|
959
|
+
RateLimitError,
|
|
960
|
+
RequestManager,
|
|
961
|
+
RequestMethod,
|
|
962
|
+
makeURLSearchParams,
|
|
963
|
+
parseResponse
|
|
964
|
+
};
|
|
965
|
+
//# sourceMappingURL=index.mjs.map
|