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